1.webgl中如何通过一个缓冲区,实现传递多种顶点数据.
这个要求是什么呢?一般我们创建一个缓冲区,都是对顶点坐标进行操作。如果我们要对每个顶点的尺寸也是一个缓冲区进行的赋值操作,那么我们一般又要创建一个缓冲区。如果我们又要对什么进行赋值的话,我们又又要创建一个新的缓冲区。
而我要讲的是入通过一个缓冲区,将顶点的不同信息一起传入赋值。
如何完成上面的需求呢?
- 首先你要会使用webgl的缓冲
- 我们只需要改变 vertexAttribPointer这个API的某几个参数就可以了。
如果你不知道 如何使用 webgl的缓冲区将一批数据同时传入webgl的着色器中。请看我的以往的博客。这里不再解释。
webgl(3) -如何使用webgl的缓冲区,使其一次性的写入多条数据,渲染多条数据。
好看代码
1.顶点着色器
const VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute float a_PointSize;\n' +
'void main() { \n' +
' gl_Position = a_Position;\n' +
' gl_PointSize = a_PointSize;\n' +
'}\n';
这个顶点着色器中,我们有两个变量是attribute的,分别是 a_Position, a_PointSize;
表示顶点的位置,顶点的尺寸。是我们可以通过js进行修改的
2.片源着色器
const FSHADER_SOURCE =
'void main() { \n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';
这里的片源着色器,没有什么特别的。
3.看看在创建缓冲区的代码
const vertices = new Float32Array([0.0, 0.5, 0.5, 0.5, 0.0, 2.0, -0.5, 0.0, 3.0])
1.这里的vertices是我们传入缓冲区的全部数据。
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); // 是将缓冲区vertexBuffer 绑定到 gl.ARRAY_BUFFER
gl.bufferData(gl.ARRAY_BUFFER, vertices) // 是向缓冲区中写入数据 --> vertices
好了,我们上面完成了什么事情呢?
1.初始化了数据
2.创建一个缓冲区
3.将缓冲区绑定到了gl.ARRAY_BUFFER
4.然后向缓冲区中写入数据.
接下来我们需要将缓冲区中的数据分配给a_Position, a_PointSize变量
const a_Position = gl.getAttribLocation(gl.program, 'a_Position'); // 获取a_Postion的存储地址.
const FSIZE = vertices.BYTES_PER_ELEMENT; // 返回元素字节数
gl.vertexAttribPointer(a_Postion, 2, FLOAT, false, FSIZE * 3, 0);
gl.enableVertexAttribArray(a_Postion); // 开启
const a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
gl.vertexAttribPointer(a_PointSize, 1, FLOAT, false, FSIZE * 3, FSIZE * 2);
gl.enableVertexAttribArray(a_PointSize); // 开启
gl.vertexAttribPointer(index, size, type, normalized, stride, offset)的api
index ----> a_Position attribute变量的存储地址。
size ---- 指定每个顶点属性的组成数量。我们这里 a_Position 是为 2。a_PointSize 是为 1
因为 a_Position是坐标只需要两个值来表示就够了(x, y)。
因为 a_PointSize是表示每个顶点的尺寸只需要一个值就可以了。
type ----> 表示数据的类型 FLOAT 浮点型
normalized -----> ........
stride -----> 以字节为单位指定连续顶点属性开始之间的偏移量(即数组中一行长度)。不能大于255。如果stride为0,则假定该属性是紧密打包的,即不交错属性,每个属性在一个单独的块中,下一个顶点的属性紧跟当前顶点之后
我简单理解为,每组顶点数据的长度,因为我们这里是 (x, y, size) 所以值为 FSIZE * 3
offset ---> 指定顶点属性数组中第一部分的字节偏移量。必须是类型的字节长度的倍数.简单理解为开始的位置。
因为 a_Position是在(x, y, size)中的前面两个值,所以是 0
因为 a_PointSize 是在(x, y, size)中的最后那一个,所以偏移是 FSIZE * 2;
实例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#canvas {
height: 400px;
width: 400px;
background-color: red;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const gl = canvas.getContext('webgl')
const initShader = (type, source) => {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader); // 开始编译着色器
const compilShader = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compilShader) {
const err = gl.getShaderInfoLog(shader); // 获取编译报错信息
alert(err)
console.log(`编译报错信息为${err}`);
gl.deleteShader(shader);
return null
}
return shader
}
// const VSHADER_SOURCE =
// 'attribute vec4 a_Position;\n'+
// 'void main() {\n'+
// ' gl_Position = a_Position;\n'+
// ' gl_PointSize = 5.0;\n'+
// '}\n';
const VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute float a_PointSize;\n' +
'void main() { \n' +
' gl_Position = a_Position;\n' +
' gl_PointSize = a_PointSize;\n' +
'}\n';
const FSHADER_SOURCE =
'void main() { \n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';
const shader = initShader(gl.VERTEX_SHADER, VSHADER_SOURCE);
// console.log(shader, 'shader')
const createProgram = (vshader, fshader) => {
const vertexShader = initShader(gl.VERTEX_SHADER, vshader);
const fragmentShader = initShader(gl.FRAGMENT_SHADER, fshader);
// console.log(vertexShader, 'vertexShader')
// console.log(fragmentShader, 'fragmentShader')
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
const linkState = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linkState) {
const err = gl.getProgramInfoLog(program);
console.log('链接报错的信息为:'+err);
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
gl.deleteProgram(program);
return null
}
// return program;
gl.useProgram(program);
gl.program = program;
}
const initVetexBuffers = () => {
const vertices = new Float32Array([0.5, 0.0, 2.0, 0.0, 0.5, 2.0, -0.5,0,3.0]);
const FSIZE = vertices.BYTES_PER_ELEMENT;
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
// gl.vertexAttribPointer(a_Position, 2)
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 3, 0);
gl.enableVertexAttribArray(a_Position);
const a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, FSIZE * 3, FSIZE * 2);
gl.enableVertexAttribArray(a_PointSize);
}
createProgram(VSHADER_SOURCE, FSHADER_SOURCE)
initVetexBuffers();
gl.clearColor(0.0,0.0,1.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 3)
</script>
</body>
</html>
效果如下