WebGL - 绘制模式
WebGL - 绘制模式
Section titled “WebGL - 绘制模式”WebGL 提供了几种解释顶点数据以形成不同形状的方式,这些方式称为绘制模式(drawing modes)或基本类型(primitive types)。这些模式被指定为 gl.drawArrays() 和 gl.drawElements() 函数的第一个参数。
mode 参数
Section titled “mode 参数”回顾绘制命令的语法:
void gl.drawArrays(mode, first, count);void gl.drawElements(mode, count, type, offset);mode 参数决定了如何连接顶点(由 count 和 first/offset 指定,可能还有索引)来形成几何图元(geometric primitives)。
可用的绘制模式:
Section titled “可用的绘制模式:”| 序号 | 模式常量 | 描述 | 顶点顺序示例 |
|---|---|---|---|
| 1 | gl.POINTS | 为每个指定的顶点绘制一个点。点的大小可以通过顶点着色器中的 gl_PointSize 控制。 | |
| 2 | gl.LINES | 绘制一系列独立的线段。顶点 (0, 1)、(2, 3)、(4, 5) 等,每对形成一条独立的线段。需要偶数个顶点(count 必须是 2 的倍数)。 | |
| 3 | gl.LINE_STRIP | 绘制一系列相连的线段。顶点 (0, 1)、(1, 2)、(2, 3) 等,形成一条连续的折线。 | |
| 4 | gl.LINE_LOOP | 类似于 gl.LINE_STRIP,但会额外绘制一条线段连接最后一个顶点回第一个顶点,形成一个闭合循环。 | |
| 5 | gl.TRIANGLES | 绘制一系列独立的三角形。顶点 (0, 1, 2)、(3, 4, 5) 等,每三个形成一个独立的三角形。需要 count 是 3 的倍数。 | |
| 6 | gl.TRIANGLE_STRIP | 绘制一系列相连的三角形。在第一个三角形 (0, 1, 2) 之后,随后的顶点 n 形成三角形 (n-1, n-2, n)、(n-1, n, n+1) 等,交替缠绕顺序(winding order)。对于以条带形式表示的网格(meshes)渲染非常高效。 | Text Description: Creates triangles (v0,v1,v2), (v2,v1,v3), (v2,v3,v4), (v4,v3,v5)… |
| 7 | gl.TRIANGLE_FAN | 绘制一系列共享第一个顶点(顶点 0)的相连三角形。三角形的形成方式是 (0, 1, 2)、(0, 2, 3)、(0, 3, 4) 等。适用于绘制圆形、圆锥或扇形等形状。 | Text Description: Creates triangles (v0,v1,v2), (v0,v2,v3), (v0,v3,v4)… |
示例:使用 gl.LINES 绘制平行线
Section titled “示例:使用 gl.LINES 绘制平行线”此示例使用 gl.LINES 绘制三条独立的水平线段。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>WebGL Drawing Modes - Lines</title> <style> body { margin: 0; overflow: hidden; background-color: #fff; } canvas { display: block; border: 1px solid black; } </style></head><body> <canvas id="webgl-canvas" width="400" height="400"></canvas>
<script> // --- 着色器源代码(简单直通)--- const vsSource = ` attribute vec3 a_position; void main() { gl_Position = vec4(a_position, 1.0); // 使线即使很细也能可见 gl_PointSize = 1.0; // 如果线很细,某些驱动程序可能需要此设置 } `; const fsSource = ` precision mediump float; void main() { gl_FragColor = vec4(0.0, 0.0, 0.8, 1.0); // 蓝色 } `;
// --- 工具函数:createShader, createProgram (假定已定义) --- function createShader(gl, type, source) { /* ... */ const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { console.error(`Shader compilation error (${type === gl.VERTEX_SHADER ? 'Vertex' : 'Fragment'}):`, gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; } function createProgram(gl, vsSource, fsSource) { /* ... */ const vertexShader = createShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fsSource); if (!vertexShader || !fragmentShader) return null; const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.error('Program linking error:', gl.getProgramInfoLog(program)); gl.deleteProgram(program); return null; } return program; }
// --- 主 WebGL 代码 --- const canvas = document.getElementById('webgl-canvas'); const gl = canvas.getContext('webgl'); if (!gl) { alert('WebGL not supported.'); throw new Error('WebGL not supported'); }
const shaderProgram = createProgram(gl, vsSource, fsSource); if (!shaderProgram) throw new Error('Failed program creation.');
// --- 几何体(3 条独立线段的 6 个顶点)--- const lineVertices = new Float32Array([ // 第 1 条线 -0.7, 0.6, 0.0, // 起点 0.7, 0.6, 0.0, // 终点 // 第 2 条线 -0.7, 0.0, 0.0, 0.7, 0.0, 0.0, // 第 3 条线 -0.7, -0.6, 0.0, 0.7, -0.6, 0.0 ]);
// --- 缓冲区 --- const vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, lineVertices, gl.STATIC_DRAW);
// --- 属性设置 --- const positionAttribLocation = gl.getAttribLocation(shaderProgram, 'a_position'); if (positionAttribLocation < 0) console.error("Attr 'a_position' not found"); gl.enableVertexAttribArray(positionAttribLocation); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.vertexAttribPointer(positionAttribLocation, 3, gl.FLOAT, false, 0, 0);
// --- 绘制 --- gl.useProgram(shaderProgram); gl.clearColor(1.0, 1.0, 1.0, 1.0); // 白色背景 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// 使用 LINES 模式绘制 gl.drawArrays( gl.LINES, // 模式:绘制独立线段 0, // 起始索引 6 // 顶点数量 (3 条线段 * 每条线段 2 个顶点) );
</script></body></html>预期输出:
代码将在白色背景上垂直堆叠渲染出三条独立的水平蓝色线段。
可视化其他模式(使用相同的顶点)
Section titled “可视化其他模式(使用相同的顶点)”如果您使用上述示例中相同的六个顶点,并将 gl.LINES 更改为 gl.drawArrays 调用中的其他模式,您将看到不同的结果:
gl.LINE_STRIP:一条连接所有六个点的 Z 字形线:(-0.7, 0.6) -> (0.7, 0.6) -> (-0.7, 0.0) -> (0.7, 0.0) -> (-0.7, -0.6) -> (0.7, -0.6)。gl.LINE_LOOP:与gl.LINE_STRIP相同,但会额外绘制一条线连接最后一个点 (0.7, -0.6) 回第一个点 (-0.7, 0.6),形成一个闭合的复杂形状。gl.TRIANGLES:两个独立的三角形。第一个使用顶点 0、1、2 ((-0.7, 0.6), (0.7, 0.6), (-0.7, 0.0))。第二个使用顶点 3、4、5 ((0.7, 0.0), (-0.7, -0.6), (0.7, -0.6))。gl.TRIANGLE_STRIP:一系列相连的三角形:(0,1,2)、(1,2,3)、(2,3,4)、(3,4,5)。这会形成一个复杂、可能重叠的形状。gl.TRIANGLE_FAN:一组从顶点 0 发散的三角形:(0,1,2)、(0,2,3)、(0,3,4)、(0,4,5)。这也会形成一个以第一个顶点为中心的复杂形状。
选择正确的绘制模式取决于您想要渲染的几何体以及您的顶点/索引数据的组织方式。