// 首先要在 JavaScript 里存在这个数据(废话) const positions = [-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0] // 创建一个 buffer,返回 buffer id const positionBuffer = gl.createBuffer() gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer) gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW)bindBuffer 会将一个 buffer 绑定到一个 target,也就是 gl.ARRAY_BUFFER,它专门用于储存 vertex shader 的 attribute。
const programInfo = { program: shaderProgram, attribLocations: { vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'), }, uniformLocations: { projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), }, }通过 getAttribLocation 可以获得一个 shader 程序的某个 attribute 的地址,当然 uniform 同理。
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position) // 把 buffer 真正放到 aVertexPosition gl.vertexAttribPointer( programInfo.attribLocations.vertexPosition, numComponents, type, normalize, stride, // 每组长度 offset // 每组偏移 ) gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition)接着就跟上面思路差不多,通过 bindBuffer 把 buffers.position 设为当前激活 buffer。然后使用 vertexAttribPointer 把当前激活的 gl.ARRAY_BUFFER 塞到上一步获取的 attribute 地址。最后的 enableVertexAttribArray 用于启用某个地址的 attribute,因为默认所有 attribute 都是未启用的,都需要通过这个接口启用,另外启用不必一定放在最后,拿到地址就能直接启用。
7.enableVertexAttribArray 启用 attribute
gl.uniformMatrix4fv( programInfo.uniformLocations.projectionMatrix, false, projectionMatrix )也就是传入 Float32Array 到 getUniformLocation 得到的地址即可。类似的方法还有 uniform[1234][fi][v] 这么一堆,都用于向 shader 传入其他类型的 uniform 数据。
const texture = gl.createTexture() gl.bindTexture(gl.TEXTURE_2D, texture) gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, image) gl.activeTexture(gl.TEXTURE0) gl.bindTexture(gl.TEXTURE_2D, texture) gl.uniform1i(programInfo.uniformLocations.uSampler, 0)为什么又 active 又 bind 的呢?我们首先要理解这个过程中涉及到两个名词:
const texture = gl.createTexture() gl.bindTexture(gl.TEXTURE_2D, texture) gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, image)这三步和 attribute 类似,创建 texture object,激活,然后塞数据。
gl.activeTexture(gl.TEXTURE0) gl.bindTexture(gl.TEXTURE_2D, texture)activeTexture 指的是激活 texture unit,设为 gl.TEXTURE0 当前激活的 texture unit 就是 0。然后再 bindTexture 可以让当前 texture object 绑定到当前 texture unit(这里我无法理解,为什么激活 object 会附带绑定功能,求懂的大佬们补充)。
gl.uniform1i(programInfo.uniformLocations.uSampler, 0) // 然后就能使用 uniform sampler2D uSampler虽然一直在说 sampler2D,但其实变量类型归根到底还是 uniform,所以最后还是通过 uniform1i 传入到 shader。特殊的是传给他的值是一个 texture unit 地址,官方规范说明,加载 sampler 仅能用 glUniform1i 和 glUniform1iv。
glUniform1i and glUniform1iv are the only two functions that may be used to load uniform variables defined as sampler types. Loading samplers with any other function will result in a GL_INVALID_OPERATION error.