Forward+是在前向渲染管线基础上的优化。它首先通过一个Z-Prepass生成全精度深度图,然后将屏幕分块。对每个块,根据其深度图中的最近和最远深度值,将从相机穿过该块四角的光线截成一个四棱台包围盒。接着,用这个包围盒去检测场景中的每个光源。将光源影响范围简化为包围球/锥体,然后检测这个光源包围盒是否与四棱台相交,则将其加入该块的光源列表;否则直接剔除。最终着色时,每个像素只需计算其所在块列表中光源的光照贡献。
其Forward+解决了Forward Renderring中灯光对性能消耗过大的问题
-
对于场景中绝大多数的固体物体,URP 会使用经典的延迟渲染流程:
-
G-Buffer Pass:将物体的几何和材质信息(如颜色、法线、光滑度等)渲染到一组名为 G-Buffer 的纹理中。
-
Deferred Lighting Pass :在屏幕空间,利用 G-Buffer 里的信息,一次性为所有光源计算光照。
这样做的好处是,可以高效支持大量动态光源,且性能不会因物体数量增加而急剧下降。
-
-
透明/特殊物体:辅助走"Forward+"
对于那些延迟渲染天生处理不好的物体,Deferred+ 会切换到 Forward+ 路径。这包括:
-
半透明物体:因为它们需要 Alpha 混合,无法简单地存入 G-Buffer。
-
使用了"仅前向" (Forward Only) 着色器的物体:比如某些材质用了非常复杂的自定义光照模型,其数据无法压缩进标准的 G-Buffer 里。
-
-
延迟渲染 G-Buffer Pass 的输出 :当所有不透明物体走完延迟渲染流程、生成 G-Buffer 的同时,一张包含所有不透明物体的完美深度图(场景深度)就已经存在于内存中了。
-
专门的 Depth Pre-Pass:即便是在正式开始延迟渲染之前,URP 也可能已经为不透明物体单独跑了一个深度预通道来加速后续的 G-Buffer 生成。这张不透明物体的深度图同样可以被复用。
所以,当流程走到渲染透明物体的 Forward+ 阶段时,会直接复用这张现成的、只包含不透明物体的深度图,来作为透明物体光照裁剪的依据。
如果半透明物体背后的不透明物体的包围盒包含了光源,那么这个光源会被加入该Tile的光源列表。之后,这个Tile内的所有像素,包括半透明物体的像素,在着色时都会尝试用这个光源进行光照计算。
存在的问题:
如果半透明物体背后的不透明物体包围盒与灯光视锥体没有相交,那么无论半透明物体本身与灯光有多大的交集,这个灯光都会被直接剔除,永远不会被用于这个 Tile 内任何像素的光照计算。
问题:为什么前向渲染要加入forward+是因为灯光计算消耗大,那么有了延时渲染为什么要deferred+呢
-
延迟渲染的困境 :它依赖 G-Buffer,而 G-Buffer 每个像素只能存一个表面的材质属性。半透明效果需要看到多个重叠的表面,并把它们的颜色混合起来。G-Buffer 根本无法同时存储玻璃、玻璃后面的墙、以及墙前面的烟雾这三层数据。
-
Deferred+ 的做法:不透明物体走延迟渲染,享受高效光照。画完之后,所有半透明物体用 Forward+ 来画。Forward+ 本身就支持逐物体的颜色混合,还能用 Tile 光源裁剪保持高效。
问题:我很好奇,forward+是用的不透明物体的深度来算的,那么在deferred+中不是和延时渲染计算的光照过后又进行了不透明物体与透明物体的forward+光照贡献计算吗,不是多算了不透明物体对光照的计算吗?
为什么不是"多算了一遍不透明物体"?
你担心的"多算",可能是指 Forward+ 的光源裁剪和光照计算,又把背景不透明物体牵扯进来了。
事实是,到了 Forward+ 这个阶段,不透明物体已经完全退场了:
-
计算阶段 :不透明物体的光照在第一步就算好并存入颜色缓冲了。这一帧里,德菲尔 Lighting Pass 只运行一次,算完即止。
-
渲染阶段 :Forward+ Pass 的渲染队列里,只有透明物体。像素着色器只会为透明物体的像素执行,不会再去碰任何不透明物体的像素。
-
裁剪目的 :Forward+ 做 Tile 光源裁剪,是为了让透明物体的像素着色器能高效地只计算对它自身有贡献的光源,而绝不是为了把不透明物体的光照重算一遍。