深入解析 Forward+ 渲染(Forward Plus / Tiled Forward Shading)
随着现代实时渲染引擎中场景光源数量从几十个激增至成千上万个,传统正向渲染(Forward Rendering)和延迟渲染(Deferred Shading)的局限性逐渐显现。Forward+ Shading(又称 Tiled Forward Shading)由 AMD 工程师 Takahiro Harada 等人提出,它结合了 Tile-Based 光照裁剪 与 正向渲染管线 的双重优势,在支持海量动态光源的同时,保留了材质多样性与硬件抗锯齿(MSAA)等重要特性。
本文将从 Tiled Deferred 演进脉络、Forward+ 管线架构、Compute Shader 光照裁剪、性能对比 到 工程挑战与现代演进 进行深度解构。
一、 演进脉络:从 Tiled-based Deferred 到 Forward+
在探讨 Forward+ 之前,有必要回顾 Intel 在 SIGGRAPH Courses 2010 中提出的 Tiled-based Deferred Shading 算法。
1. Tiled-based Deferred Shading 回顾
传统延迟渲染(Deferred Shading)需要为每个光源绘制一个几何体代理(Light Volume Proxy Mesh,如球体或锥体)来决定受光覆盖的屏幕区域。而 Intel 提出的 Tiled-based 方法将其优化为一个单 Pass 的 Compute Shader 裁剪过程:
- 生成 G-Buffer:与传统 Deferred Shading 一样,首先渲染场景几何体,生成存储位置、法线、材质等属性的 G-Buffer 附件。
- 屏幕 Tile 划分:将 G-Buffer 划分为许多小块(如 \(16 imes 16\) 像素的 Tile),并根据 Depth Buffer 得到每个 Tile 内像素的最大/最小深度值(Min/Max Depth),从而构建出该 Tile 的视锥体包围盒(Tile Bounding Frustum)。
- Tile 级光源裁剪(Light Culling):对每个 Tile,将其包围盒与场景中的光源进行求交测试,筛选出对当前 Tile 产生光照贡献的光源列表(Light Index List)。
- 像素级 Shading 累加:对 G-Buffer 中的每个像素,直接读取所在 Tile 的光源列表,累加计算光照。
优点:彻底摆脱了为每个光源提交几何体代理(Light Volumes)的绘制开销(Draw Call),在单个 Compute Shader Pass 中即可高效完成上千光源的求交与光照累加。如果结合 OIT(顺序无关半透明)链表技术,还能进一步优化光照索引存储。
2. Forward+ 的范式转换
有了 Tiled-based Deferred Shading 的基础,理解 Forward+ 的思想就变得十分顺理成章。Forward+ 与 Tiled-based Deferred 的关系,正如传统 Forward Shading 与 Deferred Shading 的关系:
核心变动:Forward+ 丢弃了体积庞大、极耗显存带宽的 G-Buffer,将最后的光照累加过程重新放回标准的正向着色器(Forward Fragment Shader)中执行。
二、 Forward+ 渲染管线三阶段
Forward+ 的标准管线主要包含以下三个核心步骤:
1 | +------------------+ +-------------------------------+ +------------------+ |
1. 第一阶段:深度预 Pass (Z-Prepass)
在许多传统 Forward Shading 中,Z-Prepass 常被作为优化手段(提前剔除不可见片元)。而在 Forward+ 中,Z-Prepass 变成了必不可少的关键步骤: * 核心作用:它填充了深度缓冲区(Depth Buffer/Z-Buffer),提供每个像素的精确深度数据。只有有了完整的 Z-Buffer,第二阶段的 Compute Shader 才能提取出每个 Tile 的 Min/Max 深度边界。
2. 第二阶段:Tile 划分与光源裁剪 (Light Culling)
该阶段完全在 Compute Shader 中并行执行: 1. 网格切割:将 Z-Buffer 划分为 \(16 imes 16\) 像素网格(Tile)。 2. 深度极值归并:计算该 Tile 内部所有像素的最大深度 \(Z_{ ext{max}}\) 和最小深度 \(Z_{ ext{min}}\)。 3. 创建视锥包围体:利用屏幕 Tile 坐标与 \([Z_{ ext{min}}, Z_{ ext{max}}]\) 构建出视锥裁剪体(Tile Frustum AABB)。 4. 求交测试:将场景中的点光源/聚光灯包围球与该 Tile 视锥体求交。 5. 索引写出:将与当前 Tile 相交的光源索引写入全局显存缓冲区(SSBO / StructuredBuffer)中,形成按 Tile 索引的光源列表。
3. 第三阶段:正向着色阶段 (Forward Shading Pass)
在标准正向绘制 Pass 中: * 逐个绘制场景物体的几何体。 * 片元着色器(Fragment Shader)利用当前像素的屏幕坐标算出其所属的 Tile ID。 * 从 SSBO 中读取该 Tile 对应的光源索引列表,循环累加所有有效光源的光照贡献。
三、 技术特性对比:Forward+ vs Deferred vs Traditional Forward
Forward+ 兼顾了正向渲染的材质灵活性与延迟渲染的多光源扩展性:
| 评估维度 | 传统正向 (Forward) | 延迟渲染 (Deferred) | Forward+ (Tiled Forward) |
|---|---|---|---|
| 显存带宽 | 极低 | 极高 (至少需 32bit Color + 32bit Depth G-Buffer) | 较低 (仅需 Depth Prepass 与帧缓冲) |
| 多光源扩展 | 极差 (受限于着色器变体与多 Pass) | 强 (光照解耦) | 极强 (凭借 Compute Shader Cache 索引) |
| 半透明渲染 | 原生完美支持 | 无法原生支持 (需正向 Pass 补漏) | 原生/扩展支持 (可结合深度范围优化) |
| 硬件 MSAA | 原生完美支持 | 无法原生使用 (耗显存/依赖后处理) | 原生完美支持 |
| 复杂材质支持 | 极其灵活 (Shader 可自由编写) | 受限 (须将材质参数编码入 G-Buffer) | 极其灵活 (支持复杂 BRDF 与动态分支) |
带宽效率提升:Forward+ 无需频繁读写体积庞大的 G-Buffer,因此在显存带宽受限的硬件(如移动端 GPU 及中低端 PC 显卡)上,Forward+ 的实际渲染速度往往能超越传统 Deferred Shading。
四、 核心代码实现
1. Compute Shader 光照裁剪示例 (GLSL)
1 |
|
2. Forward 片元着色器光照计算示例 (GLSL)
1 |
|
五、 工程注意事项与进阶优化策略
在实际引擎落地开发中, Forward+ 还需要针对特定渲染特效与空间划分进行针对性设计:
1. 透明物体的渲染策略 (Transparency Handling)
由于透明物体不写入深度预 Pass(Z-prepass),常规根据不透明物体 Z-Buffer 计算出来的 Tile Min/Max Depth 会产生偏窄的深度区间。如果透明物体位于不透明物体的前方,其所在位置的光源可能在 Compute Shader 阶段被误剔除。
主流解决方案: * 双 Z-Buffer 法 (Dual Z-Buffer):在第一步生成 Z-prepass 时维护两个 Z-Buffer,一个记录不透明物体的深度 Z,另一个记录透明物体的最近深度 Z。在第二步计算 Tile 包围盒时,将两者的深度范围合并为一个总的 Bounding Box,后续光照累加步骤保持不变即可原生兼容透明物体。 * 多光源列表分级 (Separate Light Lists):为不透明物体与半透明物体分别维护两份 Light List。透明物体的 Min Depth 直接强制拉近至相机近裁剪面 \(Z_{ ext{near}}\),从而确保前方光源不遗漏。
2. 屏幕空间特效 (Screen-Space Effects) 的融合
在延迟渲染中,由于 G-Buffer 原生存有世界空间法线与位置,SSAO、SSR(屏幕空间反射)、GI(全局光照)等特效可以无缝调用。
而在 Forward+ 中: * 深度重建位置/法线:可以直接通过深度图(Depth Buffer)实时重构视空间位置,并通过深度梯度求偏导反算法线(或增加一个轻量级的 Depth-Normal Prepass)。 * 直接应用:有了完整深度图后,SSAO、SSVO、SSR 等屏幕空间效果均可以顺畅集成到 Forward+ 管线中。
3. 现代架构演进:Clustered Forward+ (集群前向渲染)
虽然 Forward+ 在 2D Tile 层面大大减少了光源遍历,但它依然面临 2D 深度跨度过大(Depth Range Problem) 的缺陷: 例如在漫长走廊视角下,一个 \(16 imes 16\) 的 Tile 内部可能同时包含距离相机 1 米的视锥近端墙壁与距离相机 100 米的远端背景,导致该 Tile 的 \([Z_{ ext{min}}, Z_{ ext{max}}]\) 极其庞大。这会使得很多处于中间空旷区域、实际上并不影响任何像素的光源被误判为“相交”,降低了剔除效率。
1 | +-----------------------------------------------------------------+ |
Clustered Forward+ 在 Forward+ 的基础上,不仅在屏幕 2D 方向切割 Tile,还在 Z 轴深度方向进行对数/指数切片,将视锥体划分为 3D 栅格体素(Clusters)。Compute Shader 将光源裁剪直接与 3D Cluster 求交,彻底消除了深度跨度造成的误判,是目前现代主流引擎(如 UE5 Forward Shading、DOOM Eternal 等)的最佳实时光照方案之一。
六、 总结
Forward+ 渲染通过引入 Compute Shader 的 Tile 光照裁剪机制,成功解耦了前向渲染中光源数量与几何体数量的强绑定关系: * 它避免了传统 Deferred Shading 的高显存带宽与 G-Buffer 限制,使得多光源渲染管线拥有更高的执行效率; * 保留了对半透明物体、复杂材质与硬件 MSAA 的完美支持; * 为后续演进至 Clustered Forward+ 奠定了重要的工程框架基础。