WebGLBuffer 像一个数据包,可以存放顶点坐标、颜色之类的数据,可以通过 WebGL API 一次性把 Javascript 数据写入 Buffer,WebGL 也可以一次性从Buffer中读取到着色器中。
一、写入数据
写入数据的大致流程如下:
- 调用
createBuffer创建WebGLBuffer对象; - 通过
bindBuffer将gl.ARRAY_BUFFER和WebGLBuffer绑定; - 通过
bufferData将 JS 里的Array数据更新到ARRAY_BUFFER中; - 此时数据就通过
ARRAY_BUFFER进到WebGLBuffer中了; - 通过
deleteBuffer可以删除WebGLBuffer对象;
往WebGLBuffer缓冲区写数据需要用到gl.ARRAY_BUFFER这个属性,ARRAY_BUFFER就像一个临时的数据桥梁🌉或者数据转运卡车🚚一样,把Javascript环境下的的Arrary转达给WebGL的WebGLBuffer。
如果后面没有在重新调用过bindBuffer,那么所有的数据都会通过ARRAY_BUFFER写到上次绑定的WebGLBuffer中。
// 准备三个二维点坐标,普通数组
let positions = [-0.5, -0.5, 0, 0, 0.5, -0.5];
// 创建一个缓冲区对象
let positionBuffer = gl.createBuffer();
// 把刚才创建的缓冲区对象绑定到gl的 ARRAY_BUFFER上,设置为当前默认的缓冲区,后面的所有的数据都会都会被放入当前缓冲区,直到bindBuffer绑定另一个当前缓冲区。
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 将数据存放放到缓冲区,gl.STATIC_DRAW 指定数据存储区的使用方法:缓存区的内容可能会经常使用,但是不会更改。
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
二、读取数据
从 WebGLBuffer 读取 Attributes 数据到着色器大致是以下步骤:
- 通过
getAttribLocation获取着色器中 Attributes 变量的位置,指定Buffer中的数据给哪个 Attributes 变量使用; - 通过
enableVertexAttribArray激活 Attributes 变量,将着色器变量和 Buffer 关联起来。 - 通过
vertexAttribPointer、vertexAttrib*开始从缓冲区中读取数据
vertexAttribPointer需要设置以下参数:
- location 着色器变量位置,也即要给哪个变量赋值
- size 每个顶点有几个单位的数据,只能说1~4
- type 单位数据类型是什么,可以是
-
- gl.BYTE:-128 ~ 127,占用1个字节
- gl.SHORT:-32768 ~ 32767,占用2个字节
- gl.INT:-2147483648 ~ 2147483647,占用4个字节
- gl.FLOAT:3.402823e+38 ~ 1.401298e-45,占用4个字节
- ......
- normalize 是否进行归一化
- stride 是从一个数据到下一个数据要跳过多少位
- offset 是数据从缓冲的哪个位置开始
vertexAttrib*可以不借助 WebGLBuffer 直接赋值
经过以上步骤后,就能在着色器运行的时候读取到WebGLBuffer里的数据了。
需要注意的是,缓冲区里的数据并不是一次性全部读完的,顶点着色器每运行一次,会按照vertexAttribPointer的参数从指定的缓冲区获取下一个值。
// 获取给定 program 对象中某属性的下标指向位置
let positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
// 激活顶点着色器中的变量属性以便赋值,将着色器变量和Buffer关联起来
gl.enableVertexAttribArray(positionAttributeLocation);
// 从当前绑定的缓冲区(bindBuffer()指定的缓冲区)中读取数据,赋值给顶点着色器变量使用
let size = 2; // 每次迭代运行提取两个单位数据
let type = gl.FLOAT; // 每个单位的数据类型是32位浮点型
let normalize = false; // 不需要归一化数据
let stride = 0; // 0 = 移动单位数量 * 每个单位占用内存(sizeof(type)),每次迭代运行运动多少内存到下一个数据开始点
let offset = 0; // 从缓冲起始位置开始读取
gl.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);
// 顶点着色器使用顶点数据
let vertexShaderSource = `
attribute vec4 a_position; // buffer 中读取的顶点坐标
attribute vec2 a_texCoord; // buffer 中读取的纹理坐标
varying vec2 v_texCoord; // 传给片元着色器的纹理坐标
void main() {
gl_Position = a_position;
v_texCoord = a_texCoord;
}
`;
这是WebGL 系列的入门文章,免费订阅,如有帮助请点赞收藏,纰漏之处欢迎指正!
也欢迎关注公众号交流知识哇😄