【Siggraph 2016】Practical Realtime Strategies for Accurate Indirect Occlusion

今天分享的是Siggraph 2016上的GTAO算法实现细节,原文链接在参考部分给出。

总结

先对实现原理做一个总结:

  1. GTAO算法的整体思路与计算流程与HBAO一致(如上图所示,沿着半球进行积分,穿过球心形成一个个的切面),都是通过沿着各个方向计算一个无遮挡的锥角(找到起始偏移角跟终止偏移角,上图左边小图,中间的夹角叫做水平角),基于角度估算遮挡关系(最后对各个方向的切片进行积分,上图右边小图,得到最后结果),在这个思路框架下,有若干优化点
    2.不再考虑随着距离衰减的可见性函数,统一用1来替代,降低计算消耗,同时因此可以将双重积分简化为单重积分,进一步降低性能消耗
  2. 没有假设周围表面都是diffuse的,将整个光照计算公式分为AO部分跟SO部分,因此会有Specular Reflection效果

再来介绍一下,为何GTAO的实现效率比HBAO、SSAO要高:

  1. 前面提到的公式简化带来的优化(函数变常量,双重积分变单重积分)
  2. 通过采样点时域、空域复用实现质量与性能的兼顾,同时采样范围会跟随到相机的距离而调整,近景精度高
  3. 屏幕分辨率往往是一半或者1/3

最后介绍near-field GI(用于弥补使用常量替代衰减函数导致的光照过暗的问题,同时进一步提高整体质量)效果是如何得到的:

  1. 假设像素周围的像素的albedo是保持不变的(虽然不一定成立,但是影响不大)
  2. 在上述假设下,near-field GI跟AO的关系,可以用一个曲线来近似拟合

1. 简介

AO是对GI(Global Illumination)的简单模拟,在GI计算复杂度居高不下的情况下,AO效果对于提升场景光影自然度有着重要的作用,即使在有烘焙间接光(如lightmap)的情形下,AO的加入也可以提升光影效果,这是因为烘焙光照的分辨率通常较低,GI效果精度较差,而AO效果的添加则可以在一定程度上掩盖这个问题。

然而在AO计算上,目前并不存在针对任意场景的解析解,大多是通过经验的方式来产生感觉自然的效果,即使如此,现有的AO计算方案都面临着消耗过高的问题,而原文提出的Ground Truth AO(GTAO)方案是在HBAO方案的基础上经过改进得来,通过一系列的手段可以以较低的消耗完成计算(可以做到在当代主机上只需要0.5ms的消耗的实施效率)。除了效率的提升之外,这里还增加了near-field GI的模拟以及一种实现对probe-based illumination环境下的specular reflection效果方案GTSO的模拟。

2. 算法概览

完整的反射光强可以通过如下公式计算得到:

这是一个围绕x点的球面积分,其中\omega_i表示入射光方向,\omega_o表示出射光方向,而<n_x, \omega_i>^+则是一个递归运算符(recursive operator),表示的是所有场景的反射radiance(reflected radiance in all the scene,其实就是光源方向跟法线的点乘)。

这个公式要想在游戏中以实时帧率的方式计算出来在目前还不现实,这里只关心其中AO相关的部分。通过下面的一系列假设:

  1. 入射光来自于无穷远处的环境光,且这部分光照可以被x周边的几何物体所遮挡
  2. x周边的所有表面吸收率是100%,即不会出现散射或者反射
  3. x所在的表面是diffuse的

基于上述假设,我们可以将前面的公式转换成如下的形式:

其中:

  • \rho(x)是点x的albedo,\frac{\rho(x)} {\pi}是diffuse BRDF(从前面的式子中抽离出来,由于是环境光,因此L_i也可以一并抽出来),这里可以简单理解为该位置的反射系数
  • V(x, \omega_i)则是\omega_i方向上的遮挡情况,或者说可见性,在某个给定的范围内,未被遮挡为1,被遮挡则为0。
  • 最后,AO可以用A(x)来表示,对应的是针对V(x, \omega_i)的一个球面积分,可以看成是该处的遮挡关系

