Ambient Occlusion 环境光遮蔽
👓

Ambient Occlusion 环境光遮蔽

notion image
光场中表现了明显的明暗关系,这种关系和我们传统明暗关系不一样。它实际上是有个小凹槽就比较黑,凸起就亮,但渲染的时候比较难做到。因为这种结构比较小,因此叫做 micro structure (中尺度的结构)。
生活中可能不会注意得到,但是 AO 效果在游戏中是非常明显的。
notion image
notion image
我们大脑对光影明暗的变化是非常敏感的,我们可以根据这个构成 3D 视觉。
在游戏渲染很早期的时候,大家就意识到 AO 的重要性。
原理:对于表面的每一个点,在可看见的正半球面上,只有部分能看到天光,部分被周围的几何遮挡住了。
💡
如果把相机拉到足够远,那么 AO 表现的数学方程,和 BRDF 是非常接近的。所以说尺度是相对的,取决于相机的远近。
notion image

Precomputed AO

一开始我们的做法比较简单粗暴。比如我们做一个角色,这个角色在我们 Z-brush 雕刻高精度模型的时候,会有很多细节,例如皱纹、眼角。但是一旦将其转换成游戏里用的低精度模型,细节就会全部烘焙到法向上去,但是法向只是明暗变化,实际上不能告诉我们几何的变化。而且我们做渲染的时候,也不能做到当凹进去的时候,周围天光比较少的效果。因此很多建模软件都提供了 AO 烘焙的功能。如果烘焙成 AO 图,就是下图右边的那张。
这种预计算 AO 在游戏业十几年前就用起来了,效果非常好,直至今天还是不能被取代掉。
因为我们的 AO 计算都是基于有几何的。如果我们的表面没有那些小结构,就算是 real-time 的方法也是算不出来的。
notion image
💡
凡事不举,预计算,用空间换时间。
上面只能对一个一个的物体进行表达,当给一个环境的时候,就会发现不太行。

SSAO - Screen Space Ambient Occlusion

notion image

思想

我们一个相机渲染过去就是一个场景一个图像,图像有 rgba 还有深度信息。如果把每个深度信息连一起就是 Heightfield,就能得到几何,就能知道每个地方自遮挡的关系是什么样子的。

做法

从眼睛射出一道光线,交到三维空间物体的任何一个点,然后给定一个半径,在半径之间,在球形空间里面,随机撒若干个采样点,对于这些采样点再用相机去投射,从而得到深度。如果这个深度比 z-buffer 的深度还近,说明采样点是在可以看得见光的地方。如果更远,说明当前被绘制的几何给挡住。
💡
我们对游戏的整个世界有完整的几何表达,但是在做运算的时候,如果真的把上万个物体上百万的面片做各种几何运算,效率是非常低的。后来大家发现有深度了,就能得到一个局部采样的几何信息,这个几何信息就能做很多几何运算,Screen space 就是其中之一。 Screen space shadowmap, Screen space reflection, Screen space GI 都是从这个原始思想出来的。
采了 60 个点,如果只有 30 个点可见,说明大概有一半空间被挡住了,所以我的光强只有它的一半。因此方程很简单,N 个采样点,Occulusion 个采样点被挡住了,就能得到可以看见的光强:
思想是好的,但是方程可能是错的,因为一个面能接受光,实际上不是一个完整的球,是一个半球,如果用 N 去采样,那么大概率有一半个点是在下面的。平面是不应该有 AO 效果的,但是按这个方程得出的结果就是 1/2 光强。因此这个做法用的人少,大家都意识到是有问题的。有人加了 0.5,但这不重要,重要的是 Screen space 的想法:眼睛射出去的像素,对立体空间进行采样。
📖
最早期的 SSAO 算法,一运用,画面马上暗一半。

参考

SSAO+

我们发现只需要采样半球面,因此引入了 SSAO+。我们知道点的法向,因此只用采法向的半球。这样采样点少一半。
notion image
notion image
notion image
效果好一点,但这也是有问题的,例如画面中下的水泥墩,背后出现了很强的 AO 效果,这个效果其实是错误的,因为实际上离它已经很远了,但是屏幕空间没办法区分这个事情。因此还是会产生 Artifact,不应该会出现的重影。
HBAO 部分地解决了我们的问题。

HBAO - Horizon-based Ambient Occlusion

notion image
这部分可以参考 Games202。

思想

我们既然要求球面空间上的可见性,那么从点出发,朝各个方向去转,找光线能越过的邻居的几何,Pitch angle 仰角。如果周边的点都找到了,就能得到上图右上角的高高低低的覆盖图。有了球形空间的采样,就能估算出有多大面积的天顶是可见的,这是离散积分的思想。但是这个算法加了一个 Hack:如果这个山离我太远了,我认为它对我的 AO 没有什么变化。如果距离设置的比较短,w 就变成 0 了,就不会出现即使出现了比较远的物体,还是会出现 AO 的情况。
结果更好一点。

做法

