Skip to content

WebGL - 绘制模型

一旦顶点数据被加载到缓冲区中并与着色器属性关联,最后一步就是渲染几何体。WebGL 提供了两种主要方法来实现这一点:drawArrays() 和 drawElements()。这些函数指示 GPU 基于已绑定的缓冲区数据和当前活动的着色器程序绘制图元。

drawArrays() 用于当你的顶点数据在缓冲区中按顺序排列,且你不需要单独的索引数据时。

语法:

gl.drawArrays(mode, first, count);

此方法接受三个参数:

  • mode:指定要渲染的图元类型。常用值包括 gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN 和 gl.TRIANGLES。选择取决于你希望 WebGL 如何解释顶点数据以形成形状。
  • first:一个整数,指定启用顶点属性数组中的起始索引。通常为 0。
  • count:一个整数,指定要渲染的顶点数量。

使用 drawArrays() 时,WebGL 按顶点在已绑定的 ARRAY_BUFFER 中出现的顺序处理它们。例如,对于 gl.TRIANGLES,每三个连续顶点形成一个三角形。

要使用 drawArrays() 绘制单个三角形,你需要提供三个顶点,并将 count 参数指定为 3。

// Assuming 'gl' is your WebGL rendering context
// Assuming vertex buffer with these coordinates is already bound and configured
const vertices = [
// X, Y, Z
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0
];
// Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, 3); // 3 vertices form one triangle

这段代码,结合合适的顶点和片段着色器,将在 Canvas 上渲染一个单个三角形。

要使用 gl.TRIANGLES 绘制两个独立的三角形,总共需要六个顶点。

// Assuming 'gl' is your WebGL rendering context
// Assuming vertex buffer with these coordinates is already bound and configured
const vertices = [
// Triangle 1
-0.9, -0.5, 0.0,
-0.1, -0.5, 0.0,
-0.5, 0.5, 0.0,
// Triangle 2
0.1, -0.5, 0.0,
0.9, -0.5, 0.0,
0.5, 0.5, 0.0
];
// Draw two triangles
gl.drawArrays(gl.TRIANGLES, 0, 6); // 6 vertices form two separate triangles

这将渲染两个并列的独立三角形。

drawElements() 用于当你想通过使用索引指定顶点顺序来重复使用顶点时。对于复杂模型来说,这种方式通常更有效,因为它减少了所需的顶点数据量。

语法:

gl.drawElements(mode, count, type, offset);

此方法接受四个参数:

  • mode:同 drawArrays() 中的 mode,指定图元类型(例如 gl.TRIANGLES)。
  • count:一个整数,指定要从索引缓冲区渲染的元素(索引)数量。
  • type:指定元素数组缓冲区(索引缓冲区)中值的 GFX 数据类型。必须是 gl.UNSIGNED_BYTE、gl.UNSIGNED_SHORT 或 gl.UNSIGNED_INT(后者在 WebGL 1 中需要 OES_element_index_uint 扩展,在 WebGL 2 中是标准)。gl.UNSIGNED_SHORT 常用。
  • offset:元素数组缓冲区中的字节偏移量。通常为 0。

使用 drawElements() 需要你创建并绑定一个 ELEMENT_ARRAY_BUFFER,其中包含索引。WebGL 使用这些索引在 ARRAY_BUFFER 中查找顶点。这允许在多个图元(如网格中的三角形)之间共享的顶点只存储一次。

要使用索引绘制单个三角形,你需要定义顶点和一个指定哪些顶点构成三角形的索引数组。

// Assuming 'gl' is your WebGL rendering context
// Assuming vertex buffer is bound to gl.ARRAY_BUFFER
// Assuming index buffer is bound to gl.ELEMENT_ARRAY_BUFFER
const vertices = [
// X, Y, Z (Vertex 0)
-0.5, -0.5, 0.0,
// X, Y, Z (Vertex 1)
0.5, -0.5, 0.0,
// X, Y, Z (Vertex 2)
0.0, 0.5, 0.0
];
const indices = [0, 1, 2]; // Use vertices 0, 1, and 2 to form the triangle
// Create and bind buffers, load data (details omitted for brevity)
// ... buffer setup code ...
// Draw the triangle using indices
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

这将渲染与 drawArrays 示例相同的三角形,但展示了索引的使用方法。

示例:绘制两个相邻三角形(形成一个四边形)

Section titled “示例:绘制两个相邻三角形(形成一个四边形)”

drawElements() 在共享顶点时优势明显。要绘制构成四边形的两个三角形,你只需要四个顶点。

// Assuming 'gl' is your WebGL rendering context
// Assuming vertex and index buffers are set up and bound
const vertices = [
// X, Y, Z
-0.5, 0.5, 0.0, // Top-left (Vertex 0)
-0.5, -0.5, 0.0, // Bottom-left (Vertex 1)
0.5, -0.5, 0.0, // Bottom-right(Vertex 2)
0.5, 0.5, 0.0 // Top-right (Vertex 3)
];
// Indices for two triangles sharing vertices 1 and 3 (or 0 and 2 depending on order)
const indices = [
0, 1, 2, // First triangle (top-left, bottom-left, bottom-right)
0, 2, 3 // Second triangle (top-left, bottom-right, top-right)
];
// Create and bind buffers, load data (details omitted for brevity)
// ... buffer setup code ...
// Draw the quad (two triangles) using indices
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

这将渲染一个由两个三角形组成的四边形,高效地重复使用了角上的顶点。

在调用 drawArrays() 或 drawElements() 之前,通常需要在每个渲染帧中执行几个设置步骤:

使用 clearColor() 设置 WebGL 用于清除绘图缓冲区的颜色。这相当于设置背景颜色。它接受四个参数:红、绿、蓝和 alpha(范围都是从 0.0 到 1.0)。

// Set clear color to a medium gray
gl.clearColor(0.5, 0.5, 0.5, 1.0);

然后使用 clear() 方法执行实际的清除操作(见步骤 3)。

对于 3D 渲染,启用深度测试以确保靠近观察者的物体正确遮挡较远的物体。这使用了深度缓冲区。

gl.enable(gl.DEPTH_TEST);

如果没有深度测试,物体可能会按照提交的顺序绘制,导致视觉重叠错误。

在绘制新帧之前,清除相关缓冲区。通常,你会清除颜色缓冲区和深度缓冲区。

// Clear the color buffer and the depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

|(按位或)运算符用于组合标志,以便一次调用清除多个缓冲区。

定义 Canvas 的矩形区域,WebGL 应该在此区域绘制。这通常设置为 Canvas 的完整大小。

// Assuming 'canvas' is your HTML canvas element
gl.viewport(0, 0, canvas.width, canvas.height);

参数是 (x, y, width, height),定义了 Viewport 在 Canvas 内的左下角和尺寸。

执行这些设置步骤后,绑定所需的缓冲区,配置顶点属性,并选择着色器程序,你就可以调用 drawArrays() 或 drawElements() 来渲染场景了。