Games202笔记——Real-time-Global-Illumination(2)

屏幕空间中的全局光照

Screen Space Ambient Occlusion(SSAO)

大名鼎鼎的SSAO,游戏设置的常客,crytek出品,画质有保障(误)

屏幕空间指所有的信息均来自屏幕

SSAO有以下假设:

1.我们不知道间接光照是什么,但假设间接光照是一个常数。

熟悉吗?这实际上就是blin-phong模型的假设。

2.不是所有方向都能接收到全局光照

3.认为所有物体都diffuse

还记得我们第一节课说的近似相等吗?

那时候我们就说这个东西AO会用,现在是时候伏笔回收了。

说起来前面这项是不是错了啊?为什么上下都多了个$\cos{\theta_i}$?

那是因为$\cos{\theta_i}d\omega_i$本身是一个有明确定义的微元,如下

image-20210516174819240

所以这么拆也是对的

来看左边,分母实际上是定值$\pi$(算不出来的自行把$d\omega_i$拆成$d\theta d\phi$在正半球上二重积分),我们可以把这个式子记作Ambient项$k_A$,则有

再看左项,对于全局光照来说$L_i$是一个常数,对于diffuse的BRDF也是个常数,所以这一项简直是白给,化简后可得$L_i^{indir}(p)·\rho$

全局光照你随便定一个颜色就好,BRDF的albedo你也随便定一个颜色就好,所以右边突出一个随便定

重要的是$k_A$

在屏幕空间我们怎么求得visibility?

第一个假设:我们在着色点周围随机撒一些点,判断这些点哪些在物体里面,哪些在物体外面

第二个假设:只要一个点的深度大于深度图记录的最小深度,我们就认为它在物体里面

如图所示

image-20210516175925249

你可能觉得这难道不应该在半球上考虑吗?与法线方向相反的半球有什么用?

问得好,但是当时我们还不能在屏幕空间上获得物体的法线信息,所以这里我们再次认为:只有被遮挡的点来到了一半以上,才开始考虑AO的问题

我们就可以用这种方法近似visibility项

有采样就有噪声,有噪声就有降噪,懂得都懂

现在我们可以获得法线信息了,自然会指采样半球,这种改进方法叫做HBAO(Horizon based ambient occlusion),且这种方法只考虑一定范围内的遮挡关系,不会有SSAO里面一些奇奇怪怪的遮挡

Screen Space Directional Occlusion(SSDO)

SSDO是对于SSAO的提高,比起SSAO仅考虑环境光是常量,SSDO可以结合RSM考虑环境光

SSDO的实现和path tracing非常类似

1.对于着色点p,发射一根随机射线

2.如果射线没有打到障碍物,进行直接光照,反之进行间接光照

相比SSAO,SSDO做了完全相反的假设,SSAO认为物体被遮挡时无法接受到环境光照,而SSDO认为物体被遮挡是才接受环境光照,也就是说,SSAO假设环境光来自非常远的地方,SSDO假设环境光来自非常近的地方

但凡是渲染我们肯定要解渲染方程

把方程拆成可见和不可见两部分,则

我们关心第二部分

你用RSM也好,其它方法也好,一个点对着色点p的环境光贡献一定是可计算的,核心是怎么做遮挡的查询。

我们仍然不想做射线trace,太慢了,这里我们仍然使用HBAO的撒点方法。

SSDO是比较轻量级的算法,工业界应用广泛

但是它仍然无法逃离一个问题:只要是我看不见的,我什么都不知道,且只能处理小范围GI

SSR(Screen Space Reflection)

SSR同样是屏幕空间的全局光照技术,但是它是真的在屏幕空间做光线追踪。

SSR的关键在于反射,我们要想知道一个点的反射信息,我们先要知道它都能反射什么,一个基于现实的观察是:反射的东西大多都能在屏幕空间显示出来。

image-20210517155244867

基本的SSR便是基于屏幕空间已经渲染出来的东西做的镜面反射

具体是怎么做的?

首先我们可以从屏幕空间射出一道光,根据法线和深度信息,可以做出一次反射,反射出一根(视场景粗糙度等而定,可能有多根)我们关心这道反射之后的光会和场景交于哪个点。

最简单的考量就是我每次对于光线取一个步长往前查询,如果查询到深度比场景深度深,则发生了相交,如图

image-20210517160019036

问题是步长该有多大,甚至来说如果能动态决定就更好了

还真的有动态决定的方法。

还记得MIPMAP吗?我们先对场景深度做MIPMAP,不同的是MIPMAP上一个像素不再记录上一层几个像素的平均深度,而是深度的最小值。

这个加速结构就像path tracing里的层次结构一样,如果我连底层极深度最小的都碰不到,我怎么可能碰到这个层级这个像素覆盖到的所有像素呢?这东西本质是一个bbox。

所以查询的方法就是:首先查询一个深度,如果没有碰到,那么加大MIPMAP层级,继续查询(步子更大),如果碰到了,减小MIPMAP层数(步子变小)

这样我们就实现了trace

具体的着色怎么办?其实我们完全可以把path tracing的方法拿来用(都是光追谁看不起谁)

SSR是很好的实现屏幕空间反射的方法,当然它也有一些问题,集中在屏幕空间这一点,蒙特卡洛方法什么的都好

比如下面这个

image-20210517161833176

这个方法可以快速做glossy和specular的反射,这也是为什么很多以前的游戏看起来画面那么油(不diffuse,快)

欢迎关注我的其它发布渠道