深入解析环境光遮蔽(Ambient Occlusion, AO):多尺度解构、SSAO/HBAO/GTAO 原理与 PBR 融合实践

深入解析环境光遮蔽(Ambient Occlusion, AO)

环境光遮蔽(Ambient Occlusion, AO)是实时图形学与 PBR(基于物理的渲染)管线中至关重要的视觉要素,它通过模拟漫反射光线被周围几何体遮挡的程度,作为一种重要的暗化因素在各种尺度下重建阴影 。

本文将从 多尺度遮蔽分级屏幕空间 AO 算法演进(SSAO/HBAO/GTAO)PBR 镜面遮蔽(Specular Occlusion)与过暗融合GLSL 着色器工程实现 进行全面深度扩展。


一、 多尺度遮蔽架构 (Multi-Scale Occlusion Framework)

在实时渲染管线中,环境光遮蔽根据其作用的几何尺度,被划分为三个核心层次 :

1
2
3
4
5
6
7
8
9
10
11
12
+-------------------------------------------------------------------------+
| 多尺度环境光遮蔽 (Multi-Scale AO) |
| |
| +-------------------+ +-------------------+ +-------------------+ |
| | 1. 微遮蔽 | | 2. 宏/中尺度遮蔽 | | 3. 大尺度遮蔽 | |
| | (Micro-occlusion)| | (Macro-occlusion)| | (Large-scale AO) | |
| | 微小折痕、裂缝 | | 物体自身/法线细节| | 物体间接触遮蔽 | |
| +-------------------+ +-------------------+ +-------------------+ |
| | | | |
| v v v |
| BaseColor 烘焙 AO 贴图材质参数 SSAO / GTAO / RTAO |
+-------------------------------------------------------------------------+

1. 小尺度:微遮蔽 (Micro-occlusion)

  • 作用范围:用于处理极其微小的几何结构,如折痕、裂缝和空洞 。
  • 烘焙与存储策略:理论上应在漫反射贴图中预先烘焙漫反射微遮蔽,并在反射纹理中预先烘焙镜面微遮蔽 。在实际渲染系统中,如果明确知道镜面光不受微遮蔽的影响,微遮蔽可以简单地直接烘焙在基色图(Base Color Map)中 。

2. 中等尺度:宏遮蔽 (Macro-occlusion)

  • 作用范围:用于处理物体自身几何体的遮蔽,或法线贴图(如砖块缝隙、墙面雕刻等)中烘焙出的几何体遮蔽 。
  • 烘焙与存储策略:中等尺度的环境遮蔽通常在纹理制作阶段预烘焙至环境遮蔽贴图(AO Texture)中,并在 Shader 中作为材质参数(Ambient Occlusion)提供 。

3. 大尺度遮蔽 (Large-scale Occlusion)

  • 作用范围:遮蔽来自物体之间的相互接触(如脚底与地面、墙角交界处),或来自物体自身跨度较大的几何遮蔽 。
  • 计算策略:大尺度的环境光遮蔽通常使用屏幕空间技术(Screen-Space Techniques)实时计算,例如 SSAO、HBAO、GTAO 等 。
  • 距离关联特性:值得注意的是,当相机足够接近物体表面时,这些屏幕空间技术也可用于捕捉中等尺度的环境遮蔽细节 。

二、 屏幕空间遮蔽算法演进 (Screen-Space AO Evolution)

实时渲染中,大尺度环境光遮蔽(Large-scale AO)经历了从早期近似采样到物理精确积分的演进 。

1
2
3
4
+------------------+     +------------------+     +------------------+
| SSAO (2007) |====>| HBAO (2008) |====>| GTAO (2016) |
| 半球/球体随机采样| | 屏幕空间地平线采样| | 物理半球扇区积分 |
+------------------+ +------------------+ +------------------+

1. SSAO (Screen-Space Ambient Occlusion)

