Unity URP 四种渲染路径
Unity URP 四种渲染路径:Forward、Forward+、Deferred 与 Deferred+
Forward、Forward+、Deferred、Deferred+ 不是四套彼此独立的 Scriptable Render Pipeline(SRP),而是 URP 的 Universal Renderer 如何组织绘制与光照的不同路径。理解它们最有效的方式,是拆成两个维度:
- 何时计算光照:绘制几何时直接算(Forward),还是先写 GBuffer、再集中算(Deferred)。
- 如何筛选灯光:使用传统的每物体列表或光源体积,还是使用 Clustered Light Culling(带
+)。
| 传统灯光筛选 | Clustered 灯光筛选 | |
|---|---|---|
| 绘制表面时计算光照 | Forward:每物体灯列表 | Forward+:Cluster 灯列表 |
| GBuffer 后计算光照 | Deferred:Stencil Light Volume | Deferred+:Cluster 灯列表 |
因此,+ 不等于画质升级。它首先表示灯光数据的组织与筛选方式发生了变化;同一材质与灯光配置是否产生完全一致的结果,还会受功能支持、Shader 变体、精度和版本影响。
先确认版本边界
本文把四者作为“新版本 URP / Unity Graphics 当前开发分支中可以形成的四种组合”来对照,不代表所有 Unity 6 或 URP 版本的 Renderer Inspector 都稳定提供四个选项。
Unity 6.0(6000.0)的官方路径比较表只列出 Forward、Forward+、Deferred。与此同时,Unity Graphics 当前 master 的 UniversalRenderer.cs 已定义 DeferredPlus = 3 和 Inspector 名称 Deferred+。GitHub master 是开发分支,不能直接等同于某个稳定发行版。实际项目中应以 Package Manager 里安装的 URP 版本、Universal Renderer Inspector 和该版本手册为准,不要根据本文反推 Deferred+ 的发布时间。
一、先看完整数据流
这张图只描述主干。阴影、深度预通道、SSAO、天空盒、后处理、自定义 Renderer Feature、Render Graph 合并以及平台回退,都可能在实际帧中增加、删除或合并 Pass。
两个维度分别解决什么问题
| 问题 | 主要由哪个维度决定 |
|---|---|
| 材质求值和实时光照是在几何 Pass 内完成,还是与几何解耦 | Forward / Deferred |
| 一个像素需要遍历哪些局部灯 | 传统 / Clustered(+) |
| 是否需要写入并读取多张 GBuffer Render Target | Forward / Deferred |
| 是否受传统每物体附加灯列表约束 | 传统 Forward 与 Clustered 路径的差异 |
| 透明物体能否直接参与常规延迟光照 | 不能;常规透明混合仍需要前向阶段 |
Unity 6.0 的 Forward+ 手册把它描述为先将屏幕划分为 tile,再只使用影响对应 tile 的灯光;当前 Graphics 源码则使用 usesClusterLightLoop 这一命名,并在 Core.hlsl 等文件中公开了 Cluster 灯循环入口。为了涵盖实现语义,本文统一称为 Clustered Light Culling,但不假设所有版本都使用完全相同的切片布局、缓冲格式或构建位置。
二、Forward:边画边算,灯光少时最直接
处理流程
可见灯光与 Renderer
→ 为 Renderer 准备每物体灯索引
→ Opaque Forward Pass:材质求值 + 光照 → Camera Color
→ Transparent Forward Pass:材质求值 + 光照 + 混合 → Camera ColorForward 在绘制物体时完成材质求值和光照。传统 URP Forward 会为 Renderer 提供每物体灯列表,片元着色器只遍历这份列表,而不是场景中所有可见灯。
Unity 6.0 手册将 Forward 列为 URP 默认路径,并建议在灯光不多、移动端或低端平台上优先考虑它;这是该版本的经验性建议,不是“Forward 在所有移动 GPU 上必然最快”的保证。目标设备的带宽、Shader 复杂度、分辨率和 Overdraw 都会改变结论。
优点
- 不需要完整 GBuffer,通常减少多 Render Target 的存储与读取压力。
- Unity 6.0 URP 的 Forward 支持 MSAA,适合必须使用硬件多重采样的项目。
- 透明物体天然在前向阶段完成光照和 Alpha 混合,流程统一。
- 材质可在自己的 Forward Pass 中直接计算光照,不必把所有必要参数压进固定的 GBuffer 布局。
代价与适用范围
- 传统 Forward 存在每物体实时灯约束;确切数量由 URP 版本、平台和资产设置决定,不应把某个版本手册中的数字写成永久上限。
- 光照工作发生在几何绘制内。若深度测试没有提前拒绝被遮挡片元,Opaque Overdraw 可能重复执行较贵的材质与光照代码。
- 大量局部灯覆盖同一物体时,CPU 侧灯光整理与 GPU 侧逐片元灯循环可能成为瓶颈。
它通常适合灯光规模可控、透明物体较多、重视 MSAA,或 GBuffer 带宽成本不可接受的项目。
三、Forward+:仍然边画边算,只是换了灯光索引
处理流程
可见灯光 + 相机视锥
→ 构建屏幕 tile / 深度区间与灯光列表
→ Opaque Forward Pass
→ 根据像素位置和深度定位 Cluster
→ 遍历该 Cluster 的候选灯
→ Camera Color
→ Transparent Forward Pass 使用同类 Cluster 灯循环Forward+ 的“Forward”没有改变:光照仍在物体的 Forward Shader 中执行。变化的是候选灯来源——从每物体灯列表,改为根据屏幕位置和深度查询 Cluster 数据。
Unity 6.0 手册明确说明,Forward+ 不受传统的“每个 GameObject 可受多少灯影响”的限制,但仍有每相机可见灯限制。这里的“不受每物体限制”也不等于灯光无限:相机剔除上限、Shader 数据容量、平台能力和包版本仍会约束实际规模。
优点
- 大量局部灯时,每个像素只处理其 Cluster 内的候选灯,避免把灯光选择粗粒度地绑定到整个 Renderer。
- 保留前向路径对 MSAA 和透明物体的适配方式;Unity 6.0 的公开比较表中 Forward+ 支持 MSAA。
- 不承担完整 GBuffer 的写入与回读,常用于“灯多,但 Deferred 的带宽或兼容性成本不合适”的场景。
- 透明物体也能使用 Cluster 灯循环,这是它相对传统 Deferred 透明回退路径的重要价值之一。
代价与适用范围
- Cluster 数据不是免费的:需要构建、上传或读取灯光索引数据,具体发生在 CPU 还是 GPU、使用何种缓冲,取决于 URP 版本与平台实现。
- 它没有改变 Forward 的基本 Overdraw 成本。Depth Prepass、Depth Priming 和 Early-Z 可能减少无效片元,但收益依赖遮挡结构、Shader 副作用和 Renderer 设置。
- Cluster 过粗时,同一格内仍可能有许多候选灯;Cluster 过细又会增加索引结构与构建成本。URP 会选择实现参数,项目不应假定固定网格规格。
它通常适合灯光较多,同时需要 MSAA、透明材质受多灯影响,或希望避开 GBuffer 带宽的桌面、主机与经实机验证的移动设备。
四、Deferred:先记录表面,再集中照明
处理流程
Opaque Geometry
→ GBuffer Pass:写入 Albedo、Normal、材质参数、GI/Emissive、Depth 等
→ Deferred Lighting:读取 GBuffer
→ Directional Light 全屏或等价处理
→ Point / Spot Light 通过 Stencil Light Volume 限定区域
→ Camera Color
→ Forward-only Opaque 与 Transparent Forward PassDeferred 把“这个像素是什么表面”和“有哪些灯照到它”拆开。兼容延迟渲染的不透明材质先写 GBuffer,光照阶段再读取这些数据。Unity 6.0 的 Deferred Pass 参考列出的实现包含 GBufferPass、DeferredPass 与 StencilDeferred.shader。
这里的“只给最终可见表面算光”需要谨慎理解:深度测试可以让延迟光照针对 GBuffer 中留下的表面工作,但 GBuffer Pass 本身仍可能有 Overdraw,多个光源体积也可能在屏幕上重叠。Deferred 减少的是“为同一不透明像素在多个几何覆盖层上反复执行完整光照”的机会,不是消灭所有 Overdraw。
优点
- 不透明几何的材质写入和光照解耦,大量局部灯覆盖复杂场景时更容易控制逐灯影响区域。
- 在 Unity 6.0 的公开比较中,Deferred 的不透明物体不受传统 Forward 每物体实时灯限制。
- 屏幕空间效果可以直接使用 GBuffer 中已有的深度、法线或材质信息,但实际可复用内容取决于版本与 Renderer Feature。
代价与适用范围
- GBuffer 需要多个 Render Target,增加显存占用和读写带宽。Unity 6.0 的 GBuffer 布局还显示部分附件会随平台能力和 Renderer 设置增减。移动端的 Tile-Based GPU 可能借助 Native Render Pass 或 Render Graph 降低部分外部带宽,但是否合并、是否留在 tile memory 不能只由“使用 Deferred”推断。
- Unity 6.0 URP 明确不支持 Deferred + MSAA;未来或其他分支仍应查对应版本手册,而不是把这条扩展为所有实现的理论定律。
- GBuffer 能保存的材质信息有限。法线编码精度、Rendering Layers 增加的目标以及 HDR、平台能力都会改变布局和成本,因此不能把某张固定附件清单当作所有版本的事实。
- 延迟光照不适合常规透明混合。透明物体会在之后的 Forward Pass 中渲染。
- 某些材质或 Shader 无法进入标准 GBuffer。Unity 6.0 的路径比较说明,不兼容 Deferred 的 Shader 会在渲染末尾改走 Forward;GBuffer 布局说明也列出了会使用前向通道的默认 Shader。当前源码还包含专门的 Forward-only Opaque Pass。
它通常适合以不透明几何为主、局部灯较多、不依赖 MSAA,且目标 GPU 能承受或有效隐藏 GBuffer 成本的项目。Unity 6.0 的 Deferred 还有 Shader Model 与图形 API 限制,具体平台支持必须查目标版本手册。
五、Deferred+:GBuffer 不变,灯光筛选改为 Clustered
处理流程
Opaque Geometry → GBuffer ─────────────────────┐
├→ Cluster Deferred Lighting → Camera Color
Visible Lights → Cluster / Tile / Z-bin Data ──┘
Forward-only Opaque / Transparent
→ Forward Pass + Cluster Light Loop
→ Camera ColorDeferred+ 不是“更高级的 Deferred 画质模式”,而是 Deferred 的 GBuffer 与光照阶段,加上 Clustered 灯光筛选。当前 Graphics master 的 UniversalRenderer.cs 中:
usesDeferredLighting对 Deferred 与 Deferred+ 都为真;usesClusterLightLoop对 Forward+ 与 Deferred+ 都为真;- 延迟光照分别准备
StencilDeferred与ClusterDeferred材质; - Deferred+ 在运行时不支持延迟光照时回退到 Forward+,而 Deferred 回退到 Forward。
这些是当前开发分支的源码事实,不承诺任一稳定 URP 包都具有完全相同的选项、回退条件和实现细节。
优点
- 对兼容材质的不透明物体,保留 GBuffer 后集中光照的结构。
- 用统一的 Cluster 灯光数据筛选局部灯,避免为每盏局部灯都只依赖传统 Stencil Light Volume 路径。
- 按当前
master的设计,Forward-only 与透明阶段仍可沿用 Cluster 灯循环,从而避免退回传统每物体灯列表的语义。
代价与适用范围
- 同时承担 GBuffer 的容量、带宽成本和 Cluster 数据的构建、存储与查询成本。
- 不应因为名字里有
+就假定它一定快于 Deferred 或 Forward+。灯光数量少、GBuffer 带宽昂贵、透明占比高或 Tile-Based GPU 的具体实现不理想时,结果可能相反。 - MSAA、Camera Stacking、Renderer Feature、平台回退以及 GBuffer 布局应按实际包版本验证;不能把 Unity 6.0 对 Deferred 的公开表格机械外推为所有 Deferred+ 发行实现的永久契约。
它更像是面向复杂不透明场景与大量局部灯的工程选项,而不是默认答案。只有当项目安装的 URP 确实暴露 Deferred+,并且目标设备捕获证明其收益成立时,才应采用。
六、Forward+ 与 Deferred+ 的本质区别
两者都使用 Clustered Light Culling,所以“一个像素先筛掉哪些灯”的思路相近;真正的分界仍然是光照发生的位置。
| 对比项 | Forward+ | Deferred+ |
|---|---|---|
| 不透明表面数据 | 在 Forward Shader 内直接求值 | 先写入 GBuffer,再由延迟光照读取 |
| 光照执行位置 | 几何绘制阶段 | 独立的 Deferred Lighting 阶段 |
| Cluster 解决的问题 | 缩小几何 Pass 中的候选灯集合 | 缩小延迟光照阶段的候选灯集合 |
| Opaque Overdraw | 可能重复执行材质与光照;Early-Z 等可缓解 | GBuffer 仍可能 Overdraw,但被覆盖层通常不会再执行完整延迟光照 |
| 带宽特征 | 避免完整 GBuffer,通常更轻 | 多附件写入与后续读取,通常更重 |
| 材质自由度 | 光照模型可直接存在于 Forward Pass | 受 GBuffer 表达能力和延迟解码路径约束 |
| 透明物体 | Forward + Cluster | 不进常规 GBuffer;之后 Forward + Cluster(以当前 master 设计为例) |
可以把两者的选择归纳为:Forward+ 用 Cluster 解决“灯太多”,Deferred+ 再用 GBuffer 结构处理“不透明表面的光照何时算”。
七、GBuffer、MSAA、灯限制、带宽与 Overdraw 总对比
下表是架构层面的比较,不是跨设备的性能排名:
| 特性 | Forward | Forward+ | Deferred | Deferred+ |
|---|---|---|---|---|
| 主要光照阶段 | 几何 Pass 内 | 几何 Pass 内 | GBuffer 后 | GBuffer 后 |
| 传统局部灯筛选 | 每物体灯列表 | — | Stencil Light Volume | — |
| Clustered Light Culling | 否 | 是 | 否 | 是 |
| 完整 GBuffer | 否 | 否 | 是 | 是 |
| 传统每物体实时灯约束 | 有,值随版本与平台变化 | 无传统每物体限制,但仍有相机/实现上限 | 兼容 Deferred 的不透明物体不依赖该限制 | 兼容 Deferred 的不透明物体不依赖该限制 |
| 透明物体 | Forward | Forward + Cluster | Forward;Unity 6.0 表格中仍受 Forward 类约束 | Forward + Cluster 是当前 master 的设计语义 |
| MSAA | Unity 6.0 支持 | Unity 6.0 支持 | Unity 6.0 不支持 | 查安装版本;不要仅凭名称推断 |
| 带宽倾向 | 无完整 GBuffer,通常较低 | 无完整 GBuffer,但多 Cluster 数据 | GBuffer 写入与读取通常较高 | GBuffer 与 Cluster 数据都存在 |
| Opaque Overdraw 的昂贵工作 | 可能重复材质与光照 | 可能重复材质与 Cluster 灯循环 | 可能重复 GBuffer 写入,完整光照通常针对留下的表面 | 类似 Deferred,并增加 Cluster 查询 |
| 灯很多时的扩展方式 | 受每物体列表约束 | 按 Cluster 查询候选灯 | 按光源体积/模板限定区域 | 按 Cluster 查询候选灯 |
| 常见平台倾向 | 灯少、带宽敏感、MSAA | 灯多但不想承担 GBuffer | 不透明为主且带宽可接受 | 新版本、高端目标;必须实机验证 |
不要死记 GBuffer 和灯光上限
GBuffer 格式会随 HDR、Rendering Layers、法线精度、Native Render Pass、平台能力和 URP 版本变化;灯数量也会受平台、相机剔除和包实现影响。Unity 6.0 手册中的具体数字只适合作为 6000.0 的版本化事实,不应复制成跨版本常量。
八、工程选型:先排硬约束,再测瓶颈
第一步:确认项目里真的有哪些选项
在 Package Manager 记录 com.unity.render-pipelines.universal 的确切版本,然后打开项目实际使用的 Universal Renderer Data,查看 Rendering Path 下拉框。若没有 Deferred+,不要通过序列化值或反射强行启用开发分支功能。
还要确认目标平台与图形 API。Unity 6.0 文档明确说明,不支持所选路径的 GPU 会回退到其他路径;当前 master 也区分“请求模式”和“实际模式”。因此 Inspector 里选中了某项,不等于运行帧一定执行该项。
第二步:列出不可妥协的功能
- 必须使用 MSAA:先从目标版本明确支持 MSAA 的路径开始;在 Unity 6.0 中是 Forward 或 Forward+。
- 透明物体占比高且需要很多实时灯:优先验证 Forward+;若使用 Deferred+,也要单独测透明阶段。
- 大量自定义光照模型难以编码进 GBuffer:优先 Forward / Forward+,或明确接受 Forward-only Pass。
- 不透明物体为主、局部灯多:把 Deferred / Deferred+ 纳入候选,但不要跳过带宽测试。
- 依赖 Camera Stacking、XR、Renderer Feature 或特定图形 API:逐项查安装版本文档并捕获实际帧,不能只看架构表。
第三步:构造代表性场景,而不是极端空场景
至少准备三类镜头:典型战斗或玩法镜头、灯光密集镜头、透明与粒子密集镜头。保持分辨率、后处理、阴影、动态分辨率和相机路径一致,只切换 Rendering Path。若切换路径同时改变了 Shader、Renderer Feature 或抗锯齿方案,记录这些变量,避免把复合变化归因给路径本身。
第四步:分别看 CPU、GPU 与带宽迹象
- CPU:剔除、灯光准备、提交与 Render Graph 记录是否变化。
- GPU:Opaque、GBuffer、Deferred Lighting、Transparent 各阶段耗时。
- 带宽:GBuffer 附件数量、load/store、resolve 和中间纹理是否增加。
- Overdraw:被遮挡片元是否执行了昂贵 Forward Shader,或 GBuffer 是否反复写入。
- 灯光:单个 tile / cluster 的候选灯是否异常密集,阴影是否反而成为主瓶颈。
最终选择应由目标设备上的 Unity Profiler、GPU Profiler 和 RenderDoc 捕获决定;Unity 6.0 的 URP 性能配置手册也建议用 Unity Profiler 或 RenderDoc、Xcode 等 GPU 分析器衡量设置影响。不同 GPU 架构对 ALU、纹理读取、MRT 与 tile memory 的权衡并不相同。
九、如何在 RenderDoc 中识别四条路径
先在同一相机、同一帧位置分别捕获。Pass 名称会随 URP 版本、Render Graph、Native Render Pass 和调试标记变化,因此要同时检查 Render Target、绑定资源、Shader 关键字和绘制顺序。
Forward
- 不透明几何通常直接写 Camera Color(以及深度),看不到一套供后续延迟光照读取的完整 MRT GBuffer。
- 在不透明 Draw Call 的 Pixel/Fragment Shader 中,可以看到材质求值与灯光循环。
- 灯索引来自每物体数据;检查绑定的 per-object light indices 或对应常量,而不是只凭事件名判断。
- 透明绘制继续直接写 Camera Color,并开启相应混合状态。
Forward+
- 同样没有“完整 GBuffer → Deferred Lighting”的主链路,不透明物体直接产出颜色。
- 几何绘制前或相邻阶段能找到 Cluster / tile / Z-bin 灯光数据的准备痕迹;具体可能是缓冲上传、计算或框架内部工作,不保证总有独立 Compute Dispatch。
- Shader 使用 Cluster 灯循环相关变体。当前
master已逐步使用_CLUSTER_LIGHT_LOOP/USE_CLUSTER_LIGHT_LOOP命名,旧版本可能仍显示 Forward+ 相关旧关键字。 - 检查片元 Shader 读取的 tile / Z-bin 与灯光缓冲,确认它不是传统每物体灯列表。
Deferred
- 先出现同时写多张材质附件的 GBuffer Pass;在 Pipeline State 中检查 MRT 和各附件格式。
- 随后出现读取 GBuffer 的 Deferred Lighting Pass。
- 传统局部灯通常能观察到球形、锥形或等价光源体积 Draw,以及深度/模板状态;Unity 6.0 源码参考把它对应到
StencilDeferred.shader。 - 透明物体和 Forward-only 材质在后续前向绘制中写入 Camera Color。
Deferred+
- 首先必须同时满足两个证据:存在 GBuffer 主链路,并存在 Cluster 灯光数据。只有其中之一都不足以判定 Deferred+。
- 延迟光照阶段读取 GBuffer,同时使用 Cluster / tile / Z-bin 与灯光数据;当前源码参考对应
ClusterDeferred.shader。 - 不要因为事件列表里仍有 Forward Draw 就否定 Deferred+:透明和 Forward-only 材质本来就需要前向阶段。
- 若捕获里完全没有 GBuffer,要警惕运行时回退。当前
master在 Deferred+ 不受支持时会实际改用 Forward+。
可以用下面这份“帧签名”快速初筛:
直接写颜色 + Per-Object Lights → Forward
直接写颜色 + Cluster Light Data → Forward+
GBuffer + Stencil/Light Volumes → Deferred
GBuffer + Cluster Light Data → Deferred+十、常见误区
误区 1:四条路径是四套 SRP
它们都是 Universal Renderer 内部的渲染路径选择。URP 仍是同一套 SRP;改变的是 Pass 组织、表面数据暂存方式和灯光筛选方式。
误区 2:带 + 就是画质更高
+ 主要改变灯光剔除与索引。它可能让更多灯稳定参与计算,也可能改变某些探针或功能路径,但不是通用的“高画质按钮”。应把画质差异当作功能与版本兼容问题逐项检查。
误区 3:Deferred 一定比 Forward 快
Deferred 用 GBuffer 换取光照与几何解耦。灯少、分辨率高、带宽紧张、透明很多或 GBuffer 附件增加时,这笔交换可能不划算。
误区 4:Forward+ 等于 Deferred,但没有 GBuffer
两者都能高效筛选许多灯,不代表光照时机相同。Forward+ 仍在几何 Shader 内算光,因此材质自由度、Overdraw 和带宽特征都更接近 Forward。
误区 5:Deferred 完全没有 Forward Pass
透明物体、Forward-only Shader、不兼容 GBuffer 的材质以及某些回退情况仍会产生 Forward Pass。判断路径要看不透明主链路,而不是看到一个 Forward 事件就下结论。
误区 6:Inspector 选项就是最终运行路径
平台不支持、调试模式或运行时条件都可能触发回退。Unity 6.0 手册只公开比较三条路径;当前 master 又包含 Deferred+ 及其回退逻辑。必须以实际包版本和帧捕获为准。
误区 7:固定灯数量和固定 GBuffer 格式适用于所有项目
这些值会受 Unity/URP 版本、平台、HDR、Rendering Layers、法线设置、图形 API 和 Renderer 配置影响。文章或工具里若需要数字,应同时记录版本与配置。
十一、一句话记忆
Forward / Deferred 决定“何时算光”,有没有
+决定“怎样筛灯”;+是 Clustered 灯光管理,不是画质升级。
Forward = 边画边算光 + 每物体灯列表
Forward+ = 边画边算光 + Cluster 灯列表
Deferred = 先写 GBuffer + Stencil Light Volume
Deferred+ = 先写 GBuffer + Cluster 灯列表官方参考资料
- Unity 6.0 Manual:Choose a rendering path in URP
- Unity 6.0 Manual:Forward and Forward+ rendering paths in URP
- Unity 6.0 Manual:Introduction to the Deferred rendering path
- Unity 6.0 Manual:Render passes in the Deferred rendering path
- Unity 6.0 Manual:G-buffer layout in the Deferred rendering path
- Unity Graphics:UniversalRenderer.cs(当前 master)
- Unity Graphics:Core.hlsl(当前 master)
- Unity Graphics:RealtimeLights.hlsl(当前 master)
