欢迎光临散文网 会员登陆 & 注册

蒙特卡洛光线追踪基础 - 实时光线追踪的降噪

2023-08-23 17:49 作者:B1ueMicr0  | 我要投稿


最近的 DLSS 3.5 可谓是实时光追降噪领域的革命,它的 Ray Reconstruction 技术其实就是一种 AI 降噪器,替换了原来的时空滤波技术(原本类似 SVGF 的方法)。所以趁着这个机会我就先把这个系列文章更新了,主题就是实时光追的降噪,最后会延伸到现在的 DLSS 3.5 技术。

上篇文章:

提到了蒙特卡洛光线追踪的两大重要基础——渲染方程和概率密度函数。现在我们就来讨论另一个重要概念,就是降噪(denoise)。通过这篇文章,你将看到降噪在光线追踪中起到的重要作用,尤其是在游戏领域,也就是实时光线追踪上的重要应用。

首先什么是滤波我们要说一下。顾名思义,滤波(Filter)就是对信号中特定波段频率滤除的操作,是抑制和消除信号干扰的一项措施。而噪声(noise)则是信号干扰的一种体现,为了去除噪声,我们就要进行滤波。

上篇文章我们提到蒙特卡洛光线追踪的本质,就是采样或多次采样蒙特卡洛积分来接近收敛到正确结果。然而我们的采样数 N%20%5Cto%20%5Cinfty 时才会完全收敛,其实除了每像素采样次数之外,还有一个叫反弹(bounce)的重要概念。

我们这里看一下渲染方程的诺依曼级数展开。这里,我们把渲染方程写成以下形式:

I%20%3D%20g%20%5Cepsilon%20%2B%20gMI%20

其中 M 是线性算子。

接着,我们再改写一下这个表达式:

(1-gM)I%3Dg%20%5Cepsilon

其中 1 是单位算子,我们可以再转换为这个形式:

I%3D(1-gM)%5E%7B-1%7Dg%20%5Cepsilon

%3D%20g%5Cepsilon%20%2B%20gMg%5Cepsilon%20%2Bg(Mg)%5E%7B2%7D%5Cepsilon%20%20%2B%20g(Mg)%5E%7B3%7D%5Cepsilon%20%20%2B%20%C2%B7%C2%B7%C2%B7%2Bg(Mg)%5E%7Bn%7D%5Cepsilon

通过这个式子你也能看出要用数值方法快速求出渲染方程的解析解几乎是不可能的。

其中 n 对应光线反弹的次数。一般地实时光线追踪技术里 n%20%5Cin%20%5B1%2C4%5D , 再高下去的增益不明显(经过反弹之后光能会大量衰减)并且开销呈指数上升。

说完了实时光追在渲染上的一些注意事项,我们接下来进入降噪环节了。

对光线追踪的结果进行降噪,对几何多边形抗锯齿,对纹理做反走样(例如各向异性过滤)都属于滤波。

右图就是通过每像素发射 32 根光线(也称每像素采样 32 次, 32 spp)去采样渲染方程得到的结果。左图则是经过了时间性滤波得到的结果。这里也间接地说明了滤波不只是针对空间的,时间维度上也可以做滤波。例如著名的时间性抗锯齿(TAA)就属于一种时间性滤波。

对于实时光线追踪来说,找到一种合适的降噪方式是非常重要的。因为目前消费级光线追踪硬件的性能只能满足于每像素发射 1-2 根光线去采样。

所以所谓的实时光线追踪的难点完全不在于渲染技术(渲染方程,蒙特卡洛无偏估计,BSDF 模型),它们的原理和工业界用了很多年的离线渲染是一致的,已经十分成熟;

真正的难点在于后期做的重建(reconstruction)工作(降噪,升采样,性能优化)。

好,接下来我们就正式进入实时光追的降噪了。它的本质就是通过滤波算法来消除高频的噪声。高频就是信号的变化幅度很大,看上去密密麻麻的。

一般性定义:

我们定义一个带有噪点的图像 %5Ctilde%7BC%7D%20,这个作为降噪的输入数据

