实时渲染里面的 GI,其实就是比直接光照多一次 bounce 的间接光照。
一切被直接光照照射的物体,又可以作为光源照亮其他物体,我们把这些叫做 secondary light source(次级光源)。
我们high level地分为两步:哪些地方可以被光源直接照亮当作次级光源;这些次级光源对点p的贡献怎么求。我们为了简化,假设次级光源都是diffuse的但是p不一定是diffuse的(Any reflector is diffuse,反射物是diffuse的,接受物不一定)。
对于第一个问题(哪些地方可以被光源直接照亮当作次级光源),可以用 shadow map 去找,shadow map对应的每一个像素就是一个次级光源。
于是我们知道了,哪些地方是次级光源,且反射出去的能量是多少。
但是这里比较难的是,visibility不好算(次级光源q到p的可见性),于是就不算了…
人们还有一些trick,比如每次对shading point,我们不希望完整地跑一遍 shadow map 来算次级光源的影响,我们于是把这个shading point直接投影到shadow map下,然后仅采样它周围的像素认为是临近的像素。
核心问题:可以求出对任意一个 shading point,一个次级光源对他的 radiance 值。
假设:Radiance 在传播的过程中是不变的(像之前的path tracing里面也有这样的假设)。
具体做法:
问题:
格子精度不够,场景遮挡信息不能很好的体现,就容易漏光(Light leaking,比如照亮自己的背面)
和之前不一样的地方:
确定次级光源不再用 RSM 那样的像素,而是变成了体素;
最后求radiance是直接从相机出发,打到对应物体,根据物体的材质做一次 cone tracing。
具体做法:
如果是 diffuse 的就用大概八个圆锥就可以覆盖了:
环境光遮蔽就是对全局光照的一种近似。
对任意一个shading point,我们大胆假设它的间接光照是一个常数。但是我们这里要考虑这个shading point的visibility function,即它不见得可以接收到这个间接光。
补充:在一些三维渲染软件里面,即离线里面,也有这种东西。就像拿个模型用全白的环境光去渲染直接光,这种也叫做天光(看起来就和AO一样):
我们拆分一下渲染方程,单独把visibility项拆出来(下图右边的ρ是diffuse的albedo):
我们这里在蓝框式子里同时弄了一个cos θ,其实是在一个单位圆上做了一个积分(projected solid angle积分):
不过 SSAO 其实远远没有那么复杂:
前面只是便于理解:除以一个归一化的pai,其实相当于从shading point 从四面八方看得到的visibility的平均结果。
那么理论有了,实际上做我们并不是Tracy光线去看是否被遮挡,我们的SSAO做了一个假设,最后我们只需要做采样:
在shading point往周围撒一些采样点,然后往深度缓冲采样,如果撒的点的深度大于深度缓冲的值则是被遮挡住的(当然我们和rendering equation一样,只需要考虑法线所在的半球)
(有法线的情况叫 HBAO)
AO 不能 color bleeding,DO 是更精准得到全局光照的信息的方法。
SSDO 更 path tracing 有点像:
如上图,很有趣的是,AO和DO是完全相反的两种假设:AO认为红色圈是有间接光的,黄色圈是被遮挡的没有间接光的;而DO认为红色圈直接打出去了接收到的是直接光而不会有间接光,黄色圈才可能接收到间接光。(当然这两种都不完全正确)
和 HBAO 类似,也是在半球上撒一些点,然后和相机方向的深度去做判断来看是否遮挡(下图最右边的A点就是假设不正确的例子):
仍然是一种实时渲染中实现全局光照的方式。(闫老师认为应该叫 Screen Space Ray Tracing)
因为Screen Space得到的其实就是场景面向摄像机最外围的一层壳。我们有两个主要任务:
这里的步长,因为没有 sdf 信息,我们只能设一个定值每次march,但是这里我们可以动态决定步长是多少:
如上图,比如我们按照像素划分出这样一格一格来,我们希望可以知道一次走几格。我们先拿场景深度做一个mipmap,但是这里的mipmap比较特别,我上一层像素是下一层四个像素的最小值而不是平均值:
那么如果一个光线和上层的像素都不能相交,那么下层的像素只可能更深,就更不可能相交了。于是这样我们就可以快速跳过很多格子。(可以用试探步,这次没相交下次步子就更大,相交了就退回来再把步子放小)