WebGL - 图形渲染管线
WebGL - 图形管线
Section titled “WebGL - 图形管线”WebGL 图形管线(或称渲染管线)是 WebGL 将你的 3D 场景描述(顶点、着色器、纹理)转换为显示在 Canvas 上的 2D 图像所采取的步骤序列。理解这个过程有助于优化性能和调试渲染问题。
管线涉及在 CPU(通过 JavaScript)上执行的阶段和在 GPU(固定功能硬件和可编程着色器)上执行的阶段。数据从你的应用代码流出,经过管线,最终在 Framebuffer(帧缓冲区)中生成像素。
管线的概念阶段:
Section titled “管线的概念阶段:”1. JavaScript 应用 (CPU)
Section titled “1. JavaScript 应用 (CPU)”- 数据准备: 使用 JavaScript Typed Arrays(类型化数组)定义顶点坐标、颜色、纹理坐标和索引。
- 资源分配: 创建 WebGL 资源,如缓冲区 (
gl.createBuffer)、纹理 (gl.createTexture)、着色器程序 (gl.createProgram)。 - 数据传输: 将数据从 JavaScript Typed Arrays 上传到 GPU 缓冲区 (
gl.bufferData) 和纹理 (gl.texImage2D)。 - 着色器编译/链接: 编译 GLSL 着色器代码 (
gl.compileShader) 并链接到程序 (gl.linkProgram)。 - 状态配置: 设置各种 WebGL 状态(Viewport、清除颜色、深度测试、混合函数、活动纹理单元)。
- 属性/Uniform 设置: 配置顶点属性如何从缓冲区读取数据 (
gl.vertexAttribPointer,gl.enableVertexAttribArray) 并设置 Uniform 值 (gl.uniform*)。 - 发出绘制调用: 使用
gl.drawArrays或gl.drawElements指示 GPU 进行渲染。
2. 顶点获取 (GPU)
Section titled “2. 顶点获取 (GPU)”基于绘制调用(drawArrays 或 drawElements)和属性配置(vertexAttribPointer),GPU 从已绑定的 VBOs(如果使用 drawElements,还有 IBO)中获取所需的顶点数据。
3. 顶点着色器 (GPU - 可编程)
Section titled “3. 顶点着色器 (GPU - 可编程)”- 接收顶点属性(位置、颜色等)和 Uniform。
- 执行变换(模型-视图-投影,即 Model-View-Projection)、每顶点光照计算、纹理坐标生成等计算。
- 必须 将最终顶点位置以齐次裁剪空间坐标(Homogeneous Clip Space)输出到内置变量
gl_Position。 - 可以通过
varying变量将插值数据(如颜色、纹理坐标)传递给片段着色器。
4. 图元组装 (GPU - 固定功能)
Section titled “4. 图元组装 (GPU - 固定功能)”转换后的顶点根据绘制调用中指定的 mode 和顶点顺序/索引组装成几何图元(点、线、三角形)。
5. 光栅化 (GPU - 固定功能)
Section titled “5. 光栅化 (GPU - 固定功能)”- 裁剪 (Clipping): 丢弃位于 [-1, +1] 裁剪空间体之外的图元部分。
- 透视除法 (Perspective Divide): 将裁剪空间坐标 (x, y, z) 除以 w 得到归一化设备坐标 (NDC)。
- 视口变换 (Viewport Transform): 根据
gl.viewport将 NDC 坐标映射到窗口(像素)坐标。 - 背面剔除 (Culling): (可选)丢弃正面或背面三角形 (
gl.enable(gl.CULL_FACE))。 - 插值 (Interpolation): 通过平滑混合图元顶点的值,计算图元内部每个像素(“片段”)的
varying变量值。
6. 片段着色器 (GPU - 可编程)
Section titled “6. 片段着色器 (GPU - 可编程)”- 接收来自顶点着色器的插值
varying值。 - 接收 Uniform。
- 执行纹理采样 (
texture2D)、每像素光照计算、雾效等操作。 - 必须 将片段的最终 RGBA 颜色输出到内置变量
gl_FragColor(在 WebGL 1 中)。
7. 每片段操作 (GPU - 固定功能)
Section titled “7. 每片段操作 (GPU - 固定功能)”- 像素所有权测试 (Pixel Ownership Test): (内部)确定像素是否属于 WebGL 上下文。
- 裁剪测试 (Scissor Test): 丢弃定义矩形之外的片段 (
gl.scissor)。 - 模板测试 (Stencil Test): 比较/修改模板缓冲区中的值 (
gl.stencilFunc,gl.stencilOp)。 - 深度测试 (Depth Test): 将片段的深度与深度缓冲区进行比较 (
gl.depthFunc)。丢弃被遮挡的片段。 - 混合 (Blending): 将片段的颜色与颜色缓冲区组合 (
gl.blendFunc)。 - 抖动 (Dithering): (可选)模拟更多颜色。
如果一个片段通过了所有启用的测试,其颜色、深度和模板值就会被写入到 Framebuffer 中相应的缓冲区。
8. Framebuffer (GPU 内存)
Section titled “8. Framebuffer (GPU 内存)”最终存储渲染图像(颜色缓冲区)以及相关深度/模板信息的目的地。默认情况下,这是与 HTML Canvas 元素关联的缓冲区,随后由浏览器显示。
- CPU 的作用: 设置、数据准备、状态管理、启动绘制。
- GPU 的作用: 大规模并行执行顶点/片段着色器、固定功能几何处理和测试。
- 可编程阶段: 顶点着色器和片段着色器赋予开发者控制权。
- 数据流: 数据从 JS -> 缓冲区 -> 顶点着色器 -> 光栅化器 -> 片段着色器 -> Framebuffer。
- 性能: 最大限度减少 CPU-GPU 通信(使用缓冲区),优化着色器,高效利用固定功能测试(如深度测试)。