Real-time Ray Tracing
RTX是一种硬件架构,能够更方便的追踪光线。每秒能处理10G的光线(指一个像素的样本,sample per pixel),但并不是全程算力都在处理光线,还会做降噪等工作。所以在RTRT中,我们只能做到1SPP的光追精度。
RTRT在做什么:阴影、反射和镜面反射、环境光遮蔽、全局光照(光线追踪适合做的事)
RTX处理的反射情况非常多,因为glossy的表面更容易做RTRT,diffuse倒更复杂
RTRT
基本是路径追踪算法(path tracing)的简化,本身的突破是因为硬件能力增加,关键技术是降噪。
最简单的情况:是一条光路的样本(1SPP):
包括1次着色点光栅化(从相机像素出发的光线击中的交点)+
1条着色点光源的可见性光线(着色点到光源连接,采样光源并判断遮挡)+
1条二次弹射的间接光照(根据着色点的材质采样出一个方向,发射光线,击中的表面是次级光源,计算次级光源对着色点的影响)+
二级光源到光源的可见性测试光线(二次光源与光源连接判断遮挡)
路径追踪是基于蒙特卡洛积分的方法,本身会产生噪声,采样的样本越多噪声越小,RTRT使用了1SPP的方法,会产生非常大的噪声。所以RTRT的核心技术是降噪,如何从噪声图生成清晰的图。
降噪目的是:在1SPP的前提下,进行降噪,达到画面质量要求(没有过模糊,没有artifacts,保留了所有细节),并高效处理。
使用切边滤波系列(SF,AAF,FSF,MAAF)、离线滤波方法(IPP,BM3D,APR)、深度学习,等降噪方法对RTRT降噪不可能。
G-buffer
G-buffer:几何缓冲区:在渲染的过程中获得的免费的屏幕空间信息,比如逐像素深度、法线、世界坐标、直接光照结果、反照率kd等等。是屏幕空间的信息。也可以都各自保存进gbuffer中,方便后续使用。
RTRT时域滤波方法
是工业界常用的解决方法。关键思路:假设前一帧被降噪完毕,并假设帧与帧间的连续性。使用motion vector寻找前一帧的位置,将前一帧的结果复用。相当于增加了SPP。
motion vector:描述了屏幕空间中的物体在帧与帧之间运动的相对位置(上一帧像素对应的片元,与下一帧该片元对应的像素位置的相对移动)
RTRT时域滤波的方法:
- 先对当前帧做简单的滤波处理(后面讲)
-
获得两帧之间内容的motion vector,也就是找到两帧之间的内容的位置的对应关系。
- 获得像素
所对应的片元
- 每一帧生成G-buffer,保存这一帧的世界坐标,然后取
其对应的世界坐标
- 想要得知
上一帧的位置,可以看作上一帧的位置经过了变换
得到了这一帧的位置,那么对这一帧的位置应用逆变换
,就能得到上一帧的位置。(BackProjection下文讲)
- 获得像素
- 将当前帧和上一帧的结果线性混合
时域滤波.png
Back Projection
要找到当前帧某一像素的内容,对应上一帧哪个像素,Back Projection就是求解motion vector的方法。
- 首先要求出这个点的世界坐标(如果保存了G-buffer可以直接取值用;如果没有保存,通过逆视口变换、逆VP变换得到)。
- 如果两个帧间物体发生了移动,则当然应该拥有移动变换矩阵,将这一帧的世界坐标乘逆变换矩阵,从而得到上一帧这个点的世界坐标(如果物体没有移动,那么就失效)。
- 将上一帧的世界坐标经VP和视口变换得到上一帧的像素位置。从而得到motion vector。
时域滤波的问题:
- 镜头的第一帧,或光源突变的情况无法处理。
- 屏幕空间信息不足:比如屏幕外的点进入了屏幕内(由于时域滤波基于屏幕空间)
- 被遮挡的物体突然出现(本质还是屏幕空间问题)
- 由于世界空间几何位置没有变化(从而motion vector没有变化),导致阴影、反射等滞后的现象。
解决方法:主要是clamping和detection。
- clamping:将前一帧的结果“拉近”当前帧,再做混合,可以削弱两帧差异过大的情况下,前一帧对当前帧的影响。
- detection:我们可以检测是否使用上一帧的结果。比如可以判断前后两帧motion vector对应的像素对应的物体是否为一个物体,从而决定是否使用上一帧的结果。这时使不使用前一帧就变成了非0即1的问题。当是同一物体时,我们才使用插值系数
。
空间域滤波的方法
上文介绍了如何实现时域滤波,在时域滤波前我们会对1SPP的图像进行一次空间域的滤波,这次空间与的滤波可以有效地把原图降噪。
空间域滤波最常用的方法是使用基于距离的高斯滤波核进行滤波。这种滤波考虑的部分大概是范围内对中心像素有贡献。
而一般情况下,我们使用基于距离的高斯滤波核对充满蒙特卡洛积分得来的噪声的原图进行滤波时,会使图像均匀变糊,也就是损失了有用的高频信息。
我们在对原图进行滤波时,要首先明确:不是所有的高频信息就全是噪声,当然也不是低频信息中就没有噪声。于是我们需要保留有用的高频信息。
双边滤波(Bilateral Filtering)
双边滤波基于一个观察:当此处颜色变化非常剧烈,我们认为是边界。
所以双边滤波的思路是:找到一个保留边界的方法——如果像素与像素
的颜色差异非常大,就让像素
贡献少一些;仅仅向滤波核添加一些控制的方法就可得到。
双边滤波在对两个像素
这是一个很直观的判断,仅仅向滤波核添加了关于颜色差异控制的方法就可得到结果。因为双边滤波将颜色变化剧烈的位置认为成边界,然而事实上,颜色差异的剧烈不能区分两点是在边界还是噪声,这是双边滤波的固有问题。
联合双边滤波(Joint Bilateral filtering)
我们可以看到:高斯滤波提出了一个滤波标准,即两像素之间的距离;双边滤波提出了两个滤波标准,即像素位置距离和颜色距离;那么我们也可以使用更多的特征来帮助滤波。由此而提出的联合双边滤波是非常适用于RTRT下的滤波。
使用G-buffer,作为新的标准帮助滤波。因为G-buffer是完全没有噪声的,G-buffer在光栅化过程中生成,和光线多次弹射无关。联合双边滤波还可以考虑其他的标准,每一个标准的σ和μ都可以单独考虑,滤波的阈值(多大距离算大)也可以主观设置
例如下图中:AB之间深度差距过大,BC间法线差距过大,DE间颜色差距过大
还有一个问题:我们滤波过程中所用的滤波核是NxN大小的,对于每个着色点的滤波都要遍历它NxN范围内的邻居,开销很大。对于小滤波核来说可以接受,但是对于大滤波核,开销巨大。
对于大滤波核有两种加速滤波的办法:
-
将2维高斯核拆分成一次1维的水平滤波和一次1维的垂直滤波。因为二维高斯滤波在数学定义上是水平垂直两次1维高斯滤波叠加而成的,本身就是可拆分的。这样我们只需要访问2xN次纹理,即可计算出NxN区域内的滤波结果。
注意:只适用于高斯滤波的情况下,其他种类的联合双边滤波滤波核过于复杂,不容易分离成水平和竖直两次滤波。
2维高斯滤波.png -
逐步增长滤波步长。举例方法:a-trous wavelet:是多pass的方式,每个pass对每个像素都滤波,但是样本间隔增加。
增长滤波步长.png
在上图例子中,我们需要计算用大小为64x64的滤波核滤波后的结果,最初使用5x5的滤波核,在5个Pass中,每个Pass逐次增加采样间隔,在第Pass时,采样间隔为
(每个Pass增加
,也就是说第1Pass比第0Pass间隔增加了
,第2Pass比第1Pass间隔增加了
,第3Pass比第2Pass间隔增加了
)。这样到第5个Pass时,采样间隔为15,采样跨度为
,正好和64x64大小的滤波核大小相同。而我们一共查询了555次纹理,相比于64*64要节省很多。
Outlier Removal(移除噪点,Outlier指亮度极其高的噪点)
由于outlier的亮度会非常大,导致滤波后它的亮度会贡献到周围点,形成块状亮斑,所以要在滤波前将outlier检测并剔除。但是由于outlier的结果也是合理的,剔除outlier导致能量不守恒,但是RTRT领域为了效率只能这样做。
检测Outlier:对于任何像素,取它周围7x7的范围,计算范围内的均值/方差/中位等(自己设计),在有效范围以外则可以记为outlier。
Outlier检测出来后,我们可以把Outlier clamp到接近的范围,如
Spatiotemporal Variance-Guided Filter(SVGF,时空差异引导滤波)
在讲述高斯滤波和双边滤波时提到,我们需要判断高频信息属于噪声还是图像信息,保留有用的高频信息。
SVGF与在时空上降噪的方法差不多,SVGF增加了偏差分析和其他的技巧。
主要思想:SVGF是一种联合双边滤波
它通过三个因素指导滤波:
-
深度:考虑两点的深度差异对滤波的影响,当然是深度差异越小,滤波贡献越大。但是不能单纯只考虑深度,要联合考虑二者法线差异和深度差异,如果是同一平面但深度不同的点,考虑沿平面的深度差距。
SVGFDepth.png
在图中展示的A与B点,在同一个平面上,颜色也相近,所以理论上A和B会相互贡献不少权值。但由于A与B有很大深度差异,如果用深度判断的话,会判定A和B不会有很大的贡献。这产生了矛盾,所以我们不能简单地用深度来判断贡献值,我们需要考虑A和B沿平面方向上的深度变化。
在深度权重公式中,我们联合考虑了两点深度和平面梯度的关系,由于公式中是的形式,所以差异越大,贡献越小。
-
法线:
我们考虑两点法线的差异,我们用两个点法线向量求一个点积,由于求出来的值有可能是负值,因此使用把负的值给clamp到0。而
是为了更突出法线变化,放大法线变化效果。
注意:如果使用法线贴图,使用法线贴图变换前的法线。
SVGFNormal.png -
亮度(两点颜色间的灰度差距)
任意两点间我们考虑它们的颜色差异,如果颜色差异过大,则认为两点位置靠近边界,此时A和B的贡献不应该过大。
但是由于噪声的存在会出现一些干扰,也就是B点虽然在阴影里,但是可能刚好选择的点是一个噪声,导致B点比较亮,同时A不在阴影里也很亮,那么A和B亮度差异小,就会互相贡献,但是这样是错误的现象。这时就需要SVGF中Variance发挥作用。
SVGFLuminance.png
方差的计算:1. 计算需要滤波的点7x7范围内的方差 2. 按时域的方法,通过motion vector计算上一帧对应像素的方差,并计算平均(相当于按时域滤波了,将方差变得时域上平滑) 3. 再在周围3x3的区域内做空间的平均滤波
Recurrent denoising AutoEncoder(RAE,循环降噪自动编码器)
通过循环神经网络在时域上,基于Gbuffer和1SPP的渲染图,从而计算降噪的渲染图。