快速收敛的Stochastic Screen Space Reflections
Stochastic Screen Space Reflections 旨在屏幕空间反射时,加入重要性采样的思想,根据反射表面的粗糙度计算表面法线的概率分布,得到一个锥形分布的反射光线。
主流做法有两种,一个是使用原有法线抖动反射光线 Jitter Ray(如下左图),一个是根据粗糙度抖动法线,进而得到抖动的反射光线 Jitter normal(如下右图)。
更加符合物理规律的当然是Jitter Normal的做法,因为物体微表面本身就是粗糙的,根据概率得到法线的分布,进而得到反射的方向,这是一个很自然的想法。
但Jitter normal的做法有个坏处就是不容易收敛,UE4中glossy表面发射了4根光线来做追踪,配合它强大的TAA才让SSR收敛。
在AMD的SSSR示例里,他们更是夸张的使用了一个巨大的Denoise库,共计使用8xRT 约100MB显存(1080p)来做Denoise。
EA的做法是Jitter Ray,因此他们可以使用RayResue的做法来重用Ray。
我当然是想按照Jitter Normal来做,并且也想像EA一样使用RayReuse,实现之前参考了两个库:https://github.com/Polish-Miko/GravityEngine 和https://github.com/haolange/Unity_ScreenSpaceLighting_Old 。
不过按照他们的做法,1 Ray 4 Resolve或者 1Ray 9 Resolve无论如何都没办法在高粗糙度收敛:
下方是0.3 roughness:
下方是0.5 roughness:
下方是0.7 roughness:
无论如何我都是做了双边滤波和时域滤波的,噪点应该是可以去除的。
观察上方图片,发现噪点随着粗糙度的增加而逐渐增多。
为什么会这样呢?因为前两个库的双边滤波都是用的一个固定尺寸的3x3 Box。
随着粗糙度增加, H的分布应该会更加的发散:
如下图所示:
对于低粗糙度物体,sample Box可能覆盖超过法线分布的区域,最终双边滤波出来会出现Blur,而更加粗糙的物理,应该使用更加大的sample Box,否则Sample Box 没办法覆盖完整的区域面积,Temporal累积时总会漏掉其余部分的贡献,就很容易出现noise。
所以正确的做法应该是让双边的Box随着Roughness变化而变化,最好是呈现一个Cone形状:
这里面应该有一个最佳的公式,但是好像直接用 roughness 乘上一个常数就可以得到不错的效果了: