现代渲染管线架构

在现代 GPU 架构下,渲染管线的演进本质上是 “权衡顶点处理(Draw Call / 几何提交)、片元算力(ALU)与显存带宽(Bandwidth)三者关系” 的历史。


1. 前向渲染 (Forward Rendering)

最符合直觉的”逐物体计算”架构,是所有管线的基准。

运行机制:

1
遍历场景物体 → 针对每个物体遍历受影响光源 → 片元着色器计算材质与光照 → 输出到 Framebuffer
  • 性能复杂度: 为物体数, 为光源数)。多光源场景通常需要 Multi-pass 叠加,导致 Draw Call 数量暴增。

优势:

  • 材质极度灵活: 每个物体独立着色,不受统一数据结构约束,可实现任意 Shading Model(各向异性、次表面散射、卡通渲染等)。
  • 原生硬件 MSAA: 片元着色器独立运行,兼容光栅化阶段的多重采样。
  • 天然支持半透明: 不需要额外的 Forward Pass,按深度排序后直接 Alpha Blend。
  • 低显存占用: 无需 G-Buffer,适合移动端和低显存平台(如 Quest、Switch)。

劣势:

  • 严重的光照 Overdraw: 被遮挡像素仍会执行完整的光照计算(无 Early-Z 优化时尤为严重)。
  • 多光源扩展性极差: 10 个动态光源 × 1000 个物体 = 10000 次着色调用。
  • Shader 变体爆炸: 不同光源数量组合需要预编译大量 Shader Variant(Unity URP 的 _ADDITIONAL_LIGHTS keyword 即为此设计)。

工程实践补充(Unity URP):

  • URP 默认使用 Forward Rendering,每个物体最多支持 8 盏 Additional Lights(可通过 AdditionalLightCountPerObject 调整)。
  • Depth Priming 功能本质是在 Forward 管线中插入一个 Depth Pre-pass,以剔除被遮挡像素的 ALU 浪费。
  • 在大世界场景中,Forward 通常与 GPU Instancing + DrawMeshInstancedIndirect 结合,将 Draw Call 压力转移到 GPU 端。

2. 延迟渲染 (Deferred Shading)

核心思想:空间换时间 —— 用 G-Buffer 显存换取光照计算与几何复杂度的解耦。

为了解决 Forward 中海量光源带来的 Overdraw 和复杂度问题,是现代 3A 引擎的基石。

运行机制:

1
Geometry Pass(写 G-Buffer)→ Lighting Pass(读 G-Buffer,计算光照)→ 输出到 Framebuffer
  1. Geometry Pass: 渲染所有不透明物体,将 PBR 材质属性写入多渲染目标(MRT)构成的 G-Buffer

    Buffer 典型内容 精度
    RT0 Albedo (RGB) + AO (A) RGBA8
    RT1 World/View Normal (RGB) + Roughness (A) RGBA16F 或 RGBA8
    RT2 Metallic + Specular + ShadingModel ID RGBA8
    Depth 硬件深度缓冲 D24S8 或 D32
  2. Lighting Pass: 在屏幕空间绘制光源几何体(Quad / 球体 / 锥体),采样 G-Buffer 计算光照并累加到 Accumulation Buffer。

  • 性能复杂度: 为光源在屏幕上的像素覆盖面积),大幅优于 Forward 的

优势:

  • 零光照 Overdraw: Geometry Pass 结束后只有最终可见像素参与光照计算。
  • 海量动态光源: 光源计算与场景几何复杂度彻底解耦,理论上可支持数千盏光源。
  • 后处理友好: 所有 G-Buffer 数据天然可用于 SSAO、SSR、SSGI 等屏幕空间后处理效果。

劣势:

  • 显存与带宽黑洞: G-Buffer 的 MRT 读写极度消耗显存带宽(在 1080P 下,一帧完整的 G-Buffer 读写可高达数 GB/s)。在带宽受限的移动端 GPU(如 Mali、Adreno)上,这是致命问题,需结合 TBDR(Tile-Based Deferred Rendering)架构缓解。
  • 材质同质化: 所有材质必须被编码进统一的 G-Buffer 结构,实现各向异性毛发、次表面散射等特殊 Shading Model 时,需要额外的 RT 或精心设计的编码方案(如用 ShadingModelID 区分 Shading Path)。
  • 抗锯齿局限: G-Buffer 存储的是已插值的像素属性,无法使用硬件 MSAA(因为 MSAA 需要在着色前就完成多采样)。现代 Deferred 管线重度依赖 TAA 进行时间域反走样,但 TAA 会引入 Ghosting 和模糊问题。
  • 半透明处理: Deferred 管线无法直接处理半透明物体,必须额外维护一个 Forward Pass(Deferred + Forward 混合管线)。

工程实践补充:

  • Unreal Engine 的 Substrate 材质系统(UE 5.3+)是对传统 Deferred G-Buffer 材质同质化问题的系统性解答,通过可组合的材质层取代固定 G-Buffer 编码。
  • Unity URP 目前的 Deferred Rendering Path 默认仅启用 4 个 RT(比 Built-in 的 Deferred 更保守),以控制带宽开销。

3. 延迟光照 (Light Pre-Pass / Deferred Lighting)

历史定位:折中方案 —— 诞生于早期主机时代,旨在解决 Deferred Shading 带宽受限的问题。

运行机制:

1
Geometry Pass 1(薄 G-Buffer)→ Lighting Pass(输出光照缓冲区)→ Forward Pass 2(几何体 × 光照缓冲)
  1. Geometry Pass 1: 渲染几何体,输出极”薄”的 G-Buffer(仅 Depth + Normal,带宽需求极低)。
  2. Lighting Pass: 遍历光源,利用 Depth 和 Normal 计算漫反射 + 高光信息,写入光照累加缓冲区(Light Accumulation Buffer)
  3. Forward Pass: 再次渲染几何体,在片元着色器中读取自身材质(Albedo、Roughness 等)并采样光照缓冲区进行相乘融合,最终输出。

优势(对比 Deferred Shading):

  • G-Buffer 极小(仅 2 个 RT),大幅降低带宽压力。
  • 第二个 Forward Pass 中材质完全自由,恢复了任意 Shading Model 的支持。
  • 支持硬件 MSAA(第二个 Pass 是标准 Forward 渲染)。

劣势(致命伤):双倍几何提交

所有不透明物体需提交两次(两个完整的顶点变换 + 光栅化流程)。在现代高多边形场景(数千万三角形)和高 Draw Call 场景下,顶点着色器压力和 CPU 提交开销远超带宽节省的收益。

Light Pre-Pass 的衰落时间线:

  • Xbox 360 时代(2005-2010):带宽极度受限,此方案是主流。
  • PS4/Xbox One 时代(2013+):GPU 带宽大幅提升,加之 Compute Shader 普及,Deferred Shading 和 Forward+ 逐渐取而代之。
  • 目前此架构基本退出主流引擎,主要作为历史参考存在。

4. 分块与聚类渲染 (Tiled & Clustered Rendering)

核心思想:算力换效率 —— 将光源剔除逻辑从传统的 CPU/光源几何体提交转移到 GPU Compute Shader,通过空间数据结构实现精确的每像素/每体素光源列表。

这一层技术是正交于前三种架构的优化层,可以叠加在 Forward 或 Deferred 之上,形成 Forward+Tiled DeferredClustered ForwardClustered Deferred 等组合。

4.1 前向+ (Forward+ / Tiled Forward)

运行机制:

1
Depth Pre-pass → Light Culling (Compute, 2D Tile) → Forward Shading Pass(查 Tile 光源列表)
  1. Depth Pre-pass: 预渲染场景,输出深度图(用于 Tile 的深度范围计算)。
  2. Light Culling (Compute): 将屏幕划分为均匀的 2D 网格(Tiles,通常 8×8 或 16×16 像素)。每个 Tile 由一组 GPU 线程处理,利用深度图计算该 Tile 的 Min/Max Depth,然后对每盏灯进行视锥体 vs AABB 相交测试,生成该 Tile 的局部光源索引列表,写入 Light Index Buffer
  3. Forward Pass: 渲染几何体,片元着色器根据当前像素所在的 Tile 坐标查表,仅对该 Tile 的有效光源计算光照。