另外,降噪的算法方面,我们定义一个滤波核 (kernel) K, 它可以有很多种,用来改变像素,我们简称 “”。

最终图像为 %5Cbar%7BC%7D%20%20

我们先从简单的高斯滤波(Gaussian Filter)说起,它最常用来做模糊效果。了解了这一整套流程之后,你将会更理解实时光追的另一种基于联合双边滤波的方法。

用高斯滤波的核对图像做卷积可以使得图像的高频信息变成低频的,最终结果就是图像变得模糊了起来。

高斯提出的正态分布大家都知道吧。N 维空间的正态分布为:

G(r)%20%3D%20%5Cfrac%7B1%7D%7B%5Csqrt%7B2%5Cpi%20%5Csigma%5E2%7D%5EN%7D%20e%5E%7B-r%5E2%2F(2%20%5Csigma%5E2)%7D

令 N%3D2,则二维表达为:

G(r)%20%3D%20%5Cfrac%7B1%7D%7B2%5Cpi%20%5Csigma%5E2%7D%20e%5E%7B-r%5E2%2F(2%20%5Csigma%5E2)%7D

其中模糊半径 r 与横纵坐标 (x%2Cy) 有  r%5E2%20%3D%20x%5E2%20%2B%20y%5E2 的关系,这样一来我们可以得到:

G(x%2Cy)%20%3D%20%5Cfrac%7B1%7D%7B2%5Cpi%20%5Csigma%5E2%7D%20e%5E%7B-%5Cfrac%7B%7Bx%5E2%20%2B%20y%5E2%7D%7D%7B2%20%5Csigma%5E2%7D%7D

通过这个方程,我们可以生成一个高斯核。不过一开始生成的高斯核是一堆浮点数组成的,我们要进行定点化。以 5%20%5Ctimes%205 的为例,因为在定点后我们需要做归一化(normalization),必须除掉这个数, 所以选择 2^8 也就是 256 做定点。

最后得到的核长这样:

K%3D%20%5Cfrac%7B1%7D%7B256%7D%20%5Ccdot%20%5Cbegin%7Bbmatrix%7D%20%20%0A%20%204%20%26%206%20%26%2012%20%26%206%20%26%204%20%5C%5C%20%20%0A%20%206%20%26%209%20%26%2018%20%26%209%20%26%206%20%5C%5C%20%20%0A%20%2012%20%26%206%20%26%2036%20%26%2018%20%26%2012%20%5C%5C%20%20%0A%20%206%20%26%209%20%26%2018%20%26%209%20%26%206%20%5C%5C%0A%20%204%20%26%206%20%26%2012%20%26%206%20%26%204%20%20%0A%5Cend%7Bbmatrix%7D%20%20

它还可以拆成两个一维的核,这样 5%20%5Ctimes%205%20%3D%2025  的采样就变成了 5%2B5%20%3D%2010 次,节约了性能。

K%3D%20%5Cfrac%7B1%7D%7B256%7D%20%5Ccdot%20%5Cbegin%7Bbmatrix%7D%20%20%0A%20%204%20%26%206%20%26%2012%20%26%206%20%26%204%20%5C%5C%20%20%0A%20%206%20%26%209%20%26%2018%20%26%209%20%26%206%20%5C%5C%20%20%0A%20%2012%20%26%206%20%26%2036%20%26%2018%20%26%2012%20%5C%5C%20%20%0A%20%206%20%26%209%20%26%2018%20%26%209%20%26%206%20%5C%5C%0A%20%204%20%26%206%20%26%2012%20%26%206%20%26%204%20%20%0A%5Cend%7Bbmatrix%7D%20%20%3D%20%20%5Cbegin%7Bbmatrix%7D%20%20%0A%20%202%20%20%5C%5C%20%20%0A%20%203%20%20%5C%5C%20%20%0A%20%206%20%5C%5C%20%20%0A%20%203%20%20%5C%5C%0A%20%202%20%20%0A%5Cend%7Bbmatrix%7D%20%5Ccdot%20%5Cbegin%7Bbmatrix%7D%20%20%0A%20%202%20%26%203%20%26%206%20%26%203%20%26%202%20%20%5C%5C%20%20%0A%5Cend%7Bbmatrix%7D

