本篇概念最为复杂,但是也是必须掌握的基础
理解Buffer的概念及用途在日后开发中至关重要
全篇目录
什么是Buffer
buffer是WebGL系统内部划分出的一块区域,可以存放一组顶点数据,比如顶点坐标,把顶点数据写入buffer后,着色器程序执行时就可以从buffer中读取数据,在数据量较大时尤为方便
着色器程序中虽然不能直接读buffer,但可以先通过API来指定着色器变量值为buffer的地址,再指定数据读取方式,例如从哪里开始读?读几个数?下一个顶点的数据在哪里?间接地从buffer中读取数据
数据类型
GLSL ES是强类型语言,js是弱类型的,js数组元素没有限制,而GLSL ES需要非常严格的数据,所以才有了类型化数组
支持的数组类型有
- Int8Array
- UInt8Array
- Int16Array
- UInt16Array
- Int32Array
- UInt32Array
- Float32Array
- Float64Array
区别是每个元素所占字节数不同(类型化数组有BYTES_PER_ELEMENT属性,可以获取数组内每个元素所占字节数,比如Float32Array每个元素占4个字节),与普通数组相比,类型化数组不支持push和pop方法,但针对“大量元素都是同一种类型”做了优化
1 | const arrVtx = new Float32Array([-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 0.0, 0.0]); |
使用Buffer
■ 创建buffer
1 | // 若创建失败,则返回null |
■ 把缓冲区对象绑定到目标
因为我们无法直接向缓冲区写入数据,只能向target写入,所以要向缓冲区写数据,必须要先绑定target与buffer。target表示缓冲区对象的用途,值为gl.ARRAY_BUFFER或者gl.ELEMENT_ARRAY_BUFFER,前者表示缓冲区对象包含了顶点数据,后者表示包含了顶点的索引值
1 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); |
■ 向缓冲区对象写入数据
通过gl.bufferData(target, data, usage)写入数据
1 | gl.bufferData(gl.ARRAY_BUFFER, arrVtx, gl.STATIC_DRAW); |
- data是类型化数组
- usage表示缓冲区数据用途,WebGL会根据用途进行优化
usage:
- gl.STATIC_DRAW(只向缓冲区对象写入一次数据,但需要绘制很多次)
- gl.STREAM_DRAW(只向缓冲区对象中写入一次数据,然后绘制若干次)
- gl.DYNAMIC_DRAW(向缓冲区对象多次写入数据,并绘制很多次)
区别不很明显,而且只可能会影响性能,不会影响最终结果
■ 将缓冲区对象分配给a_Position变量
buffer准备好了,现在要给着色器变量赋值,并告诉着色器这些数据待会儿怎么用
1 | gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); |
通过gl.vertexAttribPointer(location, size, type, normalized, stride, offset)
给attribute对象赋值缓冲区指针,参数含义如下:
参数名 | 描述 |
---|---|
size | 缓冲区中每个顶点的分量个数(1~4),表示每个顶点数据中要赋值给着色器变量的分量个数 |
type | 数据格式,值为gl.UNSIGNED_BYTE、gl.SHORT、gl.UNSIGNED_SHORT、gl.INT、gl.UNSIGNED_INT、gl.FLOAT五种 |
normalized | true |
stride | 指定相邻两个顶点间的字节数,默认为0 |
offset | 缓冲区对象中的偏移量,从缓冲区的offset位置开始写,从头开始就是0 |
stride参数比较特别,如果每个顶点有n个数据,把stride置为arr.BYTES_PER_ELEMENT * n的效果和0一样。
因为当前顶点数据读取结束后,如果stride为0,则从当前顶点数据结束的位置
开始读取下一个顶点的数据
如果stride非0,则从当前顶点数据开始的位置
跳过stride指定的字节再开始读取
■ 连接a_Position变量和分配给它的缓冲区对象
1 | gl.enableVertexAttribArray(a_Position); |
绘制多个点
1 | gl.drawArrays(gl.POINTS, 0, arrVtx.length / 2); |
第三个参数表示要绘制的顶点个数,本例中数组长度arrVtx.length除以每个顶点的数据数2表示绘制arrVtx中的全部顶点(共5个)
demo全部代码
1 | import vsSource from '~/index.vs'; |
本文主要参考《WebGL编程指南》