WebGL - 几何图形
WebGL - 定义几何体和缓冲区
Section titled “WebGL - 定义几何体和缓冲区”要在 WebGL 中渲染任何对象(或图元),首先需要定义其几何体。这通常涉及指定顶点的位置,以及(可选地)如何使用索引将这些顶点连接起来形成形状。还可以包含其他逐顶点数据,如颜色或纹理坐标。
这些几何数据源自你的 JavaScript 代码,通常存储在类型化数组中,并且必须传输到 GPU 的内存中供着色器访问。这个传输过程通过 WebGL 缓冲区对象(Buffer Objects)完成。
在 JavaScript 中定义几何数据
Section titled “在 JavaScript 中定义几何数据”使用 JavaScript 类型化数组定义形状的顶点(和可选的索引),类型化数组提供原始二进制数据视图,这对于 WebGL 至关重要。
示例:一个简单的 2D 三角形
Section titled “示例:一个简单的 2D 三角形”顶点定义了角点。对于坐标为 (0.0, 0.5)、(-0.5, -0.5) 和 (0.5, -0.5) 的三角形:
const triangleVertices = new Float32Array([ 0.0, 0.5, // Vertex 0 (Top) - 顶点 0(顶部) -0.5, -0.5, // Vertex 1 (Bottom Left) - 顶点 1(左下) 0.5, -0.5 // Vertex 2 (Bottom Right) - 顶点 2(右下)]);如果直接使用 gl.drawArrays 绘制这个三角形,你并不严格需要索引。但是,如果使用 gl.drawElements 或定义更复杂的形状,则会使用索引。
示例:使用索引的正方形
Section titled “示例:使用索引的正方形”一个正方形可以由两个共享顶点的三角形组成。顶点:0=(-0.5, 0.5),1=(0.5, 0.5),2=(0.5, -0.5),3=(-0.5, -0.5)。
const squareVertices = new Float32Array([ -0.5, 0.5, // Vertex 0 - 顶点 0 0.5, 0.5, // Vertex 1 - 顶点 1 0.5, -0.5, // Vertex 2 - 顶点 2 -0.5, -0.5 // Vertex 3 - 顶点 3]);
// Indices define two triangles: (0, 3, 1) and (1, 3, 2) - 索引定义了两个三角形:(0, 3, 1) 和 (1, 3, 2)const squareIndices = new Uint16Array([ 0, 3, 1, // First triangle (Top-left, Bottom-left, Top-right) - 第一个三角形(左上,左下,右上) 1, 3, 2 // Second triangle (Top-right, Bottom-left, Bottom-right) - 第二个三角形(右上,左下,右下)]);使用索引(Uint16Array 或 Uint32Array)允许重用顶点数据,节省内存并可能提高性能。
缓冲区对象 (Buffer Objects) (VBOs 和 IBOs)
Section titled “缓冲区对象 (Buffer Objects) (VBOs 和 IBOs)”WebGL 缓冲区对象是分配在 GPU 上的内存,用于存储渲染数据。它们对于将几何体(和其他数据)从 CPU (JavaScript) 高效地传输到 GPU (着色器) 至关重要。
用于几何体的两种主要类型是:
- **顶点缓冲区对象 (Vertex Buffer Object, VBO):**存储逐顶点数据,如坐标、颜色、纹理坐标、法线。绑定到
gl.ARRAY_BUFFER目标。 - **索引缓冲区对象 (Index Buffer Object, IBO):**存储用于索引绘制(
gl.drawElements)的顶点索引。绑定到gl.ELEMENT_ARRAY_BUFFER目标。
使用缓冲区的工作流程:
- **创建缓冲区:**使用
gl.createBuffer()获取一个空的缓冲区对象引用。 - **绑定缓冲区:**使用
gl.bindBuffer(target, buffer)将缓冲区绑定到特定目标(VBO 用gl.ARRAY_BUFFER,IBO 用gl.ELEMENT_ARRAY_BUFFER)。之后所有针对该目标的操作都会影响绑定的缓冲区。 - **上传数据:**使用
gl.bufferData(target, data, usage)分配内存并将数据从类型化数组(data)复制到当前绑定的缓冲区中。usage提示(例如gl.STATIC_DRAW、gl.DYNAMIC_DRAW)告诉 WebGL 你打算如何使用这些数据,可能允许进行优化。 - **解绑缓冲区(可选但推荐):**使用
gl.bindBuffer(target, null)解除缓冲区与目标的绑定。这可以防止意外修改。 - **配置属性(针对 VBO):**稍后,你需要再次绑定 VBO,并使用
gl.vertexAttribPointer告诉 WebGL 着色器中的顶点属性如何从其中读取数据。
缓冲区使用提示 (gl.bufferData)
Section titled “缓冲区使用提示 (gl.bufferData)”gl.bufferData 的 usage 参数有助于 WebGL 驱动程序优化内存放置和访问:
gl.STATIC_DRAW:数据设置一次并使用多次(例如,静态模型几何体)。最常见。gl.DYNAMIC_DRAW:数据频繁更新并使用多次(例如,动画角色的顶点)。gl.STREAM_DRAW:数据设置一次且仅使用几次(例如,粒子效果数据)。
这些只是提示;实际实现可能将它们处理得类似,但提供正确的提示是良好的实践。
示例:创建和填充缓冲区
Section titled “示例:创建和填充缓冲区”// Assume 'gl' is the WebGLRenderingContext - 假设 'gl' 是 WebGL 渲染上下文// Assume 'triangleVertices' and 'squareIndices' TypedArrays exist - 假设 'triangleVertices' 和 'squareIndices' 类型化数组存在
// --- Vertex Buffer (VBO) ---const vertexBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER, triangleVertices, gl.STATIC_DRAW);// gl.bindBuffer(gl.ARRAY_BUFFER, null); // Optional unbind - 可选的解绑
// --- Index Buffer (IBO) ---const indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, squareIndices, gl.STATIC_DRAW);// gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); // Optional unbind - 可选的解绑顶点数组对象 (Vertex Array Objects, VAOs)
Section titled “顶点数组对象 (Vertex Array Objects, VAOs)”设置顶点属性需要绑定正确的 VBO,并为每个属性调用 gl.vertexAttribPointer 和 gl.enableVertexAttribArray。这种设置可能很复杂,特别是对于具有多个属性的模型。
顶点数组对象 (VAO) 存储了所有这些配置状态:绑定了哪些 VBO,每个属性如何从其 VBO 读取数据,以及哪些属性已启用。
使用 VAOs 的工作流程:
- 创建 VAO:
const vao = gl.createVertexArray();(注意:在 WebGL 1 中,需要OES_vertex_array_object扩展:gl.createVertexArrayOES()) - 绑定 VAO:
gl.bindVertexArray(vao); - **设置缓冲区和属性:**执行对象所需的所有
gl.bindBuffer、gl.bufferData、gl.vertexAttribPointer、gl.enableVertexAttribArray调用。如果使用 IBO,也需要绑定 IBO (gl.ELEMENT_ARRAY_BUFFER)。 - 解绑 VAO:
gl.bindVertexArray(null);(以防止意外更改) - **进行绘制:**只需绑定 VAO (
gl.bindVertexArray(vao);),然后进行绘制调用 (gl.drawArrays或gl.drawElements)。所有相关的缓冲区绑定和属性配置都会自动恢复。
VAOs 显著简化了渲染循环,并通过减少每帧的 WebGL 状态更改次数,通常能提高性能。它们是 WebGL 2 中的标准且强制要求的功能。
WebGL 缓冲区 API 方法
Section titled “WebGL 缓冲区 API 方法”以下是关键的缓冲区相关方法的总结: