theme: smartblue
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
创建缓冲区
之前都是对一个顶点进行绘制,一般的图形,三角形,立方体或建模同学导出的模型数据都是由多个顶点构成的,如果想要一次绘制多个点需要怎么传递数据呢。我们可以通过缓冲区对象(BufferObject)一次性向着色器传入多个顶点数据。code
// 绘制方式; 开始顶点; 总顶点数;
gl.drawArrays(gl.TRIANGLES, 0, 3)
function initVertexBuffers() {
const vertices = new Float32Array([
-0.5, 0.5,
0.5, 0.5,
0, -0.5,
])
// 创建缓冲区对象
const vertexBuffer = gl.createBuffer()
// 将缓冲区对象绑定到目标
// gl.ARRAY_BUFFER 缓冲区对象中包含顶点数据
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
// 向缓冲区对象写数据
// 第二个参数的数据写入绑定了第一个参数的缓冲区对象
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
const a_Position = gl.getAttribLocation(gl.program, 'a_Position')
// 将缓冲区对象分配给变量
// 参数分别为, 位置;大小(每一个顶点的分量数,两个就是x和y);类型
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)
// 连接变量和缓冲区对象
gl.enableVertexAttribArray(a_Position)
}
使用缓冲区对象向顶点着色器传递数据不需要调整着色器代码,也是通过attribute变量接收数据。
在绘制的时候需要在drawArrays时传递一下顶点的数量,这样着色器才能知道需要绘制多少个顶点,从缓冲区拿多少数据。
然后我们看看创建缓冲区的方法,首先需要定义数据,这里使用的是Float32Array,是因为WebGL只能从缓冲区读取二进制数据,使用类型化数组可以操作二进制缓冲区的数据。数据有了后可以开始连接着色器了:
1、创建缓冲区对象:
可以通过createBuffer创建一个WebGL的缓冲区对象。
2、绑定缓冲区对象
使用bindBuffer把创建的缓冲区对象绑定给gl.ARRAY_BUFFER,gl.ARRAY_BUFFER表示缓冲区中包含的是顶点数据,也可以绑定gl.ELEMENT_ARRAY_BUFFER表示数据是顶点索引。说句题外话:在js中ArrayBuffer 不是某种东西的数组,而是一段二进制数据缓冲区,需要使用类型化数组操作,具体可看看这。
3、将数据写入缓冲区对象
缓冲区处理好了后就可以向缓冲区写入数据了,通过bufferData,向绑定了ARRAY_BUFFER的缓冲区写入数据,gl.STATIC_DRAW表示只会想缓冲区写入一次数据。
4、将缓冲区对象分配给attribute变量
先获得attribute变量的位置,然后通过vertexAttribPointer把整个缓冲区分配给变量。参数分别为,位置、每一个顶点数据大小,数据类型, 是否进行归一化处理,后面两个参数后续再说明。
5、开启attribute变量
使用enableVertexAttribArray开启。
不同的绘制方式
对于drawArrays的第一个参数可以传递以下七种绘制方式:
传递多组数据
上述例子只说了传递多个顶点信息,如果需要同时传递多个顶点大小或者顶点颜色信息,可以多建立几个缓冲区每个缓冲区传递给一个attribute变量,其实还有更加方便的方法,就是使用vetrexAttribPointer方法的后两个参数:
function initVertexBuffers() {
const vertices = new Float32Array([
-0.5, 0.5, 1.0, 1.0, 0.0,
0.5, 0.5, 1.0, 0.0, 1.0,
0, -0.5, 0.0, 1.0, 1.0,
])
// 每个元素占字节数
const FSIZE = vertices.BYTES_PER_ELEMENT
const 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.FLOAT, false, FSIZE * 5, 0)
gl.enableVertexAttribArray(a_Position)
const a_Color = gl.getAttribLocation(gl.program, 'a_Color')
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2)
gl.enableVertexAttribArray(a_Color)
}
和之前的代码区别是:
- 传入的数据变多了,每一行除了传两个坐标信息,还带有三个颜色信息。
- 增加了一个a_Color的attribute变量来接受颜色数据。
- vertexAttribPointer调整了两个参数的传入,分别是每两次顶点之间间隔的字节数,当前变量取值的偏移字节数,因为是传字节数所以需要通过BYTES_PER_ELEMENT获取数组每一项占用字节大小。新数据是每间隔5个数据为一个顶点,位置从第0个开始取值,颜色从第2个开始取值。
其实上面传递的是颜色变量,但是到得到的三角形是没颜色的,attribute变量是不能传递到片元着色器的,那能不能通过uniform变量向片元着色器传值呢,uniform变量传的是所有顶点都一样的数据,下一章来讲讲怎么向片元着色器传递多种颜色。
暂无评论内容