GPU Gems 3 · Chapter 12. High-Quality Ambient Occlusion

从层次圆盘近似出发,解释环境光遮挡的伪影来源,以及过渡区、三角形裁剪、迭代收敛和参数调节如何把软阴影与接触细节带回实时 GPU。

学习目标

  • 能解释环境光遮挡如何用层次圆盘近似远处表面,并指出它在片元着色中的计算位置
  • 能修改 Ambient Occlusion Lab 的采样方式、鲁棒路径、遍历深度和两个衰减参数,观察伪影与工作量的取舍
  • 能回答:为什么过渡区、可见三角形裁剪和 weighted minimum 分别解决哪一种错误,而不是简单提高网格密度

先问:附近的表面挡住了多少“天空”

想象你站在一间没有明确主光源的房间里。墙角、台阶缝和物体贴合处会比平面更暗,但这种暗不是一盏灯照出来的硬影子,而是附近表面挡住环境光的结果。

本章要解决的是:如何在实时 GPU 上保留这种柔和的整体暗部,又不把接触细节抹平。如果只在顶点上算再插值,稀疏网格会出现条带;如果每个片元都直接套原始近似,圆盘边界和顶点附近又会翻车。

1. 环境光遮挡:把“附近遮住多少”变成可累加的贡献

环境光遮挡(AO)不追踪一条条完整光线,而是把模型表面拆成许多近似小圆盘。对 receiver 点来说,每个圆盘贡献一个“它能挡住多少天空”的量;所有贡献相加,再映射成可见度或暗部。它适合表现大范围的柔和变化,也能作为局部接触阴影的基础。

GPU 的工作可以分成两段:先用较粗的圆盘层次反复更新遮挡纹理,再在可见片元阶段查询这棵树。这样,远处大面积表面不必逐三角形处理,近处才逐步展开到更精细的几何。

mesh → hierarchical disks → receiver occlusiontriangle mesh / surface samplesparent diskfar: acceptnear: descend to childrenreceiver pΣ form factors远处低频近似,近处高频细节:只在误差值得付费时展开树
远处用一个大圆盘近似许多面,近处再展开到更细的节点;自适应遍历把成对求和从 O(n²) 压到接近 O(n log n)。

2. 从 O(n²) 到自适应层次遍历

如果让每个 receiver 和每个表面元素配对,工作量近似是 O(n²)。做法是把相邻圆盘聚成 parent,再把 parent 聚成更大的 parent:远处用一个聚合圆盘就够,距离变近时才沿树向下。

这是一种 :它不是“永远走到叶子”,而是把可接受的误差换成少量节点访问。理想情况下,层次遍历把配对工作压到接近 O(n log n),但树的质量、遮挡分布和分支发散仍要用 profile 验证。

mesh → hierarchical disks → receiver occlusiontriangle mesh / surface samplesparent diskfar: acceptnear: descend to childrenreceiver pΣ form factors远处低频近似,近处高频细节:只在误差值得付费时展开树
远处用一个大圆盘近似许多面,近处再展开到更细的节点;自适应遍历把成对求和从 O(n²) 压到接近 O(n log n)。

3. 为什么逐顶点与逐片元都会暴露伪影

原始方案把遮挡写在顶点上,再在线性插值后覆盖三角形。它在密且规则的网格上很快,但 contact shadow 这类高频细节无法从几个顶点值恢复。把 shader 移到片元阶段能减少插值条带,却会把近似圆盘的缺陷放大出来。

original approximation:sampling rate 不是 robustnessper-vertexlinear interpolation bandsper-fragmentdisk boundary + vertex pinching诊断顺序插值条带 → 采样位置不够细;圆盘边界 → parent/children 离散切换;pinching → 点太靠近顶点圆盘,d² 让贡献爆炸修复应改变近似模型,而不是只把三角形数量乘大
提高采样率不能自动修好近似模型:逐顶点会留下插值条带,逐片元又会暴露圆盘边界和顶点附近的 pinching。

最典型的两类现象是:第一,树在“接受 parent”和“展开 children”之间发生离散切换,形成圆盘形的明暗边界;第二,receiver 接近顶点圆盘时,form factor 中的距离平方变得极小,单个圆盘贡献压过其他表面,形成 pinching。

在 transition zone 内保留 parent 的贡献,同时计算 children 的贡献,再按 receiver 到节点的距离混合。parent 的面积还要按 childArea / parentArea 调制,避免 parent 被每个 child 重复累加。

transition zone:把树的离散跳转摊平parent weight ≈ 1blend by distancechildren weight ≈ 1tooClose · (1 + r)tooClose · (1 − r)farthercloser to receiverparent contribution × (child area / parent area) + child contribution面积比避免 parent 被每个 child 重复计算
transition zone 把离散的停止/展开决定变成连续权重:外边界偏向 parent,内边界偏向 children,中间平滑过渡。

4. 用真实三角形找回接触细节

在层次树的最低层,圆盘已经不够准确。更稳健的做法是把圆盘放到三角形重心附近,然后对真实三角形计算 point-to-triangle 的 form factor。这里不能假设整个三角形都能被 receiver 看到:应该用 receiver 的位置与法线构造支持平面,先裁掉背后的部分。

裁剪时为每个顶点计算带符号距离,并用 epsilon 把“刚好落在平面上”的值归零。三个顶点的符号决定结果是空、完整三角形,还是由两个交点形成的可见四边形。这样做会增加分支和片元工作,却避免不可见面积被计入遮挡。

// 片段化的伪代码:先裁剪,再求可见三角形的贡献
float signedDistance(vec3 x, vec3 planePoint, vec3 planeNormal) {
  float d = dot(planeNormal, x - planePoint);
  return abs(d) < epsilon ? 0.0 : d;
}
 