用一个相对直观的话来说,输出光照结果等于输入光照乘上一个反射系数再乘上用AO表示的遮挡关系

为了应对上述AO算法中未考虑near-field的interreflections,即近景几何之间的相互反射,前述假设反射出去的光都被吸收掉了,因此导致丢失了一部分光照输入,表现为效果过暗,HBAO使用了一个随着距离衰减的函数来模拟V(x, \omega_i),也就是说,射线遇到遮挡并不就表示不可见,而是用一个微弱的可见性来表征。

GTAO这里则采用了一种完全不同的做法,通过引入一个新的公式来填补了near-field的interreflections数据以得到一个更为真实的效果。

HBAO算法的计算公式可以表示为:

其中|sin(\theta)|是球面积分转换为角度双重积分时自带的一项,前面的\frac{1}{\pi}则是归一化因子,这里需要注意的是,HBAO公式计算得到的是AO的一个近似项,因此在头顶有个帽子。虽然HBAO是一个屏幕空间的算法,但是其消耗在当代GPU上依然无法达到预期,[Tim13a]给出了一系列的优化措施对这个算法进行了改进,可以一定程度上提升其计算效率。

GTAO则是在HBAO的基础上考虑了前人的优化措施,在性能上与效果上都做出了一定程度的改进提升。具体而言,这里解除了前面对表面必须是diffuse的假设,同时还考虑了near-field(近景处)occluder之间的相互反射,在这两个考虑的前提下,前面的公式(2)需要改写成如下形式:

即将光照结果分为Diffuse部分(GTAO)跟Specular部分(GTSO),这也是为什么前面说到GTAO能够支持Specular Reflection效果的原因。

上述公式中,其中F(\omega_o)是菲涅尔反射项:

  1. GTAO部分是在原有的AO项(A(x))的基础上考虑了near-field occluder的interreflection之后结果,因此用G(A(x))表示。
  2. GTSO部分中的S(x)表示的是specular occlusion项,这一项在使用的时候需要跟提前卷积过(preconvolved)BRDF项L(x, \omega_o)进行相乘。

3. 实施细节

3.1 GTAO

GTAO是脱胎于HBAO的算法,因此大体实施策略与HBAO类似,只是在其中一些地方做了改进修正:

  1. 水平角\phi跟仰角\theta都是相对于视角方向\omega_o计算的(上图中标注的是\omega_i应该是标注错了),我理解HBAO应该也是这样算的?
  2. HBAO中的可见性函数是一个随着距离而衰减的函数,但是在这里则是常量1(下面公式中的余弦不是来自于可见性函数,而是最前面积分中的光源方向与法线方向的点乘):

如上述公式所示,其中\gamma是x点的表面法线跟视线\omega_o之间的夹角,而内积分的区间\theta_1(\phi)\theta_2(\phi)按照前面的示意图来看,应该有考虑符号的(比如\theta_1(\phi)是小于0的之类),这里余弦上的加号表示的是clamp:cos (θ)^+ = max(cos (θ), 0),转换为这个公式之后,内积分可以给出一个解析解,相当于只有外积分需要通过数值解来计算,大大简化了计算消耗。

要想计算内积分,首先就需要计算出积分范围\theta_1(\phi)\theta_2(\phi),这里的做法是对于当前屏幕空间的像素,会选取周边n x n个像素作为采样范围,沿着当前水平角\phi的正反方向各进行n/2个采样点的采样计算,并通过如下公式计算出对应的仰角:

其中,\omega_s = \frac{s - x}{||s - x||},这里的s是屏幕空间对应采样像素的世界坐标。此外,这里需要注意的是,为了使得计算得到的AO效果在近景处具有更好的质量,这里采样范围是会跟随x距离相机的远近而变化的,从而避免在距离相机较近的区域采用一个较大的采样范围而导致计算效率的下降。

