软阴影 PCF 与 PCSS
Soft Shadows with PCF & PCSS
百分比渐近过滤 (PCF) 在阴影贴图上取多个样本,分别与表面深度比较后混合结果,得到伪软阴影,但半影宽度恒定。PCSS 先搜索附近遮挡体的平均深度,再据此决定过滤宽度,从而在接触处硬、远处软(接触硬化)。
PCF
- 类似纹理放大:取最近四个样本,不插值深度本身,而是插值比较结果(阴影 0、受光 1),得到人为的软边。半影随阴影贴图分辨率、相机位置等变化,分辨率越高软边越窄。有一点半影和平滑总比没有好,也能缓解阴影块状感。
- 物理上,面光源下某点的受光量取决于从该点能看到多少光源面积。PCF 把过程反过来:对点光源/方向光,在原位置附近一组表面位置(深度相近、纹素不同)上检查可见性,求可见样本的百分比。这是非物理的,到遮挡体的距离不影响结果,所以半影大小都相似,但在许多情况下是合理近似。
- 采样变量:区域宽度、样本数、样本图案、权重。老 API 中有类似双线性的特殊采样模式,比较四个邻居后返回通过比例;DirectX 10 引入了单指令双线性 PCF。
- 规则网格最近邻采样会出现明显伪影;可用尊重物体边缘的联合双边滤波模糊。预计算泊松分布图案让样本既不靠近也不规则;每像素使用相同样本位置仍会出图案,逐像素随机旋转样本分布可把混叠变成噪声。Castaño 发现泊松噪声在平滑风格化内容上特别明显,提出基于双线性采样的高效高斯加权方案。
PCF 的偏移问题
- PCF 会加重痤疮和 Peter Panning:斜率偏移假设样本离原位置不超过一个纹素,而大范围采样时部分样本会被真实表面挡住。
- 偏移锥 (Burley):每个样本按离原样本的距离向光源移动,推荐斜率 2.0 加少量常数偏移。
- 接收平面深度偏移:用接收体自身的斜率调整其他样本深度,假设邻近样本在三角形平面上;Tuft 的公式最容易用于级联阴影。凸表面上很精确,但凹处样本会被挡住。
- 常数、斜率、接收平面、视线方向和法线偏移常组合使用,仍可能需要针对每个环境手调。
PCSS (Fernando, 2005)
- 在阴影贴图附近区域搜索所有可能的遮挡体,用平均遮挡体距离决定采样宽度: 为接收体到光源距离, 为平均遮挡体距离。遮挡体离接收体越远、离光源越近,采样区域越宽。
- 没找到遮挡体则完全受光、完全被遮挡也可提前结束;否则再采样估计光照贡献。可按采样宽度调整样本数,远处软阴影可用更低采样率。
- 缺点:搜索遮挡体要采样相当大的区域。旋转泊松盘可隐藏欠采样;Jimenez 发现泊松采样在运动下不稳定,用介于抖动与随机之间的函数生成的螺旋图案逐帧更稳定。
- 基本 PCSS 的半影大小还受阴影贴图分辨率影响。
CHS 与加速
- 接触硬化阴影 (CHS):AMD 用 SM 5.0 特性的更快 PCSS 实现。先生成阴影贴图的 mipmap,选与用户定义的世界空间核大小最接近的 mip 层;8×8 区域找平均遮挡深度只需 16 次
GatherRed();锐利区域用高分辨率 mip,较软区域用低分辨率 mip。已被大量游戏使用。 - 可分离软阴影贴图 (SSSM):把 PCSS 网格采样拆成可分离部分,并尽量在像素间复用。
- 分层 min/max 阴影贴图:深度不能平均,但可以建两套 mipmap 分别存每块区域的最大深度(有时叫 HiZ)和最小深度,快速判断完全受光或完全阴影;例如纹素深度大于该区域最大深度,则必在阴影中,无需更多样本。
局限
- PCF、PCSS 都不直接考虑光源面积,而是采样附近表面,并受阴影贴图分辨率影响。
- PCSS 的主要假设是平均遮挡体能合理估计半影大小。两个遮挡体(如路灯和远山)同时部分遮挡一个像素时这个假设失效,产生伪影。例如《The Division》中树枝阴影与箱子角重叠时 PCSS 出错,与 IZB 硬阴影混合后改善。
- 反投影方法把接收点当视点、把面光源当视平面,将遮挡体投影上去,结果很好,但每像素开销高,至今未被交互应用采用。
对比
| 方法 | 半影 | 主要代价/问题 |
|---|---|---|
| PCF | 宽度恒定 | 软阴影需要更多样本;接触处不真实 |
| PCSS | 随遮挡体距离变化 | 遮挡体搜索开销;多遮挡体时出错 |
| CHS | 同上,减轻分辨率影响 | 需要阴影贴图 mipmap |
LearnOpenGL 的视角:教学用邻域 PCF(Shadow Mapping / Point Shadows)
来源:同章 Shadow Mapping、Point Shadows 末节。
方向阴影:在投影 UV 上对 depth map 做固定核(如 3×3)先比较后平均。点阴影:在立方体方向上采样偏移。这是「先比较后过滤」的入门形态;产品级可变核、遮挡物搜索与接触硬化见上文 PCSS。与 级联阴影贴图、虚拟阴影贴图(UE)衔接时,PCF 仍是各 cascade/页的基础软边手段。
GPU Gems 的视角:PCSS 的过滤步用 SAVSM 加速(GPU Gems 3 第 8 章)
来源:同 Lauritzen 第 8 章 8.6 节;摘录见 Chapter 8. Summed-Area Variance Shadow Maps — Andrew Lauritzen。与上文 Fernando PCSS 流程对照。
PCSS 三步(遮挡搜索 → 相似三角形估计半影 → 过滤)里,过滤步原本是均匀网格 PCF。把该步换成求和面积方差阴影贴图后,任意矩形核恒定开销,大核软阴影不再随核宽线性变贵。遮挡搜索仍要对阴影图做深度比较,会把 PCF 时代的偏置问题重新带回来,也仍是整条管线的瓶颈之一;但在同等 64 次遮挡采样的困难场景里,作者测得 SAVSM 版约 40 FPS、PCF 版约 25 FPS(1600×1200),且稀疏 PCF 采样质量更差。结论:SAVSM 很适合嵌进「可变核宽软阴影」;固定核宽则优先普通模糊 VSM。
GPU Gems 的视角:分支自适应软边阴影(GPU Gems 2 第 17 章)
来源:Yury Uralsky《Efficient Soft-Edged Shadows Using Pixel Shader Branching》;摘录 Chapter 17. Efficient Soft-Edged Shadows Using Pixel Shader Branching — Yury Uralsky。单张阴影图 + 片元动态分支上的分层抖动 PCF,GeForce 6 时代把软边做进实时。
不模糊深度,而模糊比较结果。固定偏移 PCF 在大半影出条带;分层抖动(方格 strata → 保面积圆盘映射)把误差变成高频噪声。3D jitter 图:屏幕分块 、沿 存不同偏移序列,每 texel 塞两对偏移。
关键优化:先在圆盘外环取少量估计样本;若全 0 或全 1(且 )则跳过剩余采样——大半影外像素几乎免费。分支局部一致性决定并行 GPU 收益;背面阴影图 + 抑制粉刺假半影。硬件双线性 PCF 免费叠加。相对固定 64 样本可 >2×。非物理面光源半影;透视阴影图等非常规投影需每像素调半影尺寸。与后文 PCSS / SAVSM 对照:本章是「分支省样本的经典 PCF」,PCSS 加接触硬化,SAVSM 走矩/卷积。
GPU Gems 的视角:阴影图抗锯齿与经典 PCF(GPU Gems 1 第 11 章)
来源:Bunnell & Pellacini《Shadow Map Antialiasing》;摘录 Chapter 11. Shadow Map Antialiasing — Michael Bunnell & Fabio Pellacini。不能预过滤深度,只能平均多次比较——实时 PCF 的奠基表述。
相对 REYES 随机微多边形区域,本章固定用约 texel 核。NVIDIA 硬件一次给出 双线性 PCF;扩到 需 16 次比较。屏幕相关 4 样本抖动子集(从 16 里挑)用抖动换灰度,质量接近、开销约 1/4。固定核在投影放大时仍有效,因邻像素滤波重叠会再平均。后续 Gems2 Ch17 在此之上加分支与分层抖动半影。
出处
- realtime_rendering_4ed.pdf 第 7 章 Shadows
- Chapter 8. Summed-Area Variance Shadow Maps — Andrew Lauritzen
- developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-8-summed-area-variance-shadow-maps
- Chapter 17. Efficient Soft-Edged Shadows Using Pixel Shader Branching — Yury Uralsky
- developer.nvidia.com/gpugems/gpugems2/part-ii-shading-lighting-and-shadows/chapter-17-efficient-soft-edged-shadows-using
- Advanced Lighting — Shadow Mapping
- Advanced Lighting — Point Shadows
- Chapter 11. Shadow Map Antialiasing — Michael Bunnell & Fabio Pellacini
- developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-11-shadow-map-antialiasing