痛点:深度不连续(Depth Discontinuity)

Tile 在 Z 轴方向是一个从近裁面到远裁面的完整视锥体切片(长条形体积)。当同一个 Tile 内同时存在近处前景物体(如人物,depth ≈ 1m)和远处背景物体(如山脉,depth ≈ 500m)时,该 Tile 的 Min/Max Depth 跨度极大,导致大量远处光源被错误地分配给近处片元(反之亦然),光源列表虚假膨胀,ALU 浪费严重。

这是 Forward+ 在室内/外混合场景和包含大量深度变化场景中性能下降的根本原因。

4.2 聚类渲染 (Clustered Rendering)

Forward+ 的终极进化形态,彻底解决深度不连续问题。由 Ola Olsson 等人于 2012 年在 SIGGRAPH 上正式提出。

运行机制:

1
Cluster 构建(视锥体 3D 体素化)→ Light Assignment (Compute, 3D AABB 测试) → Shading Pass(查 Cluster 光源列表)
  1. 3D 视锥体体素化(Cluster 构建):

    • X/Y 轴:与 Tiled 相同,按屏幕像素网格划分。
    • Z 轴(深度方向):按对数级(Exponential/Logarithmic)切片,使近裁面附近切片密集(精确),远处切片稀疏(高效)。典型划分为 16~32 层,最终形成数以千计(如 16×9×24 = 3456 个)的 3D Cluster。
    • Cluster 无需每帧重建(视锥体不变时可复用),只需在相机参数变化时重新生成。
  2. 光源分配(Light Assignment, Compute):

    • 对每个 Cluster 执行与每盏光源的 3D 空间相交测试(球体 vs AABB)。
    • 将相交结果写入紧凑的 Light Index ListCluster 查找表(Offset + Count)
  3. 着色:

    • 片元着色器根据当前片元的 View Space 坐标,解析其所属 Cluster(直接从 NDC/View 坐标计算,无需额外纹理采样)。
    • 从查找表获取该 Cluster 的光源列表,仅对列表内光源计算光照。

优势:

  • 极致的 ALU 优化: 每个片元只看与其所在 3D 体素相交的光源,Z 轴上的光照冗余被完全消除。

  • 天然支持 Raymarching 体积渲染: 这是 Clustered Rendering 最重要的”隐性优势”之一——

    在体积云(Volumetric Clouds)和体积雾的 Raymarch 步进中,采样点是 3D 空间中的任意位置,并不依附于任何几何表面,没有表面深度信息可用。传统 Forward/Tiled Forward 管线中,光源列表是以屏幕 Tile 为索引的,无法在 Raymarch 步进点处直接查询。而 Clustered 管线的光源数据结构本身就是 3D 视锥体空间的,Raymarch 步进点的 View Space 坐标可以直接解析出对应的 Cluster,从而获得精确的局部光源列表,与表面渲染复用同一套光照查询逻辑。

  • 统一半透明/不透明管线: 半透明物体无需特殊处理,与不透明物体使用同一套 3D 空间查表逻辑,天然避免了 Deferred 管线中半透明的尴尬。

  • Compute 友好: Cluster 构建和光源分配完全在 GPU Compute Shader 中完成,与主渲染管线并行,CPU 侧压力极小。

劣势:

  • Cluster 缓冲区显存开销: 需要维护 Cluster 查找表 + Light Index List,通常占用数 MB 显存(可接受)。
  • Cluster 构建与光源分配的 Compute 开销: 在光源数量极多(数万盏)或 Cluster 划分极细时,Compute Pass 本身也会成为瓶颈。
  • 着色器内的 Cluster 解析逻辑: 需要在 Shader 中内联 Cluster 坐标计算,对 Shader 代码有侵入性。

工程实践补充(Unity URP):

  • Unity URP 在 Forward+ Rendering Path(Unity 2022 LTS+)中实装了 Clustered Light Culling,使用 Compute Shader 构建 3D Cluster,支持最多 256 盏 Additional Lights。
  • 对于 GPU Driven Terrain + DrawMeshInstancedIndirect 的场景,Clustered 管线的优势尤为显著:地形像素通常深度跨度极大(山谷近地表 vs 远处天际),Clustered 的 Z 轴对数切片能精确控制每个地形区块接收的光源数量。

