如何进行光照渲染路径(Shading Path)选择?

光照渲染路径

在渲染场景中,我们往往有多种光照和材质,计算不同光照对不同材质的影响是图形编程中非常核心的一个环节。在什么时候,以怎样的形式渲染光照也是渲染架构需要考虑的。

一般来说,我们会根据项目的实际需求,所处的平台特性进行光照渲染路径(Shading Path)的选择。

在移动平台上,在早期阶段,由于手机的带宽有限,往往会选用前向渲染的技术方案,forward+在forward的基础上对光照计算进行剔除。延迟光照通常用于pc或主机平台,但目前也已经开始出现基于移动端优化的延迟光照。

接下来将会对每种渲染路径做一个简单的介绍。

前向光照

前向光照是一个相对简单的渲染路径,在绘制物体的同时直接进行光照的计算,它的优点如下:
(1)实现比较简单
(2)能够实现任意多的着色模型数量
(3)输入参数的数量限制较小
(4)没有额外的带宽和显存占用
(5)能够应用硬件反走样

缺点如下:
(1)无法获取足够多的信息,难以应用一些高级效果(如贴花)
(2)多光照情况下计算量较大,为m(光照数量)* n(物体数量)次,overdraw比较严重
(3)为了处理不同光照类型,shader代码中需要包含不同光照类型的组合,导致shader代码占用内存过大

Forward+

前向光照计算在处理有大量光照的场景时性能会快速地达到瓶颈。针对这一问题,我们对forward算法进行了改进,称为forward+。

场景中主光源的数量是有限的,一般会用到大量光源的情况主要是局部灯光。局部灯光的特点是,只会对场景中的部分物体产生光照影响。因此,我们没有必要对所有物体都计算光照,只需要对受到光照影响的物体进行计算即可。

但是,着色器无法知晓每个对象具体受到哪些光照影响,这就需要我们预先准备这些数据。

为了实现这一点,forward+在forward的基础上在着色阶段前新增了light-culling阶段。我们可以在CPU中实现基于对象的光照记录,但是这种方法并行度较低;也可以在GPU中实现光照记录,一般会使用计算着色器实现对应功能。

由上可见,forward+能够更好地处理多光照的情况,减少不必要的计算,但是也会带来一些管理开销,实现也相对复杂一些。因此我们应该根据场景的实际光照情况选择合适的光照渲染路径。

延迟光照

通俗来说,延迟光照会在后处理阶段进行光照计算。

延迟光照主要分为两个阶段:
第一个阶段,我们渲染所有物体,并将渲染的数据写入到多张渲染目标,称为GBuffer,这些数据包括基本颜色、法线、深度、材质属性等;
第二个阶段,我们根据GBuffer中的信息,进行屏幕空间的光照计算,得到最终渲染的结果。

它的优点如下:
(1)多光照情况下,以较低的复杂度绘制。它的复杂度和物体数量无关,对于m个光源,屏幕空间每个像素只需计算m次。overdraw带来的消耗更低。
(2)记录了GBuffer信息,对一些高级的屏幕空间算法的实现更友好
(3)将材质和光照计算的过程分离,减少所需的shader数量

缺点如下:
(1)用到多张渲染目标,带来严重的带宽消耗和显存占用
(2)材质信息需要记录在GBuffer中,限制了材质的多样性
(3)无法应用硬件反走样,需要自己实现相关AA算法
(4)对透明物体没有较好的处理办法

Tile-Based延迟光照

我们知道移动端无法很好地应用延迟光照主要就是因为带宽问题。随着图形API的发展,近几年也出现了针对移动端优化的延迟渲染,也就是基于前文提到的subpass技术实现的延迟光照。

此时,光照绘制分为两个步骤:
① 物体写入GBuffer,GBuffer存储于on chip memory。
② 利用GBuffer进行光照计算,将最终颜色写入framebuffer。

在此过程中,实际上GBuffer只作为中间过程量存在,因此也就在保留延迟渲染减少overdraw的优点的情况下,避免了GBuffer写入带来的带宽消耗。但同时,也失去了传统延迟光照的一些优点,比如后处理阶段无法利用GBuffer信息作为输入,因为此时GBuffer是memoryless的。

混合管线

在实际的项目中,不同的渲染路径没有绝对的区分,整个管线可能是混合的,比如我们会遇到如下情况:

① 在延迟管线中,大部分光照是后处理完成的,但是仍然有一些简单光照计算可能放到前向阶段就完成了,直接写入到SceneColor中;

② 在延迟管线中,会单独处理透明物体,让其依然按照forward管线进行绘制;

在很多情况下,我们会发现,有些渲染算法本身可能并不复杂,有时候真正的难点在于如何使用一套渲染框架描述尽可能多的着色模型,并且保证性能和易用性。因此,在处理渲染管线时,也会为了更好地适配更多效果做或多或少的妥协,加上各种各样的特殊处理。我们也就会吸取不同渲染路径的优点来实现最终的渲染架构。

本文摘自:CSDN博主「ZJU_fish1996」的原创文章《[引擎开发] 渲染架构与高级图形编程》,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ZJU_fish1996/article/details/112847781

最新文章