这是一个逐像素进行的操作。设 i 是原本像素,j 是周围像素,则理论上需要考虑所有 j 和 i自身的贡献值。

但实际上不必考虑所有像素周围的所有信息,因为根据正态分布图象,两边延伸的值非常小。在这里可以当成没有像素贡献值。

所以编程时只需稍微设置下 %5Csigma 就可以了,一般选择 3%20%5Csigma。如上图,这时候的值是很小的。

好了,接下来看下高斯滤波的效果:

显然,高频信息被干掉了。左边有肉眼可见的高频噪声,右边没有了。

上面我们以高斯滤波,高斯核作为引例来解释了滤波上的一些东西。接下来我们就要回归实时光追这边来了。如果你在刚才已经形成了初步认知,那么接下来的东西也会比较简单。

我们提到,滤波可以有很多种。接下来我们介绍一种滤波,叫做联合双边滤波(Joint Bilateral Filtering),这是目前实时光追中 SVGF 降噪的基础。

它有很多优点,比如不需要像高斯滤波那样要考虑到归一化的问题,联合双边滤波这个过程本身就已经做了归一化了。

联合双边滤波相比于双边滤波,优化了相似性权重模板。什么是双边滤波呢?我们知道高斯滤波最终的结果全是低频的,这肯定是不行的。为了视觉观感,去掉低频噪声的同时我们也要保留高频信息。

双边滤波的核心就是:如果两像素的颜色差异较大,则降低周围像素 j 对原本像素 i 的贡献。

所以我们在高斯滤波的基础上来表示颜色差异,以此实现双边滤波。这样一来,像物体的轮廓等高频信息就没有被破坏。

而联合双边滤波则能使用更多信息来做滤波,除了颜色之外还有 Depth(深度), Normal(法线)信息。这些一般都是通过光栅化来生成的,本身就不带噪点。这对使用联合双边滤波来降噪是很好的。

例如:

A,B 两点就可以通过深度信息来判断贡献(一个在后面的墙上,一个在砖块的前面);

B,C 两点可以通过法线来判断贡献(一个法线朝着正面的墙,另一个朝着侧面的墙);

D,E 两点就可以凭借颜色信息来判断了。

这样我们就可以确定贡献值,它们互相之间的贡献基本等于没有,所以我们就可以保留住它们不进行模糊滤波。

这样一通操作下来,我们输入的信息多了,控制滤波的因素就多了,所以我们就需要一个很大的核(有可能会达到 128%20%5Ctimes%20128 的大小),这开销就过于庞大了。

其实我们之前把那个二维高斯核拆成两个一维核就是一种解决方案,但是理论上双边滤波是不能这样拆的,所以我们另辟蹊径:

如上图,我们选择渐进地增大滤波的大小。

第一层 i%3D0 使用 5%20%5Ctimes%205 的核,然后第二层继续使用 5%20%5Ctimes%205 的核算出第三层的中间像素,连续算5层,每一层都间隔 2%5Ei 个像素,直到 i%3D4,这样就能将原本滤波的一个像素需要 64%20%5Ctimes%2064 的核变成 5%20%5Ctimes%205%20%5Ctimes%205 的了,大幅节约了性能(采样次数 4096%20%5Cto%20125)。

但滤波不是万能的。输入图像可能少许存在一些小的白色亮点(outlier),其实这是求解蒙特卡洛积分导致的问题,亮度可能会出现大于 1 的情况。

但是做滤波的过程中,这些 outlier 会越来越大,远超过 1,影响到的周围像素导致出现比较明显的大白点了,如下图。所以我们需要一些手段在滤波之前就去掉这些 outlier。

方法也很简单。我们分为寻找和消减两个阶段:

寻找阶段

  1. 遍历一个像素周围的 n%20%5Ctimes%20n 的区域 (7%20%5Ctimes%207),算出的均值 %5Cmu%20 和方差 %5Csigma 。

  2. 如果这个像素的值在 %5B%5Cmu%20-%20k%20%5Csigma%2C%20%5Cmu%20%2B%20k%20%5Csigma%5D 范围外(一般 k%20%5Cin%20%5Cleft%5C%7B%201%2C2%2C3%20%5Cright%5C%7D%20),则判定该像素为 outlier。

消减阶段

  1. 我们并不是要删除这个像素,因为它只是亮度值有问题。

  2. 所以我们只需把亮度值给它 clamp 到 %5B%5Cmu%20-%20k%20%5Csigma%2C%20%5Cmu%20%2B%20k%20%5Csigma%5D  即可。

但是这样显然违背能量守恒,因为人工调整了亮度值,这样一来就违背了物理规律。

当然我们也可以简单粗暴地直接提升每像素发射光线的数量来减缓 outlier 的出现频率,但对于实时光追来说这是极其昂贵的。就算是赛博朋克 2077 的超速光追,也只是达到了 2 spp 的数量级,然而这已经是游戏领域里最高的了。

然后我们来讲一讲时间上的滤波。刚刚讲了这么多,你应该能发现我们一直围绕着空间的角度来展开降噪的。单有空间信息的效果是肯定不够的,我们还要时间维度上的。

所以,我们现在就进入时间滤波(temporal filtering)了,并且结合空间滤波(spatial filtering)来理解我们现在已经应用的时空滤波(spatiotemporal)的降噪方法。

首先,要做时空图像信号的滤波,我们要明确一个很重要的概念叫 “复用”(reuse),为什么呢?因为在实时渲染里,每秒都要渲染几十上百帧,细分到时间轴上,每相邻两帧的变化往往不大,所以有很多信息是可以下一帧直接拿来用的。

所以这里有一个很重要的概念,叫做运动矢量(motion vector),它描述了场景内容的变动情况,也就是说我们可以通过运动矢量来找到上一帧的位置信息。

这里我们使用 BackProjection 方法来寻找运动矢量,将第 N 帧着色点的屏幕空间坐标转到世界空间,然后再把第 N-1 帧的世界空间坐标转到屏幕空间上来,这样就得到了运动矢量。

P.S. 如果可以在 G-Buffer 里直接拿世界空间坐标的话那就不用转换了。物体运动时注意做一遍逆矩阵。

好了,拿到运动矢量了,可以做时间性的降噪了。怎么降呢?对了,刚刚提到了复用,那么我们就可以复用上一帧已经降噪过的信息来做线性插值了,而运动矢量在这里的用处就是提供复用帧信息的 “指导”。

我们在前面定义了:带有噪点的图像 %5Ctilde%7BC%7D%20,这个作为降噪的输入数据,算法方面定义一个滤波核 K,最终图像为 %5Cbar%7BC%7D%20%20

则空间上的降噪可以表示为:

%5Cbar%7BC%7D%5E%7BN%7D%3Df(%5Ctilde%7BC%7D%5E%7BN%7D%20)%20

空间上降噪的具体办法,我们已经花了大篇幅来讨论了。接下来就是叠加上时间维度的东西了,则时空上的降噪可以表示为:

%5Cbar%7BC%7D%5E%7BN%7D%3D%20%5Calpha%20%20%5Cbar%7BC%7D%5E%7BN%7D%20%2B(1-%20%5Calpha%20)%20%5Cbar%7BC%7D%5E%7B(N-1)%7D

通常情况下,插值因子 %5Calpha%20%5Cin%20%5B0.1%2C0.2%5D

但是又引出了新的问题,例如快速转动视角导致的颜色信息不连续,遮挡位移导致出现上一帧不存在的颜色信息等等。这时候盲目地做叠加就会产生各种 artifact 了。

遮挡位移产生的鬼影

所以我们要做一个很重要的工作,叫做 Temporal Clamping(不知道怎么翻译)