5. 架构对比矩阵

架构特性 Forward Deferred Shading Deferred Lighting Forward+ (Tiled) Clustered
光照复杂度
光源支持数量 极少(< 8) 海量(数百) 大量(数十) 大量(数百) 海量(数百~千)
带宽 / 显存消耗 极高(G-Buffer MRT) 中低(薄 G-Buffer) 中等 中偏高(Cluster Buffer)
几何提交次数 1 次 1 次 2 次(致命伤) 2 次(含 Depth Pre-pass) 1~2 次
材质自由度 极高 受限(G-Buffer 编码) 高(第二 Pass 自由) 极高 取决于底层管线
硬件 MSAA ✅ 原生支持 ❌ 不支持 ✅ 支持 ✅ 支持 ✅ 支持(Forward 底层)
半透明处理 ✅ 原生 ⚠️ 需额外 Forward Pass ✅ 第二 Pass 处理 ✅ 原生 ✅ 统一管线
体积渲染契合度 一般(需 Depth 绑定) 一般 一般(Tile 深度不连续) 极佳(纯 3D 空间数据)
移动端适配 最佳 差(带宽瓶颈) 较好 一般(需 Compute 支持) 一般
代表引擎/游戏 Unity URP Mobile Unreal Engine 4/5 Xbox 360 时代主机引擎 Unity URP Forward+ Doom (2016)、Frostbite

6. 选型决策树

1
2
3
4
5
6
7
8
9
10
11
12
场景光源数量 ≤ 8?
├── 是 → 移动端/低端平台?
│ ├── 是 → Forward Rendering(带宽最优)
│ └── 否 → Forward Rendering 或 Forward+(视画质需求)
└── 否 → 需要特殊材质(毛发/SSS/卡通渲染)?
├── 是 → Forward+ 或 Clustered Forward
└── 否 → 带宽受限(移动端/主机)?
├── 是 → 考虑 Tiled Deferred 或精简 G-Buffer 的 Deferred
└── 否 → Deferred Shading 或 Clustered Deferred

需要体积渲染/Raymarching?
└── 是 → Clustered(任意管线底层均可)

7. 补充

7.1 Visibility Buffer

(Deferred Materials / Triangle Visibility Buffer)

近年来兴起的新型管线思路,可视为对 Deferred Shading 的再进化,在 Nanite(Unreal Engine 5)中达到工业级实现。

  • 核心思想: Geometry Pass 中不存储材质属性,只存储 三角形 ID + 重心坐标(Barycentric Coordinates)(即”谁覆盖了这个像素”的信息,而非”这个像素长什么样”)。Material Pass 中通过三角形 ID 重新索引顶点数据,在屏幕空间按需计算各种材质属性。
  • 优势: G-Buffer 极薄(仅两个通道),带宽极低;材质完全灵活(延迟到 Material Pass 才采样纹理);天然兼容 Virtual Geometry(Nanite)。
  • 劣势: 实现极度复杂,Shader 代码需要手动执行插值计算(通常需要 Compute Shader + 手写 Barycentric 插值),工程门槛极高。

7.2 TBDR

Tile-Based Deferred Rendering

注意区分”Clustered Deferred”与移动端 GPU 的”TBDR” 架构:

  • 移动端 TBDR 是 GPU 硬件架构层面的特性(PowerVR、Mali、Apple GPU),将屏幕划分为小 Tile(如 16×16 像素),在 On-Chip Cache 中完成 Tile 内的完整渲染(包括深度测试、混合),最后才将结果写回显存,从而极大减少显存带宽压力。
  • 软件层面的 Clustered Deferred 和 Tiled Forward 是渲染算法,与 TBDR 硬件架构是两个正交的概念,可以在 TBDR GPU 上运行,也可以在 IMR(Immediate Mode Rendering,如 PC 的 NVIDIA/AMD GPU)上运行。
  • 在移动端开发中,设计良好的 Forward 管线 + TBDR 硬件加速,通常比 Deferred 管线 + 额外带宽开销更高效。

📚 参考文献与延伸阅读