由 Crytek 在 Crysis (2007) 中率先引入 。 * 基本原理:以当前像素的视空间 3D 坐标为中心,在其四周(球体或沿法线半球)随机生成若干采样点 。将采样点投影回屏幕空间,对比该采样点的深度值与 Depth Buffer 中的实际深度值 。若采样点位于深度表面下方,则计为被遮挡 。 * 局限:缺乏物理基础,采样点容易受到深度不连续(如前景物体误遮挡远景)影响,产生严重的暗斑与“黑晕”瑕疵 。

2. HBAO (Horizon-Based Ambient Occlusion)

由 NVIDIA 提出,引入了基于物理地平线角度的几何积分 。 * 基本原理:在屏幕空间以当前像素为中心沿着多个 2D 方向(Ray Directions)步进,记录极坐标系下的最大地平线仰角(Horizon Elevation Angle \(\theta\) 。 * 优势:结合表面法线向量,对半球积分进行切片累加,显著降低了误遮挡现象,边缘更加清晰 。

3. GTAO (Ground Truth Ambient Occlusion)

由 Activision 在 2016 年提出,是现代引擎(如 Unreal Engine 5、Decima Engine)中最常用的屏空 AO 方案 。 * 基本原理:将半球积分公式推导分解为切面视角(Multi-slice Horizon Angle)计算,通过闭式解(Closed-form Solution)精确解算出余弦加权的半球遮挡率 。 * 优势:在数学和物理上极其接近光线追踪环境光遮蔽(RTAO)的结果,且能极好地拟合 PBR 管线中的半球漫反射 。


三、 多尺度 AO 的融合与 PBR 镜面遮蔽 (Specular Occlusion)

在 PBR 渲染管线中,直接将多尺度 AO 简单相乘会导致场景边缘过度变暗或破坏镜面高光 。

1. 混合遮蔽:解决过度变暗问题 (Double Darkening)

当同时使用预烘焙的中等尺度遮蔽 \(\mathrm{AO}_{\mathrm{medium}}\) 和屏幕空间实时的大尺度遮蔽 \(\mathrm{AO}_{\mathrm{large}}\) 时,二者容易在凹陷区域重叠,造成场景被二次暗化(Double Darkening) 。

为了防止在使用中等和大尺度遮蔽时过度变暗,Lagarde 提出了经典的最小权值组合公式 :

\[ \mathrm{AO}_{\mathrm{final}} = \min\left(\mathrm{AO}_{\mathrm{medium}}, \mathrm{AO}_{\mathrm{large}}\right) \]

这种策略取两者中的最强遮挡值,既保留了材质贴图中的高频暗部细节,又避免了屏空 AO 在叠加时产生的黑斑 。


2. 镜面反射遮蔽 (Specular Occlusion, SO)

标准的 AO 仅作用于漫反射环境光(Diffuse Indirect Light) 。如果在强镜面反射(如高光金属、湿润表面)区域直接应用漫反射 AO,会导致高光在裂缝中错误地保留,或者相反地被无脑抹去 。

为了解决这一问题,引擎通常根据表面粗糙度(Roughness)观察视角(\(\mathbf{N} \cdot \mathbf{V}\)以及漫反射 AO 实时推导出镜面反射遮蔽系数(Specular Occlusion, SO)

常见的 Lagarde / Gotanda 镜面遮蔽推导公式为:

\[ \mathrm{SO} = \operatorname{clamp}\left( \frac{(\mathbf{N} \cdot \mathbf{V} + \mathrm{AO})^2 - 1 + \alpha}{\alpha}, 0.0, 1.0 \right) \]

其中 \(\alpha = \mathrm{Roughness}^2\) 。当粗糙度较低(表面光滑)且观察角切向较大时,镜面反射遮蔽会适当保留高光反射,确保符合 PBR 能量守恒定律 。


四、 核心代码实现:SSAO 片段着色器 (GLSL)

以下展示了一个包含视空间重建随机旋转采样核法线定向半球积分的标准 SSAO Fragment Shader 示例 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#version 450
layout (location = 0) out float FragColor;

layout (location = 0) in vec2 inTexCoord;

// 深度与法线附件
layout (binding = 0) uniform sampler2D gDepth;
layout (binding = 1) uniform sampler2D gNormal;
layout (binding = 2) uniform sampler2D texNoise; // 4x4 随机旋转噪声图

const int KERNEL_SIZE = 32;
layout (std140, binding = 0) uniform SSAOUniforms {
mat4 projection;
mat4 invProjection;
vec4 samples[KERNEL_SIZE]; // 采样核向量
vec2 noiseScale; // 屏幕尺寸 / 4.0
float radius; // 采样半径
float bias; // 深度偏置,避免自遮挡
};

// 根据深度值与屏幕 UV 重建视空间坐标
vec3 GetViewPos(vec2 uv) {
float depth = texture(gDepth, uv).r;
vec4 clipSpacePos = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
vec4 viewSpacePos = invProjection * clipSpacePos;
return viewSpacePos.xyz / viewSpacePos.w;
}

void main() {
vec3 fragPos = GetViewPos(inTexCoord);
vec3 normal = normalize(texture(gNormal, inTexCoord).rgb);
vec3 randomVec = normalize(texture(texNoise, inTexCoord * noiseScale).xyz);

// 构建切线空间正交基 (TBN)
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);

float occlusion = 0.0;
for (int i = 0; i < KERNEL_SIZE; ++i) {
// 1. 将半球采样点变换至视空间
vec3 samplePos = TBN * samples[i].xyz;
samplePos = fragPos + samplePos * radius;

// 2. 将采样点投影回屏幕空间 UV
vec4 offset = vec4(samplePos, 1.0);
offset = projection * offset;
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5 + 0.5;

// 3. 读取采样点处的实际几何深度
float sampleDepth = GetViewPos(offset.xy).z;

// 4. 范围检查与遮挡因子累加
float rangeCheck = smoothstep(0.0, 1.0, radius / abs(fragPos.z - sampleDepth));
occlusion += (sampleDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck;
}

// 归一化并反转输出 (1.0 代表无遮挡,0.0 代表完全遮挡)
FragColor = 1.0 - (occlusion / float(KERNEL_SIZE));
}

五、 总结与技术方案对比

技术方案 计算阶段 捕捉尺度 物理真实度 带宽与算力开销 适用场景
BaseColor 烘焙 纹理制作 小尺度(微遮蔽) 较低 无开销 裂缝、孔洞、织物细节
AO 贴图材质参数 几何/材质 Pass 中等尺度(宏遮蔽) 中等 低(增加 1 通道纹理采样) 砖墙、模型表面雕刻细节
SSAO 后处理 Pass 大/中尺度 较弱(有黑晕瑕疵) 中等 中低端设备/移动端项目
GTAO 后处理 Pass 大/中尺度 极高(接近 Ray Tracing) 中高 AAA 级 PC/主机游戏
RTAO (硬件光追) Ray Traced Pass 极全(无视屏幕限制) 理论完美 极高 次世代高端硬件环境

环境光遮蔽通过微观、中观与宏观的联合作用,构建出阴影的层次感 : * 小尺度微遮蔽烘焙于 BaseColor 或漫反射贴图 ; * 中等尺度宏遮蔽通过 AO 贴图作用于材质 ; * 大尺度遮蔽依靠屏幕空间算法(如 GTAO)动态计算 ; * 在融合阶段使用 \(\mathrm{AO}_{\mathrm{final}} = \min(\mathrm{AO}_{\mathrm{medium}}, \mathrm{AO}_{\mathrm{large}})\) 消除过度暗化 ,并推导 Specular Occlusion,方可实现兼具高性能与物理正确性的 PBR 画面效果 。

本文作者:Berg Zha

本文链接:http://junglemanpro.com/2025/05/05/%E9%81%AE%E8%94%BD/

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

ESC 关闭 | 导航 | Enter 打开
输入关键词开始搜索