WebGL 手把手入门指南(二)绘制三角形


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变量传的是所有顶点都一样的数据,下一章来讲讲怎么向片元着色器传递多种颜色。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容