概念介绍
WebGL 的渲染管线是 GPU 把"数据"变成"屏幕上的画面"的完整流程。理解它是学习 WebGL 的基础,因为你写的每一行代码,都是在管线的某个阶段发挥作用。
整个管线分为以下几个阶段:
CPU 准备数据
↓
顶点着色器(Vertex Shader)
↓
图元装配(Primitive Assembly)
↓
光栅化(Rasterization)
↓
片元着色器(Fragment Shader)
↓
深度测试 / 混合
↓
输出到屏幕
各阶段说明
1. CPU 准备数据
在 JavaScript 中准备好顶点坐标、颜色、纹理等数据,通过缓冲区上传到 GPU。
这是唯一由 CPU 完成的阶段,其余阶段全部在 GPU 上并行执行。
2. 顶点着色器(Vertex Shader)
GPU 对每个顶点运行一次顶点着色器,计算出顶点最终在屏幕上的位置,写入 gl_Position。
3. 图元装配(Primitive Assembly)
把顶点连接成图元(点、线、三角形)。例如 3 个顶点组成一个三角形。
4. 光栅化(Rasterization)
把三角形等几何图元转换成一个个像素格子(片元) 。这一步由 GPU 自动完成,开发者无需干预。
5. 片元着色器(Fragment Shader)
GPU 对**每个片元(像素)**运行一次片元着色器,决定该像素最终的颜色,写入 gl_FragColor。
6. 深度测试 / 混合
- 深度测试:判断像素是否被其他物体遮挡,决定是否丢弃
- 混合:处理透明度,将前后像素颜色合并
7. 输出到屏幕
最终结果写入帧缓冲,显示在 Canvas 上。
结合例子说明
画一个红色三角形的完整管线过程:
① CPU 准备 3 个顶点坐标,上传到 GPU 缓冲区
② 顶点着色器被执行 3 次(每个顶点一次)
→ 计算出三个顶点在屏幕上的位置
③ 图元装配:3 个顶点连接成一个三角形
④ 光栅化:三角形内部被分解成数百个像素格
⑤ 片元着色器被执行数百次(每个像素一次)
→ 每次都输出红色
⑥ 红色三角形出现在屏幕上
代码片段
// ① CPU 准备顶点数据
const vertices = new Float32Array([
0.0, 0.5, // 顶点1
-0.5, -0.5, // 顶点2
0.5, -0.5, // 顶点3
]);
// 上传到 GPU
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
/* ② 顶点着色器:处理每个顶点的位置 */
attribute vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
/* 光栅化由 GPU 自动完成,无需代码 */
}
/* ⑤ 片元着色器:决定每个像素的颜色 */
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
}
// ⑥ 触发绘制,管线开始执行
gl.drawArrays(gl.TRIANGLES, 0, 3);
总结
| 阶段 | 执行者 | 开发者是否可控 | 关键输出 |
|---|---|---|---|
| CPU 准备数据 | CPU | ✅ 完全可控 | 顶点缓冲区 |
| 顶点着色器 | GPU | ✅ 编写 GLSL | gl_Position |
| 图元装配 | GPU | ⚙️ 部分可控 | 三角形 / 线 / 点 |
| 光栅化 | GPU | ❌ 自动执行 | 片元列表 |
| 片元着色器 | GPU | ✅ 编写 GLSL | gl_FragColor |
| 深度测试混合 | GPU | ⚙️ 可配置 | 最终像素 |
| 输出屏幕 | GPU | ❌ 自动执行 | Canvas 画面 |
渲染管线是 WebGL 的骨架,后续所有概念(着色器、纹理、光照)都是在这个流程的某个阶段上做文章。理解了管线,学其他概念时就知道自己在"哪一步"工作。