聂宇
(四川大学计算机学院,成都610065)
以巨大的计算量为代价,全局光照(间接光照)技术能大幅度提升渲染图像的真实性。其计算复杂度存在于多个方面。首先,全局光照解决方案需要判断3维场景中任意两点的可见性。在基于光栅化管线中快速进行可见性判断则更加困难。其次,全局光照的计算要求对每个着色点的法半球所有入射光线进行积分。即使在图形硬件快速发展的今天,全局光照应用的实时性也很难得到保障。高DPI 屏幕、立体渲染、VR 设备的高帧率要求更是加剧了真实性与效率的矛盾。因此,现今大部分应用都不支持精细的全局光照(局部的、动态光源和动态场景),如图1 所示,而是主要通过预计算的辐射传输[2]来进行静态预计算或有限形式的动态光照。
在交互式渲染的前提下,就如何生成令人信服的全局光照效果近年来涌现了大量的解决方案。光场探针技术便是其中运用较为广泛的一类方法。探针的表现形式各有不同,例如JT Hooker 等人利用立方体贴图编码光场[3],而Thomas 等人则利用八面体贴图进行光场编码[4]。传统光场探针技术的局限性在于它们预计算的特性和它们对场景光场进行采样的方式。由于生成探针数据的预计算十分耗时,因此,传统光场探针仅能处理静态光源和静态场景的情形。此外,对辐射照度进行空间插值和预滤波的高光采样策略极可能造成锯齿和漏光现象,如图2 所示。
图1 精美的全局光照效果
随着图形硬件的飞速发展,实时光线追踪成为热门研究领域。DDGI(Dynamic Diffuse Global Illumination)作为首先利用硬件光线追踪的渲染算法,拓展了McGuire 等人[5]提出的传统基于探针的全局光照,弥补了原先只支持静态场景的劣势,使得DDGI 可以被广泛使用。
然而,DDGI 也并非毫无缺点。即使现在已经有硬件光线追踪的支持,在场景比较复杂的情况下,DDGI在每一个探针处仍不能发射大量光线。同时,DDGI 将多次反射的计算代价,分摊到若干帧,并通过混合的方式更新每个探针的辐照度。因此,DDGI 主要存在2 个问题:首先,首先是通过混合的方式分摊计算代价会导致闪烁的问题;其次,是由于混合,当场景存在剧烈变化时,会观察到GI 效果有从一个地方“流动”到另一个地方的问题。
我们注意到,造成这些问题的根本原因在于从探针处发射的采样光线数目较少。当场景简单时,我们可以通过增加采样光线数目来避免这些问题。但当场景复杂程度升高,场景中布满的探针数目随之增加,在每个探针多发射采样光线已经无法实时。因此,本文提出可以通过重要性采样,使得即使每个探针只发射少量光线也可以获得比较好的效果。
图2 左图漏光,右图正常
首先,我们简要地回顾一下DDGI。DDGI 是Majercik 等人在Light Field Probe 算法的基础上,结合硬件光线追踪而提出的。同Light Field Probe 一样,DDGI将场景的辐射度信息和几何信息编码到均匀分布的探针中。而与Light Field Probe 在场景初始化时预计算探针存储的信息不同的是,DDGI 会动态地根据场景中变化的几何和光源,动态地更新每个探针中存储的数据。其更新过程如图3。
图3 探针信息的更新
在生成光线阶段,DDGI 采用了最普通的均匀生成光线的方式。这种方式在大部分情况下均适用,但当每个探针处发射的光线数目较少时,极可能造成闪烁等伪影。本文希望通过重要性采样的方式规避掉这些问题。在更新每个探针存储的数据时,DDGI 通过混合的方式,通过控制混合的α值将新的数据与前一帧的数据结合起来。如公式所示:
着色点最终的间接光照计算,DDGI 相较于Light Field Probe 一样中的计算方式也作出了一些改变。笼统来说,为了能让DDGI 动态场景下具有更强的鲁棒性,Majercik 等人综合参考了一些光线追踪和阴影贴图的文献,在计算包含着色点的八个探头对应的辐照度之后,结合着色点的位置以及探针的位置,计算对应的插值权重,具体包括:
(1)通过一个合理设置的阈值,当探针处于着色点切面以下时,将此探针的插值权重设置为0;
(2)采用基于感知的权重来解释人类视觉系统对其他黑暗区域(即漏光)低强度照明的敏感性;
(3)采用方差阴影贴图算法描述的均值和方差偏差的切比雪夫插值用于探针和着色点之间的可见性判断,以便能更好地对探针中的辐照度进行滤波;
(4)根据与着色法线和探针方向来偏移着色点:这通过远离潜在的阴影和非阴影不连续的区域来提高基于可见性的插值权重的鲁棒性;
(5)根据着色点和探针中心之间的距离,使用上述计算得到的权重执行标准的三线性插值。
总的来说,DDGI 改进了传统的基于探针的辐照度插值算法,使其能够支持动态场景和动态光源。但其存在当探针处发出的光线数目较少时产生闪烁等问题。
分层样本扭曲[6]是一种让样本点的分布与某个函数相匹配的技术。假定我们可以拿到前一帧的辐射度信息(通过小波变换或者生成Mip-Map,本文以Mip-Map 作为例子讲解),则我们可以通过分层样本扭曲,将给定的均匀分布的样本点,扭曲成符合该辐射度的分布,如图4 所示。
首先,我们需要从Mip-Map 最糙的一级开始(分辨率为2×2),首先对于每一行,我们先计算行分界线。在本文的例子中,上面一行的平均辐射度为80%,下面一行的平均辐射度为20%,因此我们可以得到相应的分界,如图5 所示。
图4 HSW的基本图示
图5 纵向Warping
随后,对每一行分别进行同样的处理,如图6 所示。在本文的例子中,上面一行靠左侧的平均辐射度为75%,而靠右侧的平均辐射度为25%。同样的,我们也需要对下面一行进行分层样本扭曲。
图6 横向Warping
通过HSW,我们得到了一个根据2×2 重要性函数分布的样本点集合,且在每个象限中的样本点均为均匀分布。分层样本扭曲会递归的在每个Mip-Map 层级进行,当扭曲过程结束以后,我们将可以得到跟重要性函数相同的样本点集合。
概括上来说,我们只需要改进图3 生成光线的策略(以重要性采样的方式)即可。因此,我们需要将探针更新的流程改成图7 示。首先,我们可将上一帧探针采样得到的结果进行分层样本扭曲,以确定每一个探针需要在哪些立体角内发射更多的光线,以及在其他对应的立体角发射较少的光线。在采样方向确定以后,我们仍然需要在这些方向上应用光线追踪,以确定这些方向所击中场景中点的相关信息(例如法线、材质信息等),形成类似G-Buffer 的结果。然后我们需要对生成的G-Buffer 进行直接光照和间接光照的着色,所得到的结果将会用于更新探针的辐照度,且会被用于下一帧的分层样本扭曲。
其中比较困难的一步是如何使用GPU 实现分层样本扭曲。在过去由于GPU 的种种限制,分层样本扭曲往往是是现在CPU 端的。由于CPU 与GPU 之间相互传递数据需要涉及内存与显存之间相互拷贝数据,这一过程往往很耗时,因此我们需要在GPU 端实现分层样本扭曲。本文的解决方案是将分层样本扭曲并行在探针级别,并采用计算着色器实现。这样我们可以在较短的时间内实现重要性采样,得到最终的采样结果。后续更新探针的辐照度信息以及用更新后的探针结果进行着色的过程与DDGI 差别不大,只是由于我们采用了重要性采样,可以适当调低更新过程中使用的α的大小,同时画面保持无抖动状态。
图7 结合重要性采样的探针信息更新过程
本文所有实验的硬件设备如表1 所示。
表1 实验硬件
图8 展示了加入重要性采样以后,渲染的结果(分辨率为1920×1080)。最左一列表示直接光照结果;中间一列表示加上漫反射全局光照的结果;最右侧一列表示加上高光全局光照的结果。对应的性能数据如表2 所示。
图8 复杂场景下渲染的结果
表2 性能数据
本文就DDGI 在采样不足的情况下可能出现闪烁的伪影进行研究,采用重要性采样的方式解决这一问题,该改进方式能够有效地缓解这一问题。将来的研究将主要从以下两个方面进行:
首先,该算法现阶段并没有有效地将光泽反射的全局光照结合进去,因此只能通过其他算法去计算这一效果;其次,现阶段对探针的更新是暴力地更新场景中的所有探针,这种暴力更新策略其实浪费了大量计算资源(例如当前相机只能看见整个场景的某一部分,但却对所有探针进行更新),我们仅需要对视锥体内部以及靠近视锥体的一部分探针进行更新。在后续的研究中,希望可以对着两点进行改进。