GPU Gems 2 · Chapter 17. Efficient Soft-Edged Shadows Using Pixel Shader Branching

用单张 shadow map 的 percentage-closer filtering 近似软阴影,再用 jittered/stratified offsets 和 fragment branching 只为 penumbra 承担高采样成本。

学习目标

  • 能说明 shadow map 与 stencil shadow volume 的适用边界,以及为什么 PCF 可以从单张 shadow map 得到软边缘
  • 能把多个偏移 depth comparisons 平均成 percentage-closer filtering,而不是直接模糊 depth 值
  • 能用 stratified/jittered offsets 将规则采样 banding 转换为可隐藏的高频误差
  • 能设计“少量 estimator → penumbra 扩采样 → fully lit/dark early-out”的 adaptive branch
  • 能评估动态 branching 的局部 coherence、shadow acne/bias 和纹理带宽成本

软阴影的关键是把“光源有面积”转成屏幕上可控的半影。只需一张:在当前 fragment 的投影坐标附近反复查询它,而不必为每个 area-light sample 重渲染整套 shadow map。

1. PCF:平均比较结果而非深度

先把 fragment 变换到 light space,得到 projected coordinate 和 receiver depth。每次 texture comparison 返回“该 offset 是否被遮挡”的比例,再对这些结果求平均。offset radius 越大,边缘看起来越软;它不改变 shadow map 中的 z,也就不会制造虚假的中间表面。

one shadow map → many comparisons → soft edgeshadow mapdepth compareoffset samplescompare → averagesoftshadow样本数 ↑ 与 filter radius ↑ 会改善 penumbra,也会增加 bandwidth
PCF 不模糊 depth 值,而是对多个偏移坐标的深度比较结果求平均;偏移半径决定边缘柔软度。

直接用固定规则 offset 在很小 penumbra 上有效,但半影变宽后需要很多 sample,否则各个离散硬边会形成 banding。PCF 是视觉近似,不是物理精确的 area-light visibility;它的优势是兼容普通 shadow-map pipeline,代价集中在 fragment texture bandwidth。

2. jittered sampling 让误差不再成带

把 square domain 分成若干 strata,在每格内随机取一个点,再做 area-preserving square-to-disk warp。这样 disk 中心和边缘不会因为简单极坐标映射产生密度偏差。

regular grid → stratified jitter → disk offsetsregular stratajitter in each celldisk warpstrata 保证覆盖,jitter 隐藏采样规则带来的 color bands
规则 grid 会形成 banding;每个 strata 内做 jitter,再映射到 disk,可把规律误差换成更容易隐藏的高频噪声。

每个像素使用略有不同的 offset 序列,规则误差被换成更高频的 noise;视觉上通常比明显条带更容易接受。可以把生成成本移出渲染 loop,并让相邻屏幕区域使用不同序列。两个二维 offset 可以打包进一个 RGBA texel,减少纹理深度和读取次数。

3. 只在 penumbra 做高成本采样

大多数像素不是半影:它们完全亮或完全暗,一次比较通常就足够。才是高采样预算的目标。先用少量、也经过 jitter 的 estimator samples 估计局部 coverage;若结果接近 0 或 1,直接返回;若落在中间区域,再执行完整 PCF。

estimate → branch → adaptive sample budgetestimatelitdarksoftbranchearly outfull PCFresultlow costwhere possiblebranch 只有在局部像素路径一致时才真正高效
只在 penumbra 做高成本 PCF;完全亮或完全暗的像素可以 early-out,省下纹理带宽和 fragment ALU。

这种 adaptive sampling 把固定的 64 samples 变成“估计成本 + 只有必要像素的完整成本”。但 branch 本身有代价:GPU 以 tile/warp 为单位并行,如果同一局部既有 fully lit 又有 penumbra,路径会发散,跳过的采样不一定能转化为吞吐收益。

4. branch coherence 与 shadow acne

决定 adaptive 分支的实际收益。让 estimator 取样具有空间连续性,或让 jitter 频率足够高但不让 branch classification 在相邻像素间剧烈抖动,通常更容易保持 coherence。

branch coherence:same path good, divergence expensivecoherent tileall early-out togetherdivergent tilepaths serialize / lose benefit让 estimator 具有空间连续性,尽量让相邻 pixels 选择相同 branch
动态 branching 并非免费:邻域像素选择同一分支时能保留并行,路径发散时收益会被 pipeline 和 SIMD 利用率抵消。

shadow acne 是 shadow map 深度精度和重采样造成的自遮挡伪影。常见缓解方式是用 back faces 生成 shadow map,把 acne 移到不受当前光源照亮的面;也可以使用 depth bias 或 midpoint shadow map。若 estimator 在背光面仍错误地判断为 penumbra,会让分支 coherence 和成本都变差,因此应把 dot(N, L) <= 0 等表面朝向信息纳入判定。

5. 动手实验:质量和 early-out 预算

下面的实验把 PCF samples、penumbra radius、branch coherence 和 adaptive mode 暴露出来。提高 samples 会降低 banding;提高 penumbra 会要求更可靠的覆盖;coherence 越高,adaptive early-out 越可能真正省下工作。

Adaptive soft-shadow 实验

观察 PCF 样本、penumbra、分支一致性与 early-out 如何共同影响阴影质量和成本。

32 PCF samples · adaptivesoftness 99%banding risk 6%estimated active work 21 · coherence 78%示意值:真实质量还受 shadow-map resolution、bias 与投影方式影响

先估计再扩采样;局部路径越 coherent,early-out 越有价值。 高 penumbra 仍需要更多 offsets。

小结

  • shadow map 保持 light-space depth,PCF 对多次 depth comparison 求平均,产生软边缘。
  • stratified/jittered offsets 与 jitter map 打散规则采样,缓解宽半影的 banding。
  • estimator 先区分 fully lit/dark 与 penumbra,只有后者执行高成本 PCF。
  • branch coherence 是 fragment branching 能否加速的关键;路径发散会损失并行度。
  • 处理 shadow acne、bias、背面 shadow map 与 projection 限制,才能让估计稳定。

练习

问题 1|PCF 数据 为什么 PCF 应该平均 shadow comparisons,而不是先把 shadow map 的 depth 做 blur?

问题 2|采样分布 如何用 jittered sampling 减少大 penumbra 的 banding?

问题 3|adaptive branch 为什么“先估计、再按需扩采样”不一定加速?实现时应检查什么?

名词解释

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

shadow map
从光源视角渲染的 light-space 深度纹理。
percentage-closer filtering
平均多个深度比较结果以产生软阴影边缘的过滤方法。
stratified jittered sampling
在等面积 strata 内扰动采样,再映射到 disk 的分布策略。
jitter map
保存多组 per-pixel 随机 offset 序列的预计算纹理。
penumbra
软阴影从亮到暗的过渡区域。
branch coherence
相邻 fragment 选择相同动态分支、维持并行执行的程度。
shadow acne
shadow-map 深度精度/采样造成的自遮挡伪影。

讨论

评论区加载中…