实时光线追踪
现在RTX的能力,大约是在每一帧,能提供1 sample per pixel (SPP)
也就是每个pixel有以下几部分:
- primary ray用光栅化代替
- secondary ray一条
- 两条与光源的连线
![image]()
1 SPP就导致了光线追踪的结果非常noisy,所以实时光线追踪的关键就在于denoising
Spatial Filtering
Joint Bilateral Filtering
一个Filtering的伪代码如下,其中\(G\)是我们假设使用Gaussian Function来做的卷积核

但是Gaussian Function会把高频信息过滤掉,使得物体轮廓模糊
我们一般使用Joint Bilateral Filtering来既将物体轮廓保留,又使得物体内部模糊以去掉噪点

我们在第一步光栅化时,可以利用Geometry Buffer得到图像各种信息
我们可以分别利用各个信息,每个信息根据Gaussian Function或者其他函数做一个信息的值相差的越远,权值越小的卷积核
然后再将各个卷积核合在一起
下图中\(w\)是卷积核中(k, l)像素对(i, j)像素的影响(卷积核权值)
指数中左半部分,是一个根据像素距离做的高斯分布;
右半部分是根据某个信息\(I\)做的高斯分布
合在一起就成了由多个信息共同调控的卷积核

比如在遇到物体轮廓时,分在轮廓两边的两个像素,因为颜色(选择的I)相差比较远,而\(w\)比较小,不会被卷积到一块,轮廓得以保留
如下图,如果我们想要保留轮廓
我们可以采用一个同时受depth, normal, color影响的卷积核
点A和点B可以用depth区分出来;B和C可以用normal区分;D和E可以用color区分

加速卷积
对于每一个像素,做一次卷积都是\(N^2\)的操作,比较耗时
有如下的加速方式
拆分卷积核
把卷积核拆成两个一维的卷积核,先给x上做一次卷积,再给y上做一次卷积


但不是所有卷积核都能这样拆开,我们通常认为比较小的卷积核,e.g. 32x32
可以被拆开而不会产生过多问题
a-trous wavelet
把一个大的卷积,拆成多次小的卷积,每次卷积采样点间的距离逐渐增加,最终整个卷积范围变得像原大卷积核一样大

比如上图中,64 x 64的卷积核我们可以转换为用5 x 5的卷积核做五次,最后一次每个采样点之间距离为4x4,整个卷积范围就是64 x 64
Outlier Removal
有时实时光线追踪得到的图中有一些噪点会过分的亮,这种噪点叫做outlier
这种我们不能通过filter来去掉,因为可能会导致噪点附近整片区域都变亮

我们采用的方法是clamping,对每个像素,都检查它附近一个小区域,计算该区域的均值\(\mu\)和方差\(\delta\)
把该区域内所有值都clamp到\([\mu - k\delta, \mu + k\delta]\)(k自定义)范围内,outlier就可以被消除了
注意光源也会被消除掉,要特殊处理
Temporal Denoising
算法
Temporal Denoising的方法就是,对于当前帧的一个像素,找到该像素在上一帧对应的像素,然后将当前值和上一帧值做插值,即可denoising
找到当前像素之前对应的像素,叫做back projection

back projection有两种方法
- 把world coordinate存在geometry buffer中,然后根据物体该帧做的变化,倒推回去即可
- 把当前screen space coordinate,做MVP+视口变换的逆变换,回到world coordinate,然后根据物体该帧做的变化,也做逆变换,回到上一帧对应的world coordinate(Z值需要z-buffer存储),然后再做MVP+视口变换,得到上一帧的screen space coordinate
用横线代表denoising后的结果,波浪线~代表denoising前的结果
整体步骤就是,先给当前帧结果做spatial denoising,然后和上一帧结果做插值,\(\alpha\)一般取0.1~0.2,也就是大部分结果来自上一帧

存在问题
存在问题的关键就在于对过去帧的复用不一定准确,以下问题是一些例子
- 对第一次出现在屏幕上的物体,没有过去帧提供信息,导致第一帧要不噪声大,要不渲染缓慢
- 有时候back projection虽然找到了对应的像素,但其实要找的像素被遮挡住了,我们却使用了靠前的物体,导致渲染结果不对
![image]()
这种情况下,可以使用类似outlier removal中的方法,对\(\bar{C}(i)\)附近区域求一个均值\(\mu\)和方差\(\delta\),把\(C(i-1)\)clamp到\([\mu - k\delta, \mu + k\delta]\)(k自定义)
这样尽量避免完全不合理的temporal复用
![image]()




浙公网安备 33010602011771号