首页/ 学科题库/ webgl/ WebGL 渲染管线流程与顶点着色器最小实现
webgl 实战教程

WebGL 渲染管线流程与顶点着色器最小实现

2026-09-13 约 9 分钟 juanwangdev

WebGL 渲染管线流程与顶点着色器最小实现

一句话结论:WebGL 渲染管线是一条固定的流水线,顶点着色器决定图形在哪,片元着色器决定像素什么颜色,中间的光栅化由 GPU 自动完成。

可编程渲染管线流程

是什么

可编程渲染管线是 WebGL 处理一次绘制请求的固定流程,依次经过顶点着色器、图元装配、光栅化、片元着色器与逐片元操作五个阶段。其中只有顶点着色器与片元着色器允许开发者编写代码,其余阶段由 GPU 按固定规则执行。

解决什么问题

它解决的是“如何把一堆顶点数据变成屏幕上的像素”这一问题。管线把任务拆成可并行的小步骤:顶点阶段并行处理每个顶点,片元阶段并行处理每个像素,开发者只需关心两个着色器的输入输出,不必操心并行调度与光栅化细节。

为什么这样做

采用固定管线加可编程阶段的设计,是因为顶点与像素的处理天然可并行且彼此独立。GPU 为每个顶点和每个像素分配独立执行单元,同一份着色器代码同时运行上千次,从而获得远超 CPU 的吞吐。代价是阶段之间只能通过规定的内置变量与插值传递数据。

怎么用

glsl
// 顶点着色器:决定顶点位置
attribute vec3 aPosition;
void main() {
  gl_Position = vec4(aPosition, 1.0);
}
glsl
// 片元着色器:决定像素颜色
void main() {
  gl_FragColor = vec4(0.29, 0.55, 0.94, 1.0);
}

数据流:顶点数据 → 顶点着色器(位置变换)→ 图元装配(组成三角形)→ 光栅化(拆成像素)→ 片元着色器(上色)→ 深度与混合 → 帧缓冲。

常见坑

  • 以为片元着色器一定按顶点顺序执行 → 原因:光栅化后片元是并行且无序的 → 处理:不要依赖跨像素的共享状态
  • 在顶点着色器里写逐像素效果 → 原因:顶点数量远少于像素 → 处理:面片级别的效果全部下移到片元着色器
  • 忽略图元装配的顶点数量要求 → 原因:TRIANGLES 必须每三个顶点一组 → 处理:顶点数不足时补齐或改用 TRIANGLE_STRIP

顶点着色器最小实现

是什么

顶点着色器最小实现是一段只做一件事的 GLSL 代码:把输入的顶点位置写入内置变量 gl_Position。它是所有渲染逻辑的起点,坐标变换、法线处理、UV 传递都在这个阶段完成。

解决什么问题

它解决“图形画在哪、多大、什么朝向”的问题。顶点着色器输出的是裁剪坐标系下的四维坐标,GPU 会在后续阶段自动做透视除法与视口映射,因此只要把坐标算对,图形位置就正确,无需关心屏幕像素。

为什么这样做

把位置计算放在顶点阶段,是因为同一套变换对每个顶点都要执行,由 GPU 并行处理效率最高。gl_Position 采用四维齐次坐标,第四个分量 w 用于透视除法,使远处的物体自动变小,透视投影因此只需一次矩阵乘法即可完成。

怎么用

glsl
attribute vec3 aPosition;   // 逐顶点属性,由 JavaScript 传入
uniform mat4 uMvpMatrix;    // 每帧一致,由 JavaScript 传入

void main() {
  gl_Position = uMvpMatrix * vec4(aPosition, 1.0);
}
JavaScript
// 画一个覆盖画布的三角形:三个顶点落在裁剪空间 -1 到 1 之内
const vertices = new Float32Array([
  -0.8, -0.6, 0,
   0.8, -0.6, 0,
   0.0,  0.8, 0,
]);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, 3);

裁剪坐标范围是 -1 到 1,超出部分被裁掉;w 分量若为 0,GPU 认为顶点在无穷远,该图元会被丢弃。

常见坑

  • 顶点全在视野外导致黑屏 → 原因:坐标超出 -1 到 1 又未做投影变换 → 处理:先用固定坐标验证管线,再接入矩阵
  • 忘记给 gl_Position 赋值 → 原因:GLSL 不会报编译错误 → 处理:保证 main 中必定赋值,不要放在条件分支外
  • 传错向量维度 → 原因:vec4(vec3, 1.0) 的 w 必须显式写出 → 处理:位置向量统一补 1.0,法线补 0.0
  • 每帧重算静态顶点 → 原因:未区分静态与动态数据 → 处理:静态顶点只上传一次,用缓冲对象复用

要点总结

  • 渲染管线固定为顶点着色器、图元装配、光栅化、片元着色器、逐片元操作五步
  • 只有顶点与片元着色器可编程,其余阶段由 GPU 自动完成
  • 顶点着色器必须给 gl_Position 赋值,坐标是裁剪空间下的四维齐次向量
  • 裁剪坐标范围是 -1 到 1,w 为 0 的顶点会被丢弃
  • 逐顶点计算放在顶点着色器,逐像素计算放在片元着色器

常见问题

WebGL 渲染管线分为哪些阶段?

依次是顶点着色器、图元装配、光栅化、片元着色器与逐片元操作。顶点着色器决定顶点位置,光栅化把图元拆成像素,片元着色器决定每个像素的颜色。

顶点着色器必须输出什么?

必须给内置变量 gl_Position 赋值,它是裁剪坐标系下的四维向量,取值范围在 -w 到 w 之间,超出范围的部分会被裁剪掉。

为什么顶点着色器里写的坐标能画满整个画布?

因为裁剪空间的范围是 -1 到 1,顶点坐标落在这个区间内就映射到画布边界,因此不写任何矩阵也能画出覆盖全屏的三角形。

顶点着色器可以做什么、不可以做什么?

可以做顶点位置变换、法线与 UV 传递、逐顶点属性计算。它无法访问相邻顶点,也不能读取纹理,需要邻接信息的算法要在 CPU 侧或片元阶段完成。

想在手机上练这篇的配套题目?
使用微信 卷王开发者小程序/App,首页顶部扫一扫识别下方二维码,即可解锁本讲对应真题与错题本。
了解产品 App
← 上一篇 WebGL 上下文创建与尺寸适配实战 下一篇 → WebGL 片元着色器与 attribute、uniform 数据传参