屏幕信息

三维全局光照需要额外记录场景几何与光照;屏幕空间 Screen Space 方法则利用相机已经生成的深度、法线和颜色。屏幕上的每个有效像素对应一个相机可见表面点,可以从深度反建位置,从法线知道朝向,从直接照明颜色知道该表面已经反射了多少光。

这些图像可以作为后处理输入,省去重新访问完整场景的开销。但相机只能看到最近的一层:屏幕外、物体背面和被遮挡的表面不在输入中。光源视角的 RSM 虽然也存在图像中,却不是这里所说的“当前相机屏幕空间”。

先考虑一个更简单的问题:不求完整的间接光,只用局部几何决定环境项应该变暗多少。接触处、凹槽和墙角周围的开阔程度不同,这些差别已经能帮助辨认物体的位置关系。

环境遮蔽

环境遮蔽 Ambient Occlusion,AO 近似表面附近环境方向的可见程度。沿用三项假设:入射环境辐亮度各方向相同;可见性随位置与方向变化;接收材质为 Lambertian。

令统一入射辐亮度为 LaL_a,反照率为 ρ\rho,局部方向可见性为 VR(p,ω)V_R(p,\boldsymbol\omega),则

Lo(p)=ρπLa∫Ω+VR(p,ω)(n⋅ω) dω=ρLaA(p),L_o(p)=\frac\rho\pi L_a \int_{\Omega^+}V_R(p,\boldsymbol\omega) (\mathbf n\cdot\boldsymbol\omega)\,\mathrm d\omega =\rho L_a A(p),

其中

A(p)=1π∫Ω+VR(p,ω)(n⋅ω) dω.A(p)=\frac1\pi\int_{\Omega^+} V_R(p,\boldsymbol\omega)(\mathbf n\cdot\boldsymbol\omega)\,\mathrm d\omega.

A∈[0,1]A\in[0,1] 是余弦加权平均可见度,11 表示完全开阔,00 表示完全遮挡。有些实现将 1−A1-A 命名为 occlusion amount,写入纹理前应明确存的是“可见度”还是“遮挡量”。

Phong 的环境项通常给不同点同一个环境颜色;AO 保留了局部几何差异,所以在凹处和接触处降低环境项。在上述均匀入射与 Lambertian 条件下,这一因子化是精确的;真实间接光的方向和颜色变化,以及 VRV_R 的屏幕近似,才是误差来源。

不能将 AO 无条件乘到所有光照上。直接光源的遮挡应由该光源的可见性决定;将 AO 再乘上已有准确阴影或间接照明,可能重复压暗。

投影立体角

归一化分母为什么是 π\pi?可以把单位半球沿法线投影到单位圆盘来观察。

半球方向元素沿法线投影到单位圆盘

图中竖直箭头为法线,半球上的小片 dω\mathrm d\omega 投到下方圆盘后缩为 cos⁡θ dω\cos\theta\,\mathrm d\omega。切向附近被压缩得更多,正上方几乎不缩小。方向元素满足

dω⊥=cos⁡θ dω.\mathrm d\omega_\perp=\cos\theta\,\mathrm d\omega.

正前方的方向贡献较多,接近切线的方向贡献较少;投影后的圆盘面积恰好为 π\pi。直接积分也能得到

∫Ω+cos⁡θ dω=∫02π∫0π/2cos⁡θsin⁡θ dθ dϕ=π.\int_{\Omega^+}\cos\theta\,\mathrm d\omega =\int_0^{2\pi}\int_0^{\pi/2} \cos\theta\sin\theta\,\mathrm d\theta\,\mathrm d\phi =\pi.

所以 AO 可以理解为单位圆盘上可见区域占的面积比例。这个理解已包含余弦权重,不是将余弦从公式中丢掉。

用概率密度 pωp_\omega 采方向,可估计

A^=1Nπ∑j=1NVR(p,ωj)cos⁡θjpω(ωj).\widehat A=\frac1{N\pi}\sum_{j=1}^N \frac{V_R(p,\boldsymbol\omega_j)\cos\theta_j}{p_\omega(\boldsymbol\omega_j)}.

若均匀采半球,pω=1/(2π)p_\omega=1/(2\pi),每项仍需乘余弦;若采用余弦加权采样 Cosine-Weighted Sampling,pω=cos⁡θ/πp_\omega=\cos\theta/\pi,权重抵消,A^=1N∑jVR\widehat A=\frac1N\sum_jV_R。两种样本都可以估计同一个量,区别在于采样分布与权重,不应混用。

局部范围

这里用半径 RR 内是否遇到几何定义 VRV_R。若在封闭室内向每个方向无限延长射线,最后都撞到墙面,AO 会接近零;真实房间仍可能由墙面的反射照亮。AO 只估计局部遮挡,没有计算那些表面的反射光。