回到这个表达式:%5Cbar%7BC%7D%5E%7BN%7D%3D%20%5Calpha%20%20%5Cbar%7BC%7D%5E%7BN%7D%20%2B(1-%20%5Calpha%20)%20%5Cbar%7BC%7D%5E%7B(N-1)%7D 上来,%5Cbar%7BC%7D%5E%7B(N-1)%7D 是上一帧的信息,我们没有做任何处理。

实际情况下,上一帧的部分信息和下一帧可能截然不同,所以我们必须进行调整。

如果颜色差异过大,那么就把 %5Cbar%7BC%7D%5E%7B(N-1)%7D  给 clamp 到 %5B%5Cmu%20-%20k%20%5Csigma%2C%20%5Cmu%20%2B%20k%20%5Csigma%5D 的范围来,这个值域在前文消减 outlier 的方法也提到过,它代表着当前帧的范围。

不过 Temporal Clamping 是一种需要考虑权衡的做法,因为这里其实就需要考虑要保留更多鬼影还是更多噪点,如果鬼影少,那么噪点就明显,反之亦然。



到这里,我们的实时光线追踪降噪的基本原理就差不多结束了。接着我们再来看工业界常用的 SVGF,目前所有光追游戏都在使用它(或类似它的算法)来降噪。

SVGF 全名为 Spatiotemporal Variance-Guided Filtering;顾名思义,它是一种在时空滤波的基础上对降噪算法做优化。下图是 SVGF 的算法目标和要求,来自 NVIDIA 研究科学家,也是这篇论文的合著者之一 Edward (Shiqiu) Liu 的一篇知乎文章(zhuanlan.zhihu.com/p/28288053)

和我们之前讨论的时空滤波不一样的是,SVGF 添加了方差信息作为引导。

基于 SVGF 降噪的光线追踪管线

SVGF 虽然使用了前文提到的双边滤波技术,但是它没有使用高斯核,我们之前也提到过核有很多种,不要求是完全遵循正态分布,只要是个逐渐衰减的模型都可以,比如 f(x)%3D%5Ccos%20x也可以拿来生成卷积核。

和之前我们讨论的普通时空滤波一样,SVGF 同样也使用了深度 (z-depth),法线 (normal),颜色 (luminance) 这三个信息来指导滤波。SVGF 最大的特点就藏在 V 这个字母里。V 就是 Variance(方差)的意思,SVGF 在颜色权重上做了方差估计。

w_%7Bz%7D%3D%5Cexp(-%5Cfrac%7B%5Cvert%20z(p)-z(q)%20%5Cvert%20%7D%7B%5Csigma_%7Bz%7D%20%5Cvert%20%5Cnabla%20z(p)%5Ccdot%20(p-q)%2B%20%5Cvarepsilon%20%20%5Cvert%20%7D%20)%20

不难看出,它使用了 %5Cvert%20z(p)-z(q)%20%5Cvert 来判断 p%2Cq 两点的深度差,权重值随着深度差值的增大而减小,并且符合一个逐渐衰减的模型。衰减系数 %5Csigma_z 控制着衰减的大小,而 %5Cvarepsilon%20 是为了防止 %5Csigma_%7Bz%7D%20%5Cvert%20%5Cnabla%20z(p)%5Ccdot%20(p-q)%20%5Cvert%20%3D0 而存在的一个很小的数。

接下来则是考虑法线:

w_%7Bn%7D%20%3D%20%5Cmax%20(0%2C%5Cvec%7Bn_%7Bp%7D%7D%20%5Ccdot%20%5Cvec%7Bn_%7Bq%7D%7D%20)%5E%7B%5Csigma_%7Bn%7D%7D

根据我们高中就学习过的向量点乘知识,这显然是一个余弦函数的衰减模型。你看,没有用高斯分布模型吧。其中 %5Csigma_n 也是一个衰减系数。

最后就是颜色方面的处理了。之前说到传统的联合双边滤波,它是通过直接比颜色灰度值来确定差异的。这个方法不准确,因为图像本来存在很多噪声,一些比较亮或者比较暗的,不太正常的像素会导致权重值出现大的偏差。

所以 SVGF 在这里就做了方差估计:

