接上回,RSM优化技术介绍后,我们本部分主要看一下,光栅GI三部曲中的LPV,这个算法算是很巧妙了,算法思路基于RSM上拓展到世界空间,可以说很具学习和思考价值,之前也简单实现过Global Illumination_Light Propagation Volumes (LPV)有兴趣的可以去简单了解下,本部分主要对LPV技术进行优化介绍与分析,学习自用,大佬勿喷。
一、LPV简述
老规矩,首先我们先来看一下LPV技术的原理以分析其性能卡点,具体的就不介绍,有兴趣的找原文,本部分只简单介绍:原始算法的思想仍是基于场景RSM缓冲区生成的虚拟光源,随后把光源数据注入到一个均匀的体积网格(3DTexture)中,该网格覆盖场景,每个网格用球谐编码代表一个位置、通量和法线的缓存数据。
我们可以将场景分为n * n * n个网格,每个网格都可以存储其相邻网格的总辐照度。具体能量传输公式可如下图所示:
其中,M是单元格的邻居数(6),P是迭代传播的次数(任意数)。下面是一个简化的单次网格传播的可视化过程:
接下来我们看一下LPV的管线流程,如下图,即(生成->注入->传播->光照)四步走:
知道了大体流程我们,就看一下优化优化点。
二、RSM优化技术
2.1 降采样优化
如前所述,为了收集次级光源表面的辐射亮度(radiance),场景必须近似地在单元格网格中。这些单元格的数量取决于所提供的RSM纹理(通量/正常/世界位置)的分辨率,但是分辨率越高,光照注入和传输的成本就越高。如果原始的RSM的缓冲区是以2048x2048分辨率生成的,这对于生成2048三次方个表面的网格元素,之后无论是注入还是传输都需要执行这么多次的计算。因此,必须通过降低分辨率,减少计算量。
不得不说降采样是解决这类问题的首选方法,那么降采样后的LPV渲染管线便更改为:
总的来说,降采样后场景的视觉质量是可以接受的,而且性能的提高非常明显。注入通道的计算复杂度变为:
传输过程降低的成本再加一个维度,会降低的更狠,其中,一般根据场景大小与分辨率来综合考量确定降采样因子,但也别降低的太多,否则效果会很差,正常采用𝑘=4的降采样因子差不多,而𝑟𝑠𝑚𝑊𝑖𝑑𝑡ℎ,𝑟𝑠𝑚𝐻𝑒𝑖𝑔ℎ𝑡是RSM缓冲区的原始维度。
可以看一下降采样和不降采样后效果对比,几乎差不太多,但是如果是超大场景,差异就会明显了,大家可以根据项目综合考虑。
原始效果(非降采样):
4倍降采样后效果:
注入渲染Pass,实际上就是从这些RSM缓冲区生成场景的点云的几何图形过程,在此优化后运行的会更快。下图展示了原始2048*2048分辨率下与4倍降采样后性能对比:
可以看出,性能提升直接形成了断崖式的优化。
2.2 计算着色器降优化
当然还可以将生成3DTexture的生成流程转换至计算着色器进行实现,在降采样着色器中节省更多的性能。
如上图所示,使用计算着色器也可以些许优化性能。此外传输过程也可以基于计算着色器进行优化,但由于其复杂度不高,连续迭代多次的话其实可以使用API的bundles来优化更好。
2.3 现代图形新特性优化(Bundles)
首先我们需要知道CPU的每次图形设置都是需要在驱动层校验命令正确性的,所以在GPU上运行的CPU提交命令可能相当昂贵。
而在LPV技术中,传播光照流程是独立的、相似的、小的绘制调用命令,它们会将光照累积到最终的3D纹理集合中。传播次数也就是这些命令的调用数量随着项目不同而不同,可能从1到100不等,一般采用50此迭代,所以此部分可以优化。所以很容易联想到DirectX 12功能中的捆绑包功能,具体可以参照之前的这篇文章DirectX12_初识之根签名、显存管理、资源屏障、栅栏同步、描述符与描述符堆、捆绑包。
简而言之,捆绑包是一组保存一次并在需要时重新执行的命令。一个包将“引用”一些绑定到它的有用信息,例如缓冲区,并使用该数据的更新版本执行自己。这个功能非常适合传播传递,并节省了CPU上的工作负载,即几十个命令不再在每一帧一遍又一遍地重新添加。
简单看一下,开启和不开启Bundles的捕帧情况:
开启:
不开启:
由于捆绑包的使用只是一个CPU优化,所以在不同CPU上的性能差异会不同(性能越低、DrawCall越多效果越好)。
2.4 并行渲染管线升级
和上一章节RSM的介绍中一样,LPV其实也可以拆分成并行管线来处理,拆分后的异步管线如下图所示:
如果我们使计算队列中的RSM的并行计算传递过程处理大量图形工作以降低Buffer的异步等待,性能提高将比非异步场景中提高更明显。但是实现起来复杂且收益不高,可自行根据项目需求来。
三、小结
总的来说,LPV是一种很好的部分全局照明技术。在现代GPU硬件上经过上述优化后运行还行,并提供了可接受的一次diffuse反射的间接光照效果。但由于球谐函数的性能和低频存储的限制(一般都是用2或3阶的球谐系数,LPV一般用2阶),只有低频照明能够被映射出来,这使得间接镜面反射无法实现,如果需要再球谐函数上实现高频,需要重建高频信号,但可能很费,有兴趣的可以参照之前的这个文章Global Illumination_Spherical Harmonic Lighting(球谐光照)。
还有一个优化就是在注入阶段,生成体积数据需要RSM纹理。一些纹理,可以使用八面体编码来优化),可能会节省整体内存影响和带宽。最后,就是有些视角下网格中的许多均匀单元格都是空的,并且没有任何信息,这对于传播计算通常是非常浪费的。可以通过优化有效空间属性结构来优化,但是感觉直接使用VCT(VXGI)来应该更好,下一部分我们就主要来看一下VXGI的相关深度优化。