WebGL - 示例应用
WebGL - 示例应用:绘制一个三角形
Section titled “WebGL - 示例应用:绘制一个三角形”在涵盖了 WebGL 的基础概念如上下文(contexts)、几何体(geometry)、缓冲区(buffers)和着色器(shaders)之后,让我们将它们组合起来,通过一个最小的完整示例来绘制一个简单的 2D 三角形。这展示了一个 WebGL 应用的基本结构和工作流程。
WebGL 应用的结构
Section titled “WebGL 应用的结构”典型的 WebGL 应用包括:
- HTML: 一个
<canvas>元素作为绘制表面。 - JavaScript: 主逻辑,协调 WebGL API 调用。它准备数据、编译着色器、设置缓冲区、配置 attributes/uniforms,并触发绘制命令。
- GLSL(着色器代码): 顶点和片段着色器程序,定义 GPU 如何处理顶点并确定像素颜色。
JavaScript 扮演着指挥者的角色,准备所有内容并通过 WebGL API 将指令和数据发送到 GPU。GLSL 着色器在 GPU 上执行,负责繁重的渲染工作。
示例应用:绘制一个 2D 三角形
Section titled “示例应用:绘制一个 2D 三角形”此示例演示了绘制一个静态、单色三角形的核心步骤。
<!doctype html><html lang="en"><head> <meta charset="utf-8"> <title>WebGL Simple Triangle</title> <style>canvas { border: 1px solid black; }</style></head><body> <canvas width="300" height="300" id="my_Canvas"></canvas>
<script> /* 步骤 1: 准备 canvas 并获取 WebGL 上下文 */ const canvas = document.getElementById('my_Canvas'); const gl = canvas.getContext('webgl'); // 请求 WebGL 1 上下文
if (!gl) { alert('WebGL is not supported by your browser.'); throw new Error('WebGL not supported'); }
/* 步骤 2: 定义几何体并将其存储在缓冲区对象中 */ // 定义三角形的顶点 (X, Y 坐标) const vertices = new Float32Array([ -0.5, 0.5, // 顶部顶点 -0.5, -0.5, // 左下角顶点 0.0, -0.5 // 右下角顶点 (已修改为非对称) ]);
// 在 GPU 上创建一个缓冲区对象 const vertexBuffer = gl.createBuffer();
// 将缓冲区绑定到 ARRAY_BUFFER 目标 (使其成为当前的 VBO) gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 将顶点数据 (TypedArray) 传递给当前绑定的缓冲区 gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 解除绑定缓冲区 (一个好习惯,尽管在此处并非强制要求) // gl.bindBuffer(gl.ARRAY_BUFFER, null);
/* 步骤 3: 创建并编译着色器程序 */
// 顶点着色器源代码 (GLSL ES 1.00) const vsSource = ` attribute vec2 aVertexPosition; // 输入顶点位置 (2D) void main(void) { // 输出剪辑空间中的位置 (XY 来自 attribute, Z=0, W=1) gl_Position = vec4(aVertexPosition, 0.0, 1.0); } `;
// 片段着色器源代码 (GLSL ES 1.00) const fsSource = ` // 设置浮点变量的精度(片段着色器中必需) precision mediump float; void main(void) { // 输出颜色:红色 (R=1, G=0, B=0, Alpha=1) gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } `;
// 用于编译着色器的辅助函数 function compileShader(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; }
const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fsSource);
// 创建一个着色器程序对象来链接着色器 const shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { console.error('Shader program linking error:', gl.getProgramInfoLog(shaderProgram)); throw new Error('Shader program link failed'); }
// 告诉 WebGL 在后续绘制中使用此程序 gl.useProgram(shaderProgram);
/* 步骤 4: 将着色器程序与缓冲区对象关联 */
// 在着色器程序中获取 attribute 的位置 (索引) const positionAttributeLocation = gl.getAttribLocation(shaderProgram, 'aVertexPosition');
// 确保顶点缓冲区再次绑定 (如果之前解除了绑定) gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 告诉 WebGL 如何从绑定的缓冲区读取数据到 attribute const numComponents = 2; // 每个顶点 2 个值 (X, Y) const type = gl.FLOAT; // 数据类型为 32 位浮点数 const normalize = false; // 不对数据进行归一化 const stride = 0; // 0 = 使用 size * sizeof(type) 获取下一个顶点 const offset = 0; // 从缓冲区的开始位置 (偏移量为 0) 开始 gl.vertexAttribPointer( positionAttributeLocation, numComponents, type, normalize, stride, offset);
// 启用顶点 attribute 数组 gl.enableVertexAttribArray(positionAttributeLocation);
/* 步骤 5: 绘制所需对象 (三角形) */
// 设置清除颜色(用于清除 canvas 的颜色) gl.clearColor(0.8, 0.8, 0.8, 1.0); // 浅灰色
// 用指定的清除颜色清除颜色缓冲区 gl.clear(gl.COLOR_BUFFER_BIT);
// 设置视口(将 NDC -1 到 1 映射到 canvas 像素 0 到 width/height) gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// 绘制三角形 const primitiveType = gl.TRIANGLES; // 绘制填充三角形 const drawOffset = 0; // 从第一个顶点开始 const vertexCount = 3; // 绘制 3 个顶点 (形成一个三角形) gl.drawArrays(primitiveType, drawOffset, vertexCount);
</script>
</body></html>预期结果:
这段代码将在 300x300 的 canvas 中,以浅灰色背景显示一个实心红色三角形。
-
获取上下文: 从 HTML
<canvas>中获取 WebGL 渲染上下文。 -
定义几何体和缓冲区: 为顶点数据创建 JavaScript Typed Arrays。创建 WebGL 缓冲区对象(
gl.createBuffer),绑定它们(gl.bindBuffer),并上传数据(gl.bufferData)。 -
创建并编译着色器: 编写顶点和片段着色器的 GLSL 代码。编译它们(
gl.compileShader)并链接到一个着色器程序(gl.createProgram,gl.attachShader,gl.linkProgram)。在每个阶段检查错误。 -
关联 Attributes/缓冲区: 获取 attribute 位置(
gl.getAttribLocation)。绑定相应的顶点缓冲区。配置 attribute 如何从缓冲区读取数据(gl.vertexAttribPointer)。启用 attribute(gl.enableVertexAttribArray)。(如果使用了 Uniforms,也在这里设置)。 -
绘制: 设置视口(
gl.viewport),清除 canvas(gl.clearColor,gl.clear)。使用配置好的程序和缓冲区发出绘制命令(gl.drawArrays或gl.drawElements)。
这些核心步骤构成了所有 WebGL 渲染的基础。