深入解析屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO)
在实时 3D 图形渲染管线中,间接光照(Indirect Illumination)的计算是决定场景空间感与真实感的核心关键。然而,完整求解全局光照(Global Illumination, GI)的渲染方程开销极大。环境光遮蔽(Ambient Occlusion, AO) 作为一个高效的经验/物理近似模型,通过计算贴近表面片元被周围几何体遮挡的程度,为漫反射环境光提供了至关重要的暗化因子。
由 Crytek 在 2007 年提出的 屏幕空间环境光遮蔽(SSAO),将三维几何空间的遮挡判定降维至屏幕空间(Screen-Space Depth Buffer),以极高的计算效率实现了动态场景的实时阴影重建。
本文将深入 SSAO 的底层数学推导、采样核分布演进、自遮挡与黑晕瑕疵修正、深度感知双边滤波降噪,并提供标准的 Vulkan/GLSL 工程级实现。
一、 SSAO 核心原理与数学建模
1. 渲染方程与环境光遮蔽项解耦
在 PBR 渲染管线中,忽略自发光项后,表面点 \(\mathbf{p}\) 在观察方向 \(\mathbf{v}\) 的反射辐射度 \(L_o(\mathbf{p}, \mathbf{v})\) 表达为:
\[ L_o(\mathbf{p}, \mathbf{v}) = \int_{\Omega} f_r(\mathbf{p}, \mathbf{\omega}_i, \mathbf{v}) L_i(\mathbf{p}, \mathbf{\omega}_i) (\mathbf{n} \cdot \mathbf{\omega}_i) d\mathbf{\omega}_i \]
在计算漫反射环境间接光(Diffuse Indirect Light)时,假设入射环境光强度 \(L_{in}\) 在半球方向 \(\Omega\) 上各向同性(Uniform Distant Light),则可以将环境光的可见性函数 \(V(\mathbf{p}, \mathbf{\omega}_i) \in [0, 1]\) 从积分中解耦,定义为环境光遮蔽因子 \(A(\mathbf{p})\):
\[ A(\mathbf{p}) = \frac{1}{\pi} \int_{\Omega} V(\mathbf{p}, \mathbf{\omega}_i) (\mathbf{n} \cdot \mathbf{\omega}_i) d\mathbf{\omega}_i \]
其中: * \(\mathbf{n}\) 为表面点 \(\mathbf{p}\) 处的单位法线向量。 * \(\mathbf{\omega}_i\) 为半球方向上的入射光线单位向量。 * \(V(\mathbf{p}, \mathbf{\omega}_i)\) 为遮挡函数:若沿着 \(\mathbf{\omega}_i\) 方向在半径 \(R\) 内击中几何体则 \(V=0\),否则 \(V=1\)。 * Factor \(\frac{1}{\pi}\) 用于将半球余弦积分归一化至 \([0, 1]\) 范围。
2. 屏幕空间离散化与 Monte Carlo 采样
在实时渲染中,SSAO 放弃了复杂的 3D 场景几何求交,转而利用深度图(Depth Buffer)重建视空间 3D 坐标。通过 Monte Carlo 随机采样法,将连续的半球积分离散化为 \(N\) 个离散采样点的遮挡校验:
\[ A(\mathbf{p}) \approx 1.0 - \frac{1}{N} \sum_{i=1}^{N} \chi\left( z_{\mathrm{sample}_i} - z_{\mathrm{buffer}_i} \right) \cdot \max(0.0, \mathbf{n} \cdot \hat{\mathbf{s}}_i) \]
其中: * \(\mathbf{s}_i\) 为在视空间中以 \(\mathbf{p}\) 为原点生成的采样点偏移向量,采样点位置为 \(\mathbf{p}_{\mathrm{sample}_i} = \mathbf{p} + \mathbf{s}_i\)。 * \(z_{\mathrm{sample}_i}\) 为采样点 \(\mathbf{p}_{\mathrm{sample}_i}\) 的视空间深度值。 * \(z_{\mathrm{buffer}_i}\) 为将 \(\mathbf{p}_{\mathrm{sample}_i}\) 投影回屏幕坐标 \((u_i, v_i)\) 后,从 Depth Buffer 读取并重建的实际几何体视空间深度。 * \(\chi(\Delta z)\) 为阶跃遮挡判定函数:当 \(z_{\mathrm{sample}_i} \ge z_{\mathrm{buffer}_i} + \text{Bias}\) 时返回 \(1.0\)(表示被遮挡),否则返回 \(0.0\)。
二、 采样核(Sampling Kernel)的设计与演进
采样核的几何分布和随机化策略直接决定了 SSAO 的画面质量与性能开销。
1 | 球体采样核 (Sphere Kernel) 法线定向半球采样核 (Oriented Hemisphere) |
1. 从球体采样(Sphere Kernel)到法线定向半球采样(Oriented Hemisphere)
- 球体采样核(Sphere Kernel):早期 SSAO 在以 \(\mathbf{p}\) 为中心的 3D 球体空间内随机均匀分布采样点。这种方式的严重缺陷在于,平整表面下方近乎半数的采样点会天然落入几何体内部,导致平面被误判为被遮挡(自遮挡,Self-Occlusion),产生不真实的灰色暗斑。
- 法线定向半球采样核(Oriented Hemisphere Kernel):现代 SSAO 获取 G-Buffer 中的像素法线 \(\mathbf{n}\),在以法线为中心轴的半球空间(Oriented Hemisphere)内分布采样点,从根本上消除了平坦表面的自遮挡现象。
2. 采样点分布曲线(Scale Power Distribution)
如果采样点在半球内完全均匀分布,会导致靠近着色点 \(\mathbf{p}\) 处的采样密度不足,丢弃高频微小折痕的遮挡细节;同时,较远的采样点容易产生带状带状噪声(Banding Artifacts)。
工程上通常使用非线性指数衰减曲线重新分配采样点的距离模长,使采样点集中密布在原点附近:
\[ \mathbf{s}_i = \mathbf{v}_i \cdot \mathrm{scale}_i \]
\[ \mathrm{scale}_i = \mathrm{lerp}\left(0.1, 1.0, \left(\frac{i}{N}\right)^2\right) \]
式中 \(i \in [0, N-1]\),二次方曲线 \((\frac{i}{N})^2\) 使得大量采样点贴近原点,极大地增强了近距离微遮蔽的细节感知。
3. 随机旋转向量与 4x4 噪声纹理(Random Rotation & Jittering)
为了在极低的采样数(如 \(N = 16 \sim 32\))下消除明显的采样带状图样(Banding),必须引入抖动(Jittering): 1. 创建一张尺寸仅为 \(4 \times 4\) 的随机旋转向量纹理(Random Noise Texture),纹理像素存放随机的切向向量 \(\mathbf{r} \in [-1, 1]^3\)。 2. 在片段着色器中,按屏幕像素坐标平铺采样(Tile Sampling)该噪声图。 3. 利用采样得到的随机向量与像素法线 \(\mathbf{n}\) 构建施密特正交化切线空间矩阵(TBN Base),将固定半球采样核旋转至随机切向空间。
这样可以将原本规则的低采样图样转化为高频噪点(High-Frequency Noise),后续只需施加一次轻量级的图像空间双边滤波(Bilateral Blur)即可获得平滑无噪的阴影。
三、 关键瑕疵(Artifacts)与工程修正
1. 深度不连续与黑晕现象(Shadow Haloing & Bleeding)
- 成因:当背景物体(如远处的墙面)的采样点投影回屏幕后,其深度值与前景物体(如近处的角色手肘)在屏幕上重叠,但两者在视空间实际距离极远。算法会将远景采样点误判为被前景物体遮挡,产生向外扩散的黑色晕影(Shadow Haloing)。
1 | 相机 Ray ──> 前景物体 (Depth z_fg) |
- 解决方案:范围衰减检查(Range Check / Distance Attenuation) 引入基于深度差的平滑衰减权重 \(W_{\mathrm{range}}\)。当采样点深度与当前片元深度的绝对差值超过预设半径 \(R\) 时,快速将该采样点的遮挡贡献衰减至 0:
\[ W_{\mathrm{range}} = \mathrm{smoothstep}\left(1.0, 0.0, \frac{|z_{\mathbf{p}} - z_{\mathrm{buffer}_i}|}{R}\right) \]
修正后的离散遮挡累加项为:
\[ \text{Occlusion}_i = \chi\left(z_{\mathrm{sample}_i} - (z_{\mathrm{buffer}_i} + \text{Bias})\right) \cdot W_{\mathrm{range}} \]
2. 深度偏置(Depth Bias / Self-Shadowing Acne)
受限于 Depth Buffer 的浮点数精度以及视空间坐标重建误差,靠近切线的采样点可能微小穿透深度表面,造成高频黑点(Acne)。引入一个极小的常数偏置 \(\mathrm{Bias} \approx 0.025\) 即可完美解决。
四、 图像空间降噪:深度/法线感知双边滤波 (Cross-Bilateral Filter)
由于采样阶段使用了 \(4 \times 4\) 噪声图进行随机旋转,SSAO 原始输出带有明显的高频颗粒噪声。直接使用标准高斯模糊(Gaussian Blur)抹平噪点会导致物体边缘(如墙角、物体轮廓)模糊消隐,破坏空间几何边界。
必须采用交叉双边滤波(Cross-Bilateral Filter),在模糊的同时根据深度梯度与法线相似度保护几何边缘。
1 | +-----------------------------------------------------------------------+ |
双边滤波加权公式
对于中心像素 \(p\),在其邻域 \(q \in \Omega\) 内累加采样,加权系数 \(w(p, q)\) 联合定义为:
\[ w(p, q) = G_{\sigma_s}(\|p - q\|) \cdot \exp\left(-\frac{|z_p - z_q|}{\sigma_z}\right) \cdot \max(0.0, \mathbf{n}_p \cdot \mathbf{n}_q)^m \]
其中: * \(G_{\sigma_s}(\|p - q\|)\) 为高斯空间距离权重(Spatial Weight)。 * \(\exp\left(-\frac{|z_p - z_q|}{\sigma_z}\right)\) 为深度相似度权重:若邻域像素 \(q\) 与中心像素 \(p\) 的深度差过大(跨越几何边缘),权重剧降为 0。 * \(\max(0.0, \mathbf{n}_p \cdot \mathbf{n}_q)^m\) 为法线相似度权重:若两像素法线夹角过大(折角处),权重降为 0。
五、 GLSL 工程完整源码实现
1. SSAO 核心片段着色器 (SSAO Pass)
1 |
|
2. 深度/法线感知双边滤波着色器 (Blur Pass)
1 |
|
六、 现代屏幕空间 AO 技术演进选型矩阵
| 评估维度 | SSAO ( Crytek 2007) | HBAO (NVIDIA 2008) | GTAO (Activision 2016) | RTAO (硬件光追) |
|---|---|---|---|---|
| 几何采样空间 | 屏幕空间半球点采样 | 屏幕空间地平线仰角步进 | 半球切面扇区闭式积分 | 3D BVH 几何求交 |
| 物理正确性 | 较低(经验性近似) | 中等(考虑地平线遮蔽) | 极高(接近光追真值) | 物理真实 |
| 边缘黑晕瑕疵 | 明显(依赖 Range Check) | 较少 | 极少 | 无 |
| 与 PBR 积分匹配 | 无法直接匹配 | 部分匹配 | 完美的余弦加权积分 | 完美匹配 |
| GPU 计算开销 | 极低 (~0.5ms) | 中等 (~1.2ms) | 中高 (~1.8ms) | 高 (~3.5ms+) |
| 硬件要求 | 任意移动/PC GPU | 标准 PC / 高端移动 GPU | 工业级现代 GPU | 支持 DXR / Hardware RT GPU |
七、 总结
屏幕空间环境光遮蔽(SSAO)凭借其“解耦几何复杂度”与“纯后处理计算”的思想,奠定了现代实时图形管线中环境光遮蔽的基础: * 数学核心在于将半球环境光积分离散化为视空间 Depth Buffer 的深度校验; * 工程成败在于利用 4x4 旋转噪声降低采样数,配合 Range Check 消除黑晕,并施加 Cross-Bilateral Filter 保护几何边缘; * 尽管现代 AAA 游戏正全面向 GTAO 和 RTAO 演进,SSAO 凭借其极低的算力开销,依然是中低端设备与移动端游戏提升画面空间感的不二之选。