前面公式中的内积分可以给出解析解,这里需要注意,这里解析解中增加了一个cos(\gamma),这是为了保证当\theta = 0的时候积分结果为0而增加的;另外,解析解这里\theta_1\theta_2上下两边界在积分公式赋值结果的符号实现相同的,是因为考虑到两个角度符号的不一致,这里分解为两部分,一部分是从0到\theta_1,另一部分则是从0到\theta_2,将两者加起来,解析公式中的\theta都取绝对值应该就好理解了。

不过这里有个问题是,上述解析公式成立是有条件的,即法线是位于由\omega_o\phi组成的平面P上的,但实际上这个假设绝大部分情况下都是不成立的,这里的做法是将法线投影到这个平面上,采用投影后的法线\frac{\overline{n_x}} {||\overline{n_x}||} \in P来完成上述计算,而前面的角度\gamma也就变成这个法线与\omega_o的夹角。

考虑到法线本身投影是不需要归一化的,这里在最终的外积分中还需要将这个归一化的影响去掉:

由于这里只有0.5ms的预算,这里需要通过一系列策略来对算法进行加速,这里的做法有:

  1. 在半分辨率的情况下进行相关计算
  2. 将积分模拟的多次采样分散到多帧以及多个像素上来完成

这里来解释下第二点,具体做法有:

  1. 每个像素只沿着某一个水平角的方向进行采样,但是会通过对相邻的4x4的像素的数据进行重用,最后通过双线性采样进行重建
  2. 通过exponential accumulation buffer对6帧的数据进行累加,相邻6帧之间的旋转角度是不一样的
  3. 将上面的结果累加到一起,相当于每个像素进行了4x4x6=96个方向的采样。

由于GTAO中移除了HBAO中随着距离而衰减的可见性函数,因此会导致occlusion结果的跳变,为了缓解乃至消除瑕疵,这里采用了一种保守的衰减策略:

  1. 确保near-field的occlusion是具有ground-truth效果的
  2. 对于far-field的occlusion会通过一个线性blend函数将之逐渐下降到0,这个衰减发生在large-enough distance到maximum search distance之间。

最后,由于当前算法是没有办法侦测到对应几何体的厚度的,因此会导致一些本身很薄的物体产生了过于浓厚的遮挡阴影,这里的解决方案是建立在一个假设之上的,即物体的厚度跟此物体屏幕空间的尺寸存在一定的正比关系(不成立吧。。),在这个假设之下,就可以对前面的公式(6)进行修正:

这里的blend的采用的是exponential moving average(EMA)算法

\theta_0 = 0

image.png

前面说过,AO计算的一个假设是,所有输入光来自于无穷远处,且各个方向的光照强度是相等的,这个假设直接忽略了near-field表面的多次反射效果,因此在边角区域会偏暗,而实际上边角区域的效果则是AO发挥威力最为显著的地方,因此在这种计算下的AO方案表现并不是特别好。

实际上,边角区域也正是near-field interreflection占据主导地位的区域,前人通过一些衰减函数来实现这个区域的多次反射模拟,以给出一个看起来相对正确的结果,但是这种方式实际上是没有什么物理意义的。

这里为了以一种低消耗的方式来实现对near-field interreflection的计算,给出了一个假设,即每个点x周边一小块区域中的表面albedo数值是恒定不变的(这个假设通常是不准确的,不过由于这里考虑的是x相邻的遮挡面在一个紧凑范围内的interreflection,从而使得这个假设在一定的程度上是成立的),在这个假设下,可以得到near-field的GI跟AO数值的一个关联关系。

这个假设的作用除了是方便推导出GI跟AO之间的映射关系,同时也是为了避免对相邻表面每一个点进行albedo采样计算,降低运行消耗。

下一步就是根据x点的albedo\rho(x)计算出AO跟near-field GI的关联关系G(A(x), \rho(x))。这里的做法是在一系列代表各种类型的测试场景中(见下图)为一系列的albedo数值(ρ = [0.1, 0.2, 0.3, 0.4, 0.5, 0.7, 0.9])同时计算AO与多次反射的GI

下图给出了AO(横坐标)跟GI(纵坐标)之间的映射关系:

从图中可以看到,对于每个场景每个albedo中的对应采样点,都可以通过一个三次多项式来进行模拟,而经过对各个场景的分析与整合可以得到,通过一个随着albedo而变化的三次多项式可以实现对所有场景映射关下的近似模拟:

而这种模拟方式不但补全了前面说的near-field上的多次表面反射输入光强,同时还具有计算高效的优点。

3.2 GTSO

下面来介绍一下specular occlusion的相关内容,这个部分代表的是Lambertian-based AO中的光滑反射部分。

先来看下specular occlusion的作用,下面两图分别给出了将specular occlusion关闭与打开情况下的表现:

off
on

可以看到,在高光上添加真实遮挡信息可以实现更为自然真实的高光效果。

跟GTAO一样,这里先假设输入光源来自于无穷远处:

要想通过数值的方式来解出这个积分是很困难的,这里的做法是假设各个方向的输入光可见性是1( ∀ω_i | V(x, ω_i) =1),之后通过[Laz13,Kar13]中介绍的积分拆分方式将之拆分成两部分以实现近似模拟(不知道这个拆分是基于什么原理给出的?):

其中C_L是归一化因子,目的是保证L(x)的积分结果永远处于[0, 1]范围之内,计算方式为:

按照AO的假设,入射光强在各个方向是恒定的,D(x, \omega_h)是x点处的法线分布函数,\omega_h = normalize(\omega_i + view_{dir})是half vector。

前一个积分表示的是实际的输入光源环境L_i(x, \omega_i)跟Cook-Torrance BRDF中的法线分布函数(可以通过一个圆周对称的lobe来表示)的一个卷积,如果我们将输入光源环境用一张irradiance cubemap来表示的话,那么这个卷积就可以在离线的时候针对不同的粗糙度计算完成,结果可以烘焙到一个cubemap mipmap中,从而使得这个部分的计算在运行时十分的高效。

后一个积分可以看成是在纯粹白色输入光(L_i(x, \omega_i) = 1)的输入下微表面反射结果,可以通过预计算的方式烘焙到一张贴图中,不过后面进一步的处理会抵消掉这个积分,因此不做进一步展开。

前面假设中输入光源的可见性在各个方向是不受遮挡的,但是这种假设终归是不正确的,为了将遮挡信息考虑进去,这里可以采用跟之前积分拆分同样的思路,将可见性函数从积分中拆出来,最终的公式给出如下:

公式中的S(x, \omega_o)就是specular occlusion部分,可以通过如下公式进行计算:

这里C_V = \int_{H^2}f_r(x, \omega_i, \omega_o)<n_x, \omega_i>^+ d \omega_i也是归一化因子,目的是保证S(x, \omega_o)处于[0, 1]范围之内。可以看到,occlusion是受BRDF的影响的,因此是一个随着方向\omega_o而变化的数值。

这里由于C_V跟前面的F(x, \omega_o)完全相等,因此二者可以抵消,最终得到的计算公式为:

上述公式如果取L_i(x, \omega_i) = 1的话,就跟Ground Truth完全一致了,与前面不考虑specular occlusion的积分公式相比,这里只是将可见性函数V(x, \omega_i)塞入到BRDF积分中而非当成一个常量看待了。

下面来介绍一下specular occlusion部分要如何计算。

这里计算specular occlusion的想法是将可见性函数V(x, \omega_i)跟BRDF f_r(x, \omega_i, \omega_o)都用一个近似模型来代替,以实现高效计算。

可见性函数可以用一个cone来代替,这个cone以bent normal作为方向,还有另一个关键参数ambient occlusion项(这个是干啥的?可以转换为cone的半径或者角度),而这两项都可以通过在运行时实时算得,当然也可以在离线烘焙出来,并将之放到一张贴图或者顶点数据中。选择cone的表示方法的原因是可以重用之前GTAO中的计算结果

cone的幅度(amplitude,也就是cone的张角)\alpha_v可以通过AO计算得到,假设bent normal周边的可见性是各向同性的话,那么\alpha_v可以表示为在所有水平角\phi下的最大仰角(这里由于是各向同性的,因此有\theta_1(\phi) = \theta_2(\phi) = \alpha_v),在这个假设下,AO(这里不是occlusion,而是visibility?)可以表示为:

