渲染管线
Rendering Pipeline
渲染管线是实时图形的核心:给定虚拟相机、三维物体、光源等,把场景转换成一张二维图像。RTR4 把它粗分为四个功能阶段:应用、几何处理、光栅化、像素处理,各阶段并行执行,整体速度由最慢的阶段决定。
为什么用"管线"
把一个任务拆成 n 个阶段并行执行,理想情况下可以提速 n 倍。但每个阶段都依赖上一阶段的结果,最慢的那个阶段就是瓶颈 (bottleneck),它决定了整条管线的吞吐量;等待瓶颈的下游阶段处于饥饿 (starved) 状态。书里用做三明治举例:每人 20 秒时每分钟能做 3 个,其中一步变成 30 秒,就只能做 2 个。
游戏开发启示:性能优化首先要找到瓶颈在哪个阶段,优化非瓶颈阶段几乎没有收益(详见 RTR4 第 18 章)。
功能阶段 vs 实现
书中讲的是功能阶段:只规定要完成什么任务,不规定怎么实现。真实硬件可能把两个功能阶段合成一个单元,也可能把一个耗时阶段拆到多个硬件单元上。
四个阶段
| 阶段 | 通常运行在 | 主要工作 |
|---|---|---|
| 应用 (Application) | CPU(多核并行) | 输入处理、碰撞检测、动画、物理、剔除等加速算法;最终把要渲染的图元(点、线、三角形)交给几何阶段 |
| 几何处理 (Geometry Processing) | GPU | 顶点着色、投影、裁剪、屏幕映射,决定画什么、怎么画、画在哪 |
| 光栅化 (Rasterization) | GPU(固定功能) | 找出每个三角形覆盖了哪些像素 |
| 像素处理 (Pixel Processing) | GPU | 逐像素运行程序算颜色,做深度测试、混合 |
下图是四个阶段的顺序,以及几何处理阶段内部的子阶段。虚线框里的是可选阶段,可以不用。
flowchart LR
A["应用<br/>CPU"] --> G["几何处理<br/>GPU"] --> R["光栅化<br/>GPU"] --> P["像素处理<br/>GPU"]
subgraph G2["几何处理内部"]
direction LR
VS["顶点着色"] --> OPT["可选:曲面细分 / 几何着色器 / 流输出"] --> CL["裁剪"] --> SM["屏幕映射"]
end
G -.-> G2
style OPT stroke-dasharray: 5 5应用阶段
- 开发者完全掌控,可以随意修改实现来提升性能,而且会影响后续阶段,比如在这里减少要渲染的三角形数量。
- 部分工作也可以用计算着色器 (compute shader) 放到 GPU 上,把 GPU 当作高度并行的通用处理器。
- 它是软件实现,所以不像其他阶段那样分子阶段,但常在多个 CPU 核心上并行。
几何处理阶段
依次包括:
- 顶点着色 (Vertex Shading):算出顶点位置(必须),以及法线、纹理坐标等输出数据。名字来自过去逐顶点计算光照再插值颜色的做法;现在顶点着色器更像"准备顶点数据"的通用单元,也可以做骨骼动画等。坐标变换细节见 坐标空间。
- 可选阶段(按顺序,均可不用):
- 曲面细分 (Tessellation):由 hull shader、tessellator、domain shader 组成,按相机距离生成合适数量的三角形,近处多、远处少,解决"近看有棱角、远看浪费"的问题。
- 几何着色器 (Geometry Shader):比曲面细分出现得早、能力更有限,常用于粒子,比如把一个点扩展成面向相机的四边形。
- 流输出 (Stream Output):把处理后的顶点输出到数组,供 CPU 或 GPU 之后再用,常用于粒子模拟。
- 裁剪 (Clipping):完全在视景体内的图元保留,完全在外的丢弃,部分在内的被裁剪并生成新顶点。之后做透视除法得到 NDC。
- 屏幕映射 (Screen Mapping):把 NDC 的 x、y 平移加缩放到窗口坐标。
光栅化与像素处理
固定功能与可编程
多年来开发者只能使用图形 API 定义的固定功能管线,最后一台主要的固定功能机器是 2006 年的任天堂 Wii。现代 GPU 可编程,可以决定各子阶段具体做什么。这条管线也不是唯一的渲染方式:电影离线渲染曾多用微多边形管线,如今多被光线追踪和路径追踪取代。
取舍与常见坑
- 能在应用阶段解决的(剔除、LOD)尽量提前做,减少进入 GPU 的工作量。
- 几何着色器和流输出等可选阶段并非所有 GPU 都支持,RTR4 也指出它们通常不常用。
GEA 的视角:从算法到管线(卷 II 11.3.1.4–11.3.1.5、11.4.1–11.4.3、11.4.6.1)
六个算法步骤
GEA 先列出光栅化渲染必须完成的算法步骤,再说明真实管线怎样对应它们(卷 II 11.4.1):
| 步骤 | 处理单位 | 内容 |
|---|---|---|
| 变换 (Transformation) | 顶点 | 把顶点变到观察空间 |
| 投影 (Projection) | 顶点 | 投到二维屏幕空间 |
| 光栅化 (Rasterization) | 三角形 | 找出覆盖的像素,把三角形拆成片元,每个片元只被一个像素"看到" |
| 着色 (Shading) | 片元 | 插值顶点颜色,或逐片元计算光照 |
| 片元测试 (Fragment testing) | 片元 | 可选的深度测试和模板测试,失败即丢弃 |
| 合并与混合 (Merging and blending) | 片元-像素对 | 颜色写入颜色平面、深度写入深度平面,可选与已有颜色混合 |
书中强调真实管线会合并、拆分或增加阶段,甚至调整顺序、引入反馈回路,但所有光栅化引擎都要大致按这个顺序完成这些步骤。
为什么是管线:数据独立
- 每一步一次只处理一个数据元素,而且不允许跨元素读写:变换顶点时不能看别的顶点,光栅化一个三角形时不能读别的三角形,片元着色、测试、合并也不能读写其他片元或无关像素(几何着色器能拿到相邻三角形的顶点,是唯一例外)。
- 数据独立意味着没有数据竞争,于是可以用两种方式并行:各阶段在时间上重叠执行;同一阶段的硬件在芯片上复制多份,同时处理多个元素(卷 II 11.4.2)。
- GEA 给出的量级:每个 GPU 计算核心是 32 或 64 通道宽的 SIMD,一块 GPU 通常有 50 个以上这样的核心;50 个 32 通道核心满负荷时可同时处理 1,600 个数据元素。访存停顿时 GPU 切换到另一个 wavefront/warp,详见 GPU 并行架构。
逻辑管线与物理管线
- 逻辑管线是图形 API(OpenGL、DirectX、Vulkan、Metal)定义的编程范式,是实现者与使用者之间的契约:有哪些阶段、怎样连接、每个阶段能做什么。
- 物理管线是某个具体实现,通常由 CPU 上的软件、驱动层的 GPU 专用软件、GPU 上的固定功能硬件和着色器共同组成。两者的阶段不一定一一对应,例如逻辑上分开的顶点着色器和像素着色器都跑在同一种通用 SIMD 核心上。
- 多数 API 还提供纯软件的参考实现,作为检验 GPU 实现正确性的"标准答案",不追求性能(卷 II 11.4.3)。这与本页「功能阶段 vs 实现」的区分是同一个意思。
传统光栅管线的九个阶段
GEA 把 DirectX 风格的传统管线列为九个阶段(卷 II 11.4.6.1):输入装配、顶点着色器、外壳着色器、细分器、域着色器、几何着色器、流输出、光栅化器、像素着色器,最后由输出合并器写入帧缓冲。下图按这个顺序画出,虚线框为可选阶段。
flowchart LR
IA["输入装配"] --> VS["顶点着色器"] --> HS["外壳着色器"]:::opt --> TS["细分器 固定功能"]:::opt --> DS["域着色器"]:::opt --> GS["几何着色器"]:::opt --> SO["流输出"]:::opt --> RS["光栅化器 固定功能"] --> PS["像素着色器"] --> OM["输出合并器"]
classDef opt stroke-dasharray: 5 5- 应用通过 draw call 提交几何(OpenGL 的
glDrawArrays/glDrawElements,D3D11 的Draw/DrawIndexed,Vulkan 的vkCmdDraw/vkCmdDrawIndexed),输入是一个或多个顶点缓冲,可带索引缓冲。 - 图元类型主要有点列表、线列表、三角形列表,以及带索引的变体和三角形带;可附带邻接信息(三角形多带三个相邻顶点、线段多带两个),只有几何着色器能看到。
- 输入装配器读取顶点和索引缓冲,把不同格式(索引列表、非索引列表、三角形带)统一装配成图元,还能把多个顶点缓冲里的属性交错拼成一个"结构体"交给着色器。
- DirectX 功能规范并不把光栅化器当作一个"阶段",而是看作阶段之间的接口;它负责裁剪、透视除法、视口变换、三角形遍历、属性插值和裁剪矩形测试,也可以整个禁用,把管线变成只经流输出写内存的数据处理管线。
- 各阶段细节见 顶点着色器、曲面细分与几何着色器、像素着色器、合并阶段与帧缓冲。
与 RTR4 的分歧:应用"阶段"还是应用"层"
- RTR4 把应用阶段算作管线的第一个阶段(本页「四个阶段」)。
- GEA 指出 OpenGL、DirectX 等 API 把应用视为管线的外部客户端,所以书中只说应用层 (application layer),不加"阶段"二字;图形管线指应用之下、由 API 定义的那部分(卷 II 11.3.1.4)。
- 两种说法描述的是同一套结构,只是边界划在哪里不同。GEA 还指出这条边界一直在往上移:早期整条管线都是 CPU 软件,Voodoo 把最贵的后段搬进硬件,GPU 又接管了更多工作;如今有的引擎把应用层也用计算着色器搬到 GPU 上,加上网格着色器,管线越来越像随机访问,等于重新走向保留模式(卷 II 11.3.1.5)。应用层本身见 图形栈与渲染引擎架构。
延伸阅读
- Blinn《A Trip Down the Graphics Pipeline》:从零写软件渲染器,讲裁剪和透视插值的细节
- 《OpenGL Programming Guide》(红宝书)
出处
- realtime_rendering_4ed.pdf 第 2 章 The Graphics Rendering Pipeline
- Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 11 章 11.3.1.4–11.3.1.5、11.4.1–11.4.3、11.4.6.1 节