文章目录
- Lecture 7 Real-time Global Illumination (in 3D)
- RSM (Reflective Shadow Maps)
- Lecture 8 Real-time Global Illumination (screen space)
- LPV (Light Propagation Volumes)
- VXGI (Voxel Global Illumination)
- SSAO (Screen Space Ambient Occlusion)
- Lecture 9 Real-Time Global Illumination (screen space cont.)
- SSDO (Screen Space Directional Occlusion)
- SSR (Screen Space Reflection)
Lecture 7 Real-time Global Illumination (in 3D)
实时渲染里面的 GI,其实就是比直接光照多一次 bounce 的间接光照。
一切被直接光照照射的物体,又可以作为光源照亮其他物体,我们把这些叫做 secondary light source(次级光源)。
我们high level地分为两步:哪些地方可以被光源直接照亮当作次级光源;这些次级光源对点p的贡献怎么求。我们为了简化,假设次级光源都是diffuse的但是p不一定是diffuse的(Any reflector is diffuse,反射物是diffuse的,接受物不一定)。
RSM (Reflective Shadow Maps)
对于第一个问题(哪些地方可以被光源直接照亮当作次级光源),可以用 shadow map 去找,shadow map对应的每一个像素就是一个次级光源。
于是我们知道了,哪些地方是次级光源,且反射出去的能量是多少。
但是这里比较难的是,visibility不好算(次级光源q到p的可见性),于是就不算了…
人们还有一些trick,比如每次对shading point,我们不希望完整地跑一遍 shadow map 来算次级光源的影响,我们于是把这个shading point直接投影到shadow map下,然后仅采样它周围的像素认为是临近的像素。
Lecture 8 Real-time Global Illumination (screen space)
LPV (Light Propagation Volumes)
核心问题:可以求出对任意一个 shading point,一个次级光源对他的 radiance 值。
假设:Radiance 在传播的过程中是不变的(像之前的path tracing里面也有这样的假设)。
具体做法:
- 用 RSM ,找到所有次级光源(被直接光照照亮的像素)
- 注入(Injection):把场景划分为格子(可以用3d纹理),次级光源换算到格子里,描述任意一个格子的radiance值,可以用二阶SH来描述他们的初始值
- 传播:每个格子传播到周围的六个格子里去,迭代至稳定(差不多迭代四五次就行)
- 此时知道整个场景任意一个格子的radiance值,于是对任意一个shading point确定它的格子就行,然后拿到radiance值再渲染
问题:
格子精度不够,场景遮挡信息不能很好的体现,就容易漏光(Light leaking,比如照亮自己的背面)
VXGI (Voxel Global Illumination)
和之前不一样的地方:
确定次级光源不再用 RSM 那样的像素,而是变成了体素;
最后求radiance是直接从相机出发,打到对应物体,根据物体的材质做一次 cone tracing。
具体做法:
- 体素化场景,并用加速结构做一个 hierarchy
- Pass 1 :记录相应体素的光源分布信息和用来反射出光线的那些表面的法线的分布。这样一来,我们有输入的直接光方向、反射的法线的大概范围(Lobe?根据材质算一下)
- Pass 2:实际渲染
最暴力的方法:判断一下相交的所有体素。 不过由于 cone 传播的时候会越来越大,所以我们可以简化一下,先算出周围的体素,然后在更大的层级上找就行了(毕竟已经建立了 hierarchy)。
如果是 diffuse 的就用大概八个圆锥就可以覆盖了:
SSAO (Screen Space Ambient Occlusion)
环境光遮蔽就是对全局光照的一种近似。
对任意一个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)
Lecture 9 Real-Time Global Illumination (screen space cont.)
SSDO (Screen Space Directional Occlusion)
AO 不能 color bleeding,DO 是更精准得到全局光照的信息的方法。
SSDO 更 path tracing 有点像:
如上图,很有趣的是,AO和DO是完全相反的两种假设:AO认为红色圈是有间接光的,黄色圈是被遮挡的没有间接光的;而DO认为红色圈直接打出去了接收到的是直接光而不会有间接光,黄色圈才可能接收到间接光。(当然这两种都不完全正确)
和 HBAO 类似,也是在半球上撒一些点,然后和相机方向的深度去做判断来看是否遮挡(下图最右边的A点就是假设不正确的例子):
SSR (Screen Space Reflection)
仍然是一种实时渲染中实现全局光照的方式。(闫老师认为应该叫 Screen Space Ray Tracing)
因为Screen Space得到的其实就是场景面向摄像机最外围的一层壳。我们有两个主要任务:
- 任意一根光线和这个壳相交的结果
- 求到交点了,相交的这个点对shading point的贡献
这里的步长,因为没有 sdf 信息,我们只能设一个定值每次march,但是这里我们可以动态决定步长是多少:
如上图,比如我们按照像素划分出这样一格一格来,我们希望可以知道一次走几格。我们先拿场景深度做一个mipmap,但是这里的mipmap比较特别,我上一层像素是下一层四个像素的最小值而不是平均值:
那么如果一个光线和上层的像素都不能相交,那么下层的像素只可能更深,就更不可能相交了。于是这样我们就可以快速跳过很多格子。(可以用试探步,这次没相交下次步子就更大,相交了就退回来再把步子放小)