notion image
这个算法细节比较多。
用 Ray marching 的方法,一个像素一个像素有步长地找,采取沿着一个方向进行多次采样的方式来模拟光线追踪。在一定范围内找到最大的 horizon angle 仰角。
从点出发,方向到每个点的时候都会 jitter 一下,因为如果每次找的方向都是一致的话,因为采样率很低,就会出现一些很明显的 Alias 花纹。如果学过信号处理就知道,如果对一个信号采样率特别低,采样的滤波非常规整,那滤出来的信号是有很明显的 pattern 的。因此算法就加了 jittering,在 pixel shader 里面,一步一步沿着 z-buffer 生成的剖面的 heightfield,找最远的仰角是多少,这样就能找一圈算出值。
如上图右数第一张图所示,采样了 四个点,每采样一个点就计算一下 horizon angle,然后比较找出最大的 horizon angle 即可。
📖
上图右数第二张图是沿着 轴从上往下看的俯视图。作者提出只采几个方向来近似即可,比如可以按照这俯视图的方向进行采样。不需要对点 P 的每个方向都求出 horizon angle。
💡
HBAO 是基于半球面积分的想法,结果比 SSAO 效果好很多,还能解决 Artifact。 但是这个算法还是有问题。

参考

GTAO - Ground Truth-based Ambient Occlusion

notion image

思想

前面讲材质的时候,天空是个球,假设表面朝上,从四面八方照过来的光,从天顶和从旁边斜着照过来的光,贡献值不是一样的,就像漫反射里面的 一样。光越靠近天顶, 的时候,Irradiance 的强度是百分之百被吸收,反射是四面八方均匀的反射。但是同样亮度的光,假如斜 45 度射进来,实际上散射出来的光也是 ,也就是 ,大概 0.7 左右。
实际上 SSAO、HBAO 都没有考虑这个因子,所以算出来的值全是错误的。因此 GTAO 是现在我们用的最多的方法。
Ground Truth 是指我的参考正确值和基本参考值是一致的,因此我的 AO 是符合真正离线算法算出来的结果。
其论文也给出过结果,和蒙特卡洛积分非常慢得出的结果几乎是一样的,因为 GTAO 真的考虑了法向。
notion image
GTAO 还有个非常厉害的地方:如果我们能算出来这个 AO 值是多少,我们就可以猜一下光射进来之后来回 bounce,最后得出来的亮度是多少。
假如光照射到山谷另外一侧,假设我们在山谷底,按之前的做法应该是最黑的地方。但实际上因为山谷的反光,底没有那么黑。里面的颜色和山谷周边的颜色也应该有关,比如山谷一边是红色,一边是绿色,那么 AO 也应该带色相。我们一般要做很多积分才能得到这个结果。

做法

而 GTAO 根据不同的 AO 值,做了大量的分析,发现 AO 值和 multi bounce 值是有关联的:不是简单的线性关系,而是符合某一条曲线,因此给出了 polynomial (多项式)的方程。我们就能用多项式计算,根据现在的 AO 值,估算出光来回 bounce 的结果。
像是上节课介绍的 fog 的算法,只计算了一次 single scattering
虽然论文原文没有给出理论证明,但是数学上是有基础的,因为 BRDF 模型的时候,我们也不知道微表面有多少细节结构,但我们统一给了一个量叫 roughness,这就表达了几何的不平整度。AO 的值也有点像 roughness 的值,指周围对我的遮挡。假设大家的分布符合一个统计学分布,实际上是会有关联度的,关联度可能是一个积分值,也可能是复杂的方程,但再复杂的方程也能通过多项式去拟合。
我的参考正确值,符合真正离线算法得出的 demo。
根据不同 AO 值,机器学习发现这是有关联的,估算光来回 bounce 最后的结果。
💡
GTAO 从数学上彻底把问题解掉了。还观察到一个很重要的性质,给出一个拟合方程。一下子把黑白的 AO,变成有色相的 AO。

参考

Ground-Truth Ambient Occlusion
前面介绍了SSAO和SSDO[1], 作为补全,本篇介绍一下GTAO。(其实目前介绍的这些AO都是SSAO技术实践,本文的SSAO主要指狭义上更广为人知的特定方式,而非一类技术统称。) GTAO其实是HBAO[2]的一个变种, 由于SSAO计算时对半径内的采样不看遮挡关系,导致会"过黑", HBAO则是针对当前采样方向在固定步长下,寻找一个最大的权重影响点。这就使得凹凸的表面上的遮挡不会像SSAO那么"平均"。但是问题在于,比采样点"低"的临近采样点,也会对AO做出贡献。这就需要你的场景是否有这种足够的微观程度,不然用了只是徒增性能开销。 GTAO而后相对于HBAO做了2点改变,第一点就是不止采样水平线之上,解决比采样点低的部分的AO权重。第二点就是做AO的半球积分,转换成了积分一个"求夹角"的操作: GATO部分以及对应的Near filed GI项: 由于完整的方程是这样的: GTSO鉴于效率推荐预计算一个3D 或者 4D LUT, 为了测试效果,我把Bent Normal替换为Normal(也就是原文作者推荐得4D降3D得方法),实时计算SO得结果: 可以看到,SO其实需要积分对应得BRDF, 这里由于UE4材质编辑器得一些限制,所以认为BRDF积分为1,只做了Delta V项得积分, 然后配合简单得Fresnel(同样由于编辑器限制), 结合GTAO预览得效果。 [1] Screen-Space Directional Occlusion. [2] Louis, B. Image-space horizon-based ambient occlusion. 2008. [3] Jimenez et al. Practical Realtime Strategies for Accurate Indirect Occlusion. 2016.
Ground-Truth Ambient Occlusion

Ray-Tracing Ambient Occlusion

notion image
现在 GPU 可以快速做 Ray casting 计算,对屏幕上每一个像素,可以射 ray 知道有没有遮挡。
想做对,屏幕上每个像素点的半球都要射很多 ray,但是这太耗了。
真实的做法是,每一帧对外射一到两根 ray,时序上进行数据的收集,从而完成球面采样的近似。