for (int edge = 0; edge < 3; ++edge) {
  float a = signedDistance(v[edge], p, n);
  float b = signedDistance(v[(edge + 1) % 3], p, n);
  if ((a > 0.0) != (b > 0.0)) {
    visible.push_back(intersectPlane(v[edge], v[(edge + 1) % 3], a, b));
  }
}
occlusion += formFactor(visible) * pow(elementOcclusion, triangleAttenuation);
finest level:真实 triangle detail 进入 form factorbefore clippingsupport planereceiver p + normal nvisible portionclip to plane3 vertices → triangle/quadsigned distance + epsilon 处理 on-plane 顶点,避免边界抖动
先裁掉 receiver 背后的三角形区域,再对可见三角形或四边形计算 form factor;否则可见性会被系统性高估。

5. 让迭代稳定,并把“像不像”交给参数

层次 AO 用多次 pass 近似 visibility,但高遮挡场景可能在两个结果之间来回摆动。可以保存最近两次 disk occlusion,取偏向较小值的 weighted minimum,例如 0.7 * min(o0, o1) + 0.3 * max(o0, o1),让结果更容易收敛,也抑制普遍偏黑的趋势。

距离衰减控制远处贡献:加大后,远处环境不容易把整间封闭房间压成黑色。三角衰减作用在最低层的真实三角形:较小的指数会强调裂缝和台阶,较大的指数会降低大而远的三角形影响。它们是画质与艺术效果的旋钮,不是“更接近真值”的分数。

iterative AO:收敛约束与可调参数pass k−1occlusion₀weighted minimum0.7 · min + 0.3 · maxstableless flickerless over-dark两个旋钮的语义distance attenuation ↑ → 远处贡献更快变亮;triangle attenuation ↓ → 细缝/台阶等小特征更突出它们改变的是目标函数,不是把近似结果冒充 ray-traced ground truth
原始迭代可能在高遮挡场景中来回摆动;对最近两次结果做偏向较小值的加权混合,再用距离和三角衰减控制过暗与局部细节。
performance ledger:画质提升来自有选择的额外工作coarse diskshierarchy passsmall batchvisible fragmentsadaptive traversalhigh-quality factorresultsmooth shadowsharp contactprofile first关注 total fragments、tree visits 和 branch cost;高质量 form factor 更稳健,但分支多、batch 小,吞吐可能下降
高质量路径把额外工作集中在可见片元和近处细节:层次阶段减少远处遍历,裁剪阶段避免为不可见三角形计算 form factor。

6. 三步把近似变成可验收的 shader 路径

分步1 / 3

先选可接受的层次近似

先从 hierarchy 的根节点开始,按 receiver 距离判断当前 parent 是否足够好。远处直接累加 parent,近处把同一分支展开到 children;不要一开始就把所有叶子送进片元程序。

mesh → hierarchical disks → receiver occlusiontriangle mesh / surface samplesparent diskfar: acceptnear: descend to childrenreceiver pΣ form factors远处低频近似,近处高频细节:只在误差值得付费时展开树
远处用一个大圆盘近似许多面,近处再展开到更细的节点;自适应遍历把成对求和从 O(n²) 压到接近 O(n log n)。
performance ledger:画质提升来自有选择的额外工作coarse diskshierarchy passsmall batchvisible fragmentsadaptive traversalhigh-quality factorresultsmooth shadowsharp contactprofile first关注 total fragments、tree visits 和 branch cost;高质量 form factor 更稳健,但分支多、batch 小,吞吐可能下降
高质量路径把额外工作集中在可见片元和近处细节:层次阶段减少远处遍历,裁剪阶段避免为不可见三角形计算 form factor。

High-Quality Ambient Occlusion Lab

猜一猜:把 traversal depth 调大,或把 sampling 从 vertex 切到 fragment,哪些伪影会下降,哪类 GPU 工作会上升?

per-fragment · smooth fix · depth 8receiver surface · darker means more local occlusion插值条带22%圆盘边界24%vertex pinching48%local detail 66%far brightness 59%work 88 units趋势示意:实际画质仍需用真实 GPU profile 验证

过渡区抑制 parent/children 的离散跳变;继续加深遍历会让残余断层更淡。

本章小结

  • 环境光遮挡用附近表面的累计遮挡塑造柔和暗部与接触细节
  • 层次圆盘让远处低频贡献少走节点,近处才展开到细节
  • transition zone 消除 parent/children 切换的圆盘形断层
  • visible-triangle clipping 避免把不可见面积计入 form factor
  • weighted minimum 与两个衰减参数共同控制收敛、亮度和细节

练习

问题 1|诊断采样伪影。

Lab 初始为 per-fragment + transition zone。把 sampling 切到 per-vertex,再把 robustness 切到 original。哪两条指标会明显变差?分别对应原章节中的什么问题?

问题 2|改一段 shader 逻辑。

把下面的单一贡献改成“只有在 receiver 支持平面上方的可见部分才累加”,并说明 epsilon 为什么不能删掉。

float contribution = formFactor(triangle, receiver);
occlusion += contribution * elementOcclusion;

问题 3|做场景选型。

一个建筑室内场景在多次迭代后出现“两个亮度结果来回切换”,同时封闭房间整体偏黑。你会先改哪三个地方?为什么不能只把 tessellation 加密?

名词解释

本章出现的专业名词,用大白话再讲一遍。

ambient occlusion
form factor
adaptive hierarchy
transition zone
visible-triangle clipping

资料与写作方式声明

本章以GPU Gems 3 · Chapter 12. High-Quality Ambient Occlusion权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…