w_%7Bl%7D%20%3D%20%5Cexp%20(-%20%5Cfrac%7B%5Cvert%20l_%7Bi%7D(p)%20-%20l_%7Bi%7D(q)%20%5Cvert%20%7D%7B%5Csigma_%7Bl%7D%20%5Csqrt%7Bg_%7B3%20%5Ctimes%203%7D%20(Var(l_%7Bi%7D(p)))%2B%20%5Cvarepsilon%20%7D%20%20%7D)

首先在空间上计算 7%20%5Ctimes%207 的方差,就像我们之前消减 outlier 那样做;然后再在时间上利用运动矢量再来求个 7%20%5Ctimes%207 的方差,最后再在空间上求另一个 3%5Ctimes%203 的方差,最后开平方得出标准差。

这样一通操作下来,我们就能得到一个比较准确的标准差了,相对于传统双边滤波去直接比灰度值要靠谱不少。这一套求方差组合拳的主要作用就是能较为准确地确定两点间的贡献关系,举个例子,如果这里的标准差越大,就说明噪声越严重,一般在处于阴影的地方比较常见,那么就可以确定它不该贡献到那些被更多的光照射的,或者比较亮的地方。

从左到右:1spp 输入图像,4096 spp 参考图像(Ground Truth),SVGF 降噪图像,传统双边滤波图像。可以看出 SVGF 比较接近参考图像了。

但是 SVGF 也有一个致命问题,那就是运动场景适配不完善。尤其是对 glossy 材质的反射表面,着色延迟以及细节缺失问题相当严重。

因为 SVGF 依赖于运动矢量,而像阴影,半透明等着色信息是没法生成运动矢量的,所以会造成比较严重的视觉滞后。不过在 NVIDIA RTX 时期,SVGF 的实现已经被大幅优化,至少现在的光追游戏不会看到像这样的 artifact(评论区有 NV 的大佬,表示近期的技术改进了置信度缓冲):

然而 SVGF 的方法仍然干掉了很多画面细节,这使得 NV 专门研究了一种叫 ReSTIR GI 的全局光照重采样算法来改善给输入降噪器的原始数据质量。

不过最近 NV 的降噪技术有了新的成果,也就是昨天 DLSS 3.5 Ray Reconstruction 的实现。它是经过 DGX 超级计算机进行 5 倍于 DLSS 3 训练算力的一个深度网络模型,并且运行在 Tensor 管线上。

它抛弃了时空滤波算法,而采用了深度学习,已经不是一条赛道上了的东西。

和 SVGF 相比,DLSS 3.5 使用训练好的深度神经网络来指导降噪。这让我想起了 FSR 1 和 DLSS 1 的关系,一个通过人为调整的固定算法做上采样,一个是基于深度学习的上采样。

并且 DLSS 3.5 的 Ray Reconstruction 是跑在 Tensor Core 这种特化电路上的,速度比在 CUDA 通用计算核心上跑的 SVGF 还要快一点,意外地提升了些许帧数。大概 10% 左右。

Rendering 的潜力快被挖干,现在是 AI 的天下了,老黄也开始在 SIGGRAPH 上卖起了计算卡。


References

[1]Kajiya, and  T. James . "The Rendering Equation." ACM Computer Graphics 20.4(1986):143-150.

[2] Schied, Christoph , et al. "Spatiotemporal variance-guided filtering: real-time reconstruction for path-traced global illumination." High Performance Graphics ACM, 2017.

[3] Ouyang, Y. , et al. "ReSTIR GI: Path Resampling for Real-Time Path Tracing." Computer Graphics Forum: Journal of the European Association for Computer Graphics 8(2021):40.

[4] Lingqi Yan, GAMES202 - Real-Time High Quality Rendering, Lecture 12/13 PDF.

[5] NVIDIA, https://www.nvidia.cn/geforce/news/nvidia-dlss-3-5-ray-reconstruction/, website.

蒙特卡洛光线追踪基础 - 实时光线追踪的降噪的评论 (共 条)

分享到微博请遵守国家法律