内容参考闫令琪课程《games202-高质量实时渲染及作业5》、“202作业5代码模板”、花桑博客
实现效果
降噪原理
整个过程使用了两种降噪手段 + 1种简化加速手段
- 联合双边滤波对单帧图片降噪
- 基于A-Trous Wavelet加速
- 基于两帧之间滤波,也常称为时域抗锯齿(鼎鼎大名的TAA,虚幻中也用到了类似的实现)
双边滤波
普通的高斯模糊是对每个像素无差别的求平均,整张图都模糊掉了
双边滤波考虑了图像像素的变化,有差别的模糊,在图像特征的边界处模糊的较低
联合双边滤波就更厉害了,不光考虑像素的突变,还用到了3D空间的法向量、像素的3D坐标信息,过滤的就更精准了
这里我们使用的联合滤波核定义如下,考虑了4个权重因子:
- 像素距离
- 像素颜色
- 法线夹角
- 是否处于同一平面
其中:
C ~ \widetilde{C} C 为有噪声的输入图像, D n o r m a l D_{normal} Dnormal为两法线夹角, D p l a n e D_{plane} Dplane为深度差值指标。
基于A-Trous Wavelet加速
卷积滤波加速常见的有两种方式
- 2D的高斯滤波,可以拆分成两次1维的高斯滤波
- 以固定大小的滤波器多次滤波,每次增大滤波采样间隔
A-Trous Wavelet加速就是基于第2种方式来加速
假如滤波器大小为5 * 5,迭代三次,步长以2的倍数增长,以近似 1 6 2 16^2 162的滤波核。
- 第一次间隔为0,以当前点为中心采样 5 * 5个点,做累加
- 第二次滤波间隔为2,以当前点为中心采样 5 * 5个点,继续累加
- 第二次滤波间隔为4,以当前点为中心采样 5 * 5个点,继续累加
实际进行了5 * 5 * 3 = 75次采样,远小于 16 * 16 = 256
参考下图来理解每次采样,将三次采样的点全都累加起来求平均
基于A-Trous Wavelet滤波
分几步
1)两帧之间的投影,要将当前点投影到前一帧的图片上,找到对应的点,将当前点做反向的Model变换,还原到初始坐标,然后乘以前一帧的MVP变换,就找到了前一帧相同点的像素
$Screen_{i-1} = P_{i-1}V_{i-1}M_{i-1}M_{i}^{-1}World_{i}
$
2)特殊case判断
- 判断该点在上一帧时是否在图像内
- 和上一帧该坐标相同点是否对应同一个物体(有可能某一帧中,物体移动造成遮挡了)
3)两帧图像做混合
混合时要将颜色clamp到合理的范围内,避免噪点
核心代码说明
工程基于C++实现,可以使用CLion、Vscode、sublime,核心代码在denoiser.cpp中
开始是在Mac上跑,libomp的引用有问题,找不到该库,可能是Mac端xcode自带的clang有问题,不支持libomp,放到ubuntu系统的台式机上跑OK了
代码参考 这位博主的实现已经很好了。
https://github.com/DrFlower/GAMES_101_202_Homework/tree/main/Homework_202/Assignment5