这个公式的推导可以参考下图(通过cos加权的球面积分求得AO的可见性):

根据AO,我们就可以得到这个张角的计算公式:

关于BRDF项,我们同样可以使用一个cone来进行表示,这个cone的中心就是反射点x,反射方向\omega_r则为cone的方向。这里有一些假设,比如BRDF需要沿着\omega_r圆周对称,这个假设实际上是不成立的,不过这个假设已经是十分通用了,前面对cubemap进行卷积也是在这个假设的基础上完成的。另一个假设则是BRDF数值是一个常量。在这些假设的基础上,specular occlusion可以表示为如下的公式:

上述公式中的两项可以通过下图左边小图来理解,分子是两个cone的交集,分母则是BRDF对应的specular cone。

这个公式是可以通过解析的方式计算出来的,虽然是在一系列的假设的情况下得出的结论,但是结果还可以。

虽然这个公式看起来已经十分精简了,但是在计算上还是太费了,难以做到实时运算,但是这个计算是可以提前完成的,将结果转换为可见性cone的角度、specular cone的角度以及两个cone之间的夹角(bent normal跟反射向量\omega_r之间的夹角)\beta = arccos(<b, \omega_r>)三个变量的函数,从而将结果提前计算好存储在一张3D贴图中即可。因为是提前计算的,因此这里可以使用一些计算复杂度相对高一点,但是结果也更为精确的方式,即表示成可见性cone\Delta_V跟BRDF相乘的积分,其示意图如上图右侧小图所示。

其中\Delta_V(\alpha_v, \beta)是一个二值函数,只有当\alpha_v \geq \beta的时候为1(即两个cone之间会存在交集),其他时候为0。

假设反射微表面的BRDF是各向同性的,使用的NDF是可以通过一个粗糙度r就能表达的GGX格式的,那么反射角度\omega_r就能够用一个角度来表示:\theta_0 = arccos(<n_x, \omega_r>),其中n_x是表面法线,在这个假设下(不考虑空间上的dependency),上面的公式就可以转换成一个由四个变量表达的积分:

也就是说,specular occlusion可以表示成四个变量的lookup table,此外,如果将表面法线跟bent normal等同起来,那么就有\theta_0 = \beta,就可以将这个lookup table的维度降低到三维(不过会引入一些误差)。

如果这个函数比较平滑的话,就可以用较低分辨率进行存储,比如32^4分辨率的BC4压缩格式的每个像素消耗8-bits的lookup table,并在运行时采样使用。

4. 总结

原文中的技术总的来说可分成GTAO跟GTSO两块。

在AO上面,GTAO在HBAO的基础上移除了随着距离衰减的可见性函数,转而使用一个常量1作为可见性(不过恢复了正常积分中的光线与法线之间的余弦项),为了避免硬切导致的瑕疵,这里的做法是从一个较大的距离到最大的采样半径上使用一个从1到0的线性混合权重。为了模拟near-field的interreflection,原文通过对多个具有代表性的场景在不同的albedo作用下的GI跟AO之间的数值关系进行匹配映射,得到了两者之间的关系的解析模拟解。

在SO上面,则是通过积分拆分的方式将光滑表面的反射结果拆分成specular occlusion跟输入光卷积结果(输入光跟BRDF的发现分布函数的卷积,可以在离线的时候完成)的乘积,而specular occlusion又可以表示成由四个参数表示的lookup table,因此整个计算可以完全转换为离线计算,运行时采样的实现方式,从而以较低的成本获得光滑表面上带有specular occlusion的反射结果。

参考文献

[1] Practical Realtime Strategies for Accurate Indirect Occlusion - Thesis
[2] Practical Realtime Strategies for Accurate Indirect Occlusion - PPT
[3]. 实时渲染器开发(四) GTAO原理与实践
[4]. UE4 Mobile GTAO 实现(HBAO续)
[5]. SSAO HBAO GTAO
[6]. GTAO原理&UE4移动端GTAO实现分析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容