较小 RR 主要保留接触和细小凹槽,较大 RR 能考虑更远的遮挡,但更容易过度压暗,也扩大屏幕近似的错误范围。可对遮挡距离使用平滑衰减,避免恰好在 RR 边界突然改变结果;这时计算的是带距离权重的遮蔽定义,需与实现中的强度参数一起理解。

深度采样

屏幕空间环境遮蔽 Screen-Space Ambient Occlusion,SSAO 用深度图近似局部几何。经典做法不一定有法线,因此在表面点周围的球体内部生成随机样本点,将这些三维点投影到相机图像,比较样本深度与该像素保存的最近深度。

球形邻域样本与相机深度曲线的比较

白点是待着色表面点,虚线圆表示有限采样范围;三维球在图中只画了截面。绿点通过近似可见性测试,红点被深度测试判为遮挡。凹处遮挡样本较多,凸起处较少,从而形成不同暗化程度。

样本是球内的点,不只是球面上的方向。一个平面原本就将球体分成两半,因此经典启发式常以“超过一半样本被挡”作为额外遮蔽。例如失败比例为 ff 时,可以使用

Ahack=1−max⁡(0,2f−1).A_{\rm hack}=1-\max(0,2f-1).

这是平面基线的重映射示意,不是理论 AO 的余弦积分。球内采样未限定法线半球,也没有正确的方向测度和余弦权重,只能视为工程近似。

有法线时,可以在切线坐标系中生成半球样本,再转到视图空间。采样方向、采样距离和概率权重决定估计的含义;单次“样本点位于深度之后”仍不等价为沿该方向找到了第一个真实遮挡交点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 经典球内采样的示意;假设正的视图距离随远离相机而增大。
for each surface pixel p:
position = reconstructViewPosition(p, depth[p])
failed = 0
validCount = 0
for each randomized point offset inside radius R:
samplePosition = position + offset
uv = projectToScreen(samplePosition)
if outsideScreen(uv):
continue
surfacePosition = reconstructViewPosition(uv, depth[uv])
if outsideLocalRange(position, surfacePosition, R):
continue
validCount += 1
if surfaceDepth(uv) + bias < sampleDepth(samplePosition):
failed += 1
occlusionFraction = failed / max(validCount, 1)
ambientVisibility[p] = 1 - max(0, 2 * occlusionFraction - 1)

Reverse-Z 或负视图 zz 的实现需要相应改变比较约定。深度与样本应转换到一致空间,bias 的单位也要一致。屏幕外和无深度样本的处理会改变边缘处的估计;跳过并重归一只是一个取舍,并不恢复缺失几何。

错误遮挡

深度图保存表面,却不保存该表面背后是否仍是实体。将“落在深度之后”统一当成内部,会把自由空间错判为遮挡,称为 False Occlusion。

红色箭头所指样本在真实自由空间中却被深度测试判为遮挡

红虚线之后的红点与最近表面有前后关系,但它并不真的在物体内部;单层深度无法表达这个区别。于是相机前方的物体可能使后方表面产生不应有的暗化。

SSAO在悬空物体附近地面产生错误黑晕

右图红圈内是台体附近地面的额外黑晕。屏幕上相邻不等于世界中接触,台体与地面的层叠关系会触发这种误遮挡。减小半径通常能减轻黑晕,同时也会漏掉真正较远的局部遮挡。偏差来自输入缺失,单纯增加样本数不能解决。

随机与滤波

少量规则样本会形成方向性条带,可以为每像素随机旋转采样模式。课程举约 1616 个样本,并使用小随机纹理提供旋转;这样将规则图案转成较分散的噪声,再做平滑。

少量随机SSAO样本产生的噪声

过滤后的SSAO结果

上图大面积表面存在细粒噪点,下图更平滑,但小沟槽与边界也可能减弱。保边滤波 Edge-Preserving Filtering 结合深度、法线等信息,限制跨几何边界的混合,避免背景遮蔽被抹到前景。普通图像模糊无法区分噪声与真实结构。

法线可由邻近深度重建的表面切向量叉乘估计,但深度断层处需要避免使用另一物体的点。若 G-buffer 已有法线,可直接用其定义半球。

Horizon-Based Ambient Occlusion,HBAO 沿屏幕方向搜索几何形成的地平线角度:某方向被抬高的几何挡住的角度越多,该方向遮蔽越强。它利用法线和角度信息,能改善部分球形采样误差。课程中的柱子与地铁场景对照展示了接触暗化,以及经典 SSAO 的误暗区域;HBAO 仍缺少屏幕外和背面几何,不能看成完整场景的准确可见性。

方向遮蔽

AO 将可见方向的光统一处理。若两侧分别是蓝色、黄色表面,遮蔽比例相同也可能有不同的反弹光颜色。屏幕空间方向遮蔽 Screen-Space Directional Occlusion,SSDO 保留方向上的照明差别,并利用已有直接照明图估计短程反弹。

从统一AO到方向遮蔽与有色反弹的逐步效果

上排依次是无该效果、AO、方向遮蔽、方向遮蔽加反弹;下排放大了局部差别。AO 主要压暗开阔程度较低的区域,方向方法能随照明方向改变颜色与暗化;加入 Bounce 后,黄色物体的颜色进入附近接收表面。不能仅把 AO 纹理换成一张彩色暗化图就认为已经计算间接反射。

输入仍是当前相机的直接照明结果。像素 qq 保存的是朝相机的出射辐亮度,要让它作为朝 pp 的次级源,通常仍需将 qq 近似为漫反射面。接收点的材质可以 Glossy;“源近似漫反射”与“接收点必须漫反射”是不同要求。

方向分类

从点 pp 向局部半球采样方向:若没有遇到附近表面,该方向从环境或直接项获取光;若遇到表面 qq,该方向的光由 qq 的反射提供。AO 常把后者只视为损失,SSDO 则继续估计它携带的间接贡献。

AO与方向遮蔽对开阔方向及命中表面方向的不同处理

图中 p0p_0 位于凹处,开放方向较少;p1p_1 朝向外部,开放方向较多;p2p_2 一部分方向到外部,另一部分命中相邻表面。图中的向外箭头代表查询入射来源的方向,不是光一定按箭头向外传播。右侧要进一步使用方向照明与命中点信息,几何示意本身相似不代表两种算法贡献相同。

令 VR=1V_R=1 表示局部范围内对环境开阔,可概括为

Loopen=∫Ω+VRLenv(ω)frcos⁡θ dω,L_o^{\rm open}=\int_{\Omega^+}V_R L_{\rm env}(\boldsymbol\omega) f_r\cos\theta\,\mathrm d\omega,

Lobounce=∫Ω+(1−VR)Lodir(q,−ω)frcos⁡θ dω.L_o^{\rm bounce}=\int_{\Omega^+}(1-V_R) L_o^{\rm dir}(q,-\boldsymbol\omega) f_r\cos\theta\,\mathrm d\omega.

这里“遮挡环境”不等于该方向完全无光:命中的表面仍会反射光。VRV_R 是方向分类的局部可见性,不能和“次级源被另一物体挡住时乘零”的两点可见性混为一谈。

局部求值

SSDO在局部半球内投影深度样本并查询受光表面

左图从 PP 周围选三维样本 A,B,C,DA,B,C,D,再投影到相机保存的表面;中图使用查询到的表面法线和反射信息估计其贡献;右图说明悬空或层叠物体会让采样位置与可见表面对应关系发生误差。红色局部半球限定搜索距离,屏幕内存在某个像素也不保证它就是从 PP 沿该方向遇到的第一个表面。

按方向密度 pωp_\omega 采样时,将开放方向的环境辐亮度或命中方向的表面辐亮度记为 L~i\widetilde L_i,计算

L^o=1N∑jL~i(ωj)fr(ωj,ωo)cos⁡θjpω(ωj).\widehat L_o=\frac1N\sum_j \frac{\widetilde L_i(\boldsymbol\omega_j) f_r(\boldsymbol\omega_j,\boldsymbol\omega_o)\cos\theta_j} {p_\omega(\boldsymbol\omega_j)}.

若实际实现选择的是屏幕面片,再按面积求和,就要使用面片几何项和对应概率。两种积分参数化应分别处理;方向辐亮度采样不能额外乘一遍 1/r21/r^2。

1
2
3
4
5
6
7
8
9
10
11
12
// 方向采样版概括;localScreenQuery 只是屏幕可见性近似。
for each receiving point p:
estimate = 0
for each direction omega sampled with density pdf:
query = localScreenQuery(p, omega, radius)
if query.hasSurface:
incoming = directLitColor[query.pixel]
else:
incoming = environmentRadiance(omega)
estimate += incoming * receiverBRDF(p, omega)
* max(dot(normal[p], omega), 0) / pdf
result[p] = estimate / sampleCount

查询失效、离屏和没有真正命中的情况,需要明确 fallback。若已有独立环境直射和主光源着色,合成时也要避免把同一开放方向贡献重复添加。

缺失路径

局部半径无法取得远墙对盒面点的间接贡献

盒面黑点本应受到远处彩色墙面反射的光;若墙超出采样半径,局部算法就无法取得该路径。叉号强调的是局部方法在该点缺失贡献,并不表示参考图中的绿色不该存在。

此外,相机可见性与 pp 到 qq 的可见性不同。相机看不到的表面可能正好能照到 pp,相机看得到的两个表面也可能被第三个物体隔开。相机或物体运动时,输入突然出现或消失,会引发贡献变化。SSDO 因而适合短程、有色的局部 GI 补充,不能独立完成大范围、多次反射的全局照明。