提高Shadow Depth Maps性能的常用技术


目前项目组尚未开启Nanite, 故也一直没有好好地钻研过Nanite算法. 前段时间终于抽出业余时间, 静下心来认真学完了Games 104的Nanite一节内容, 收获颇多. 接下来打算以若干篇文章学透Nanite的技术要点, 本文先介绍提高Shadow Depth Maps性能的常用技术, 翻译自微软的技术博客文章《Common Techniques to Improve Shadow Depth Maps》.

参考材料
1. Common Techniques to Improve Shadow Depth Maps
2. 22.GPU驱动的几何管线-nanite (Part 1) | GAMES104-现代游戏引擎:从入门到实践
3. 22.GPU驱动的几何管线-nanite (Part 2) | GAMES104-现代游戏引擎:从入门到实践
4. Nanite

1978年首次引入的Shadow Depth Maps是一种为游戏添加Shadow的常用技术. 三十年后, 尽管硬件和软件都取得了进步, 但Shadow Artifacts—— 即边缘闪烁, Aliasing与其它精度问题仍然存在.
$\\$ 本文概述了一些常见的Shadow Depth Maps算法与常见Artifacts, 并介绍了几种可用于提高标准的Shadow Depth Maps质量的技术(实现难度从低到高). 在游戏中添加基础的Shadow Depth Maps通常很简单, 但理解Shadow Artifacts的细微差别却很有挑战性. 本文是为已经实现Shadow但不完全理解为什么会出现特定的Artifacts也不确定如何处理它们的中级图形开发人员编写的.
$\\$ 选择正确的技术来缓解特定的Artifact是非常重要的. 当Shadow Depth Maps的缺点得以解决时, 质量上的差异会令人印象深刻, 如下图所示. 正确地实现这些技术大大提高了Shadow Depth Maps的质量.

1. 回顾Shadow Depth Maps

Shadow Depth Maps算法是一种双Pass算法. 第一步在光空间中生成Shadow Depth Maps. 在第二步中, 比较每个像素在光空间中的深度与它在Shadow Depth Maps中的相应深度, 若不通过深度测试, 则说明该像素处于Shadow中.

1.1 Pass1

场景如上图所示. 在第一个Pass中(如下图所示), 从光的角度将几何图形渲染到深度缓冲中. 更具体地说, 顶点着色器将几何体转换至光空间下.

1.2 Pass2

在第二个Pass中(如下图所示), 顶点着色器会对每个顶点执行两次变换操作:
$\\$ $\cdot$ 首次变换将顶点转换至相机的视图空间, 并将结果作为位置信息传递给像素着色器.
$\\$ $\cdot$ 同时进行第二次变换, 通过光源的视图-投影-纹理矩阵将顶点转换, 并将结果作为纹理坐标传递给像素着色器.
$\\$ 这里使用的视图-投影-纹理矩阵与第一个Pass中渲染场景所使用的矩阵完全相同, 但额外增加了一个关键变换: 该变换会将NDC(其$x$分量值与$y$分量值均在区间$[-1, 1]$内) 中的点, 通过缩放与平移操作转换至纹理空间(其$x$分量值与$y$分量值均在区间$[0, 1]$内), 从而建立从三维场景到二维Shadow Depth Maps的映射关系.

2. Shadow Map Artifacts

Shadow Depth Maps算法是应用最广泛的实时Shadow算法, 但仍然会产生一些需要消除的Artifacts. 下面将总结可能出现的Artifacts类型.

2.1 Perspective Aliasing

Perspective Aliasing是一种常见的Artifact, 如下图所示. 当相机空间中的像素到Shadow Depth Maps中的纹素的映射非双射时, 就会发生这种情况. 这是因为相机空间中靠近近裁剪平面的像素距离更近, 需要更高的Shadow Depth Maps分辨率.

左边的图像中, Perspective Aliasing更明显; 相机空间中太多的像素关于Shadow Depth Maps的纹理坐标是相同的. 而在右图中, Perspective Aliasing相对而言较不明显, 因为在相机空间中的像素与Shadow Depth Maps中的纹素存在双射.

下图展示了Shadow Depth Maps与视锥体. 在相机附近, 相邻像素在相机空间中的位置更接近, 许多像素关于Shadow Depth Maps的纹理坐标是相同的. 远平面上的相邻像素关于Shadow Depth Maps的纹理坐标距离较远, 从而缓解Perspective Aliasing.
$\\$ 远平面上较亮的像素表示Low-Perspective Aliasing, 而近裁剪平面上较暗的像素则表示High-Perspective Aliasing.
$\\$ Shadow Depth Maps的分辨率也可能过高. 虽然更高的分辨率可缓解Perspective Aliasing, 但它可能导致小物体(如电话线) 不投射Shadow. 此外, 由于纹理访问模式, 分辨率过高可能会导致严重的性能问题.
$\\$ Perspective Shadow Maps(PSMs) 与光空间Perspective Shadow Maps(LSPSMs) 试图通过对光空间下的投影矩阵进行倾斜变换来解决Perspective Aliasing问题, 以便在相机附近提高Shadow Depth Maps的利用率. 不幸的是, 这两种技术都不能解决Perspective Aliasing问题. 将相机空间下的像素映射到Shadow Depth Maps中的纹素所需的参数化变换不能受到线性倾斜变换的约束, 一般使用对数参数化. PSMs在相机附近的Shadow Depth Maps使用了过高的分辨率, 导致远处的阴影质量很低, 甚至消失. LSPSMs在提高相机附近的分辨率与为远处的物体留下足够的细节之间找到了一个更好的中间方案. 在某些场景配置中, 这两种技术都退化为正交投影. 这种退化可以通过为视锥体的每个面渲染单独的Shadow Depth Maps来抵消, 尽管如此一来性能开销较为昂贵. 对数Perspective Shadow Maps(LogPSMs) 也为视锥体的每个面渲染一个单独的Shadow Depth Maps, 这种技术使用非线性光栅化在相机附近使用更高分辨率的Shadow Depth Maps. D3D10和D3D11类硬件不支持非线性光栅化.
$\\$ Cascaded Shadow Maps(CSM) 是处理Perspective Aliasing最流行的技术. 虽然CSM可以与PSM, LSPSM组合, 但这是不必要的.

2.2 Projective Aliasing

Projective Aliasing比Perspective Aliasing更难展示. 下图中突出显示的膨胀Shadow展示了Projective Aliasing. 当相机空间中的像素与光空间中的像素之间的映射非双射时, 就会出现Projective Aliasing, 这是由几何体相对于光源的朝向导致的. 当几何体的切面与光线平行时, 就会出现Projective Aliasing.

用于缓解Perspective Aliasing的技术也可以用于缓解Projective Aliasing. 当几何体表面法线与光线正交时, 会发生Projective Aliasing; 根据漫反射光照方程, 这类几何体表面应该接收较少的光.

2.3 Shadow Acne与错误的Self-Shadowing

Shadow Acne(如下图所示) 是图形渲染中因Self-Shadowing计算错误产生的术语, 其产生机制在于: 当Shader在比较像素的实际深度值与Shadow Depth Maps上对应纹素的深度值时, 被错误地判断为Self-Shadowing.
$\\$ Shadow Acne的另一个原因是, 光空间中像素的实际深度值与Shadow Depth Maps上对应纹素的深度值非常接近, 精度误差导致深度测试错误地失败. 造成这种精度差异的一个原因是深度图由固定功能的硬件光栅化管线生成, 而参与比较的深度值则由着色器实时计算得出. 此外, Projective Aliasing也会导致Shadow Acne.

如左图所示, 一些像素未能通过深度测试, 产生了斑点与波纹图案. 为了减少错误的Self-Shadowing问题, 应尽可能精确地计算光空间视锥体的近裁剪平面与远裁剪平面的边界范围. 此外, 采用基于斜率的深度偏移策略与其它类型的偏移策略亦是用于缓解Shadow Acne的常用解决方案.

2.4 Peter Panning

Peter Panning这一术语源自儿童读物中的经典角色, 其影子脱离身体后便获得了飞行能力. 这种Artifact表现为: 物体不投射Shadow, 产生与接触面分离并悬浮在空中的异常现象.

在左图中, Shadow与物体分离, 呈现一种漂浮效果.

消除表面Acne的一种技术是: 在光空间中对像素位置添加一个偏移量, 这被称为施加深度偏移. 当使用的深度偏移量过大时, 会产生Peter Panning现象, 此时过大的深度偏移量会导致深度测试被错误地通过. 与Shadow Acne现象类似, 当深度缓冲区的精度不足时, Peter Panning现象会变得更加显著. 精确计算近裁剪平面和远裁剪平面的范围, 也有助于避免Peter Panning现象的发生.

3. 改进Shadow Depth Maps的技术

添加Shadow是一个分阶段的技术实现过程. 首要步骤是实现基础的Shadow Depth Maps的功能验证. 第二阶段需对所有底层计算进行深度优化: 需确保相机空间的视锥体的近/远裁剪面的范围计算需精确贴合场景, 采用基于斜率的深度偏移策略等. 当基础的Shadow系统成功启用并达到最佳可视化效果后, 开发者可据此明确后续所需的高级算法, 以提升Shadow保真度至项目要求的标准. 本节将重点阐述实现高品质Shadow Depth Maps所需的基础优化技巧, 涵盖视锥体适配策略, 深度缓冲区精度控制及偏移参数调优等核心实践策略.

3.1 根据斜率调整深度偏移

如前文所述, Self-Shadowing可能导致Shadow Acne. 而过度施加深度偏移则会导致Peter Panning现象(物体看似在异常悬浮). 此外, 相对于光源方向的斜率绝对值较大的多边形, 其产生的Projective Aliasing问题会比其它多边形更为严重. 基于此特性, 每个Shadow Depth Map可能需要根据相对于光源方向的斜率绝对值, 动态应用差异化的深度偏移量. 这种基于几何特征的偏移调整机制, 正是根据斜率调整深度偏移技术的核心设计原理.
$\\$ 支持Direct3D 10的硬件具备根据多边形相对于观察方向的斜率对其深度施加偏移的能力. 这种机制的效果是: 当多边形相对于光源方向的斜率绝对值较大时, 会对其深度施加较大的偏移量; 而当多边形直接面向光源时, 则不会对其深度施加任何偏移. 如下图所示, 当未根据斜率调整深度偏移时, 同一表面上的两个相邻像素可能呈现投影与不投影交替出现的现象.

3.2 计算相机空间的视锥体, 使场景在其远裁剪平面上的投影尽可能贴合其远裁剪平面边界

对于相机空间的视锥体, 当场景在其远裁剪平面上的投影尽可能贴合其远裁剪平面边界时, 可提升Shadow Depth Maps的利用率. 如下图所示, 若采用任意视锥体或简单地将相机空间的视锥体与场景边界进行适配, 会导致更严重的Perspective Aliasing现象.

该视图是从光源的视角呈现的. 梯形表示相机空间的视锥体在光空间的视锥体的远裁剪平面上的投影, 覆盖在图像上的网格代表Shadow Depth Map. 右侧图像表明, 当场景与相机空间的视锥体在光空间的视锥体的远裁剪平面上的投影尽可能贴合时(左图表示不紧密贴合的情形, 右图表示紧密贴合的情形), 相同分辨率的Shadow Depth Maps能覆盖更多像素, 从而显著提升Shadow细节的精度和采样效率.
$\\$ 下图展示了场景与相机空间的视锥体在光空间的视锥体的远裁剪平面上的投影贴合的情形. 为进行投影计算, 构成相机空间的视锥体的八个顶点会被转换至光空间下. 随后, 通过提取光空间下八个顶点的$x$分量与$y$分量的最小值与最大值, 确定正交投影的边界范围.

也可以通过将相机空间的视锥体进行裁剪, 使其在光空间的视锥体的远裁剪平面上的投影包含于场景的AABB在光空间的视锥体的远裁剪平面上的投影, 以此获得更合适的相机空间的视锥体. 但这并不适用于所有情况, 因为这可能导致Shadow Depth Maps的利用率逐帧发生变化. 当Shadow Depth Maps的利用率需要保持每帧恒定时, 此类方法可能无法达到最佳效果.

3.3 计算近裁剪平面与远裁剪平面

近裁剪平面与远裁剪平面是计算投影矩阵所需的最后两个关键参数. 这两个裁剪面之间的距离越近, 深度缓冲区中的数值精度就越高.
$\\$ 深度缓冲区的位数通常为16位, 24位或32位, 其数值范围在0到1之间. 一般情况下, 深度缓冲区采用定点数格式, 靠近近裁剪平面的数值分布比靠近远裁剪平面的数值更密集. 深度缓冲区的可用精度取决于近裁剪面与远裁剪面的$z$分量比例. 通过尽可能缩小近/远裁剪平面的间距, 即使使用16位深度缓冲区也能满足精度需求. 采用16位深度缓冲区可在保证渲染精度的同时, 有效减少内存占用并提升处理速度.

3.4 基于AABB的近裁剪平面与远裁剪平面

一种简单且直观的计算近裁剪平面与远裁剪平面的方法是: 将场景的AABB转换至光空间下, 令变换后包围盒所有顶点的最小$z$分量值为$z_{min}$, 最大$z$分量值为$z_{max}$, 将近裁剪平面设定为与光空间的$z$轴垂直且通过$(0, 0, z_{min})$的平面, 将远裁剪平面设定为与光空间的$z$轴垂直且通过$(0, 0, z_{max})$的平面. 对于大多数场景与光源配置而言, 这种方法完全适用. 然而在最坏情况下, 这种策略会导致深度缓冲区的精度显著下降(如下图所示案例). 在该示例中, 近/远裁剪平面的间距范围比实际需求扩大了四倍.
$\\$ 下图中展示的相机空间的视锥体体积被刻意设计得较小. 该场景规模较大, 包含从相机延伸出去的众多柱状结构. 此时若直接采用场景的AABB的坐标范围来确定近/远裁剪平面并非最优方案(如下图所示). Cascaded Shadow Maps(CSMs) 算法需要针对这种微型视锥体结构, 精确计算出与之匹配的近/远裁剪平面参数.

3.5 基于视锥体的近裁剪平面和远裁剪平面

另一种计算近/远裁剪平面的技术方案是: 将相机空间的视锥体变换至光空间下, 并令变换后视锥体所有顶点的$z$分量最小值为$z_{min}$, $z$分量最大值为$z_{max}$, 将近裁剪平面设定为与光空间的$z$轴垂直且通过$(0, 0, $$ z_{min})$的平面, 将远裁剪平面设定为与光空间的$z$轴垂直且通过$(0, 0, $$ z_{max})$的平面. 下图展示了该方法的两个核心缺陷: 其一是当视锥体大小超出场景几何范围时, 这种计算方式会产生过度保守的裁剪范围(如下图中左侧所示); 其二则是近裁剪平面与远裁剪平面的设置可能过于紧凑, 导致部分物体投射的Shadow被错误剔除(如下图中右侧所示).

3.6 基于光空间的视锥体与场景相交结果的近/远裁剪平面计算方法

计算近/远裁剪平面的正确方法如下图所示. 首先通过光空间下视锥体所有顶点的$x$/$y$分量值范围, 确定光空间的正交视锥体的四个侧平面. 剩余两个平面(近裁剪平面与远裁剪平面) 的计算需分两步完成: 首先将场景包围盒与这四个已知的光空间的视锥体侧平面进行裁剪, 然后令裁剪后形成的新边界中最小的$z$分量值为$z_{min}$, 最大的$z$分量值为$z_{max}$, 将近裁剪平面设定为与光空间的$z$轴垂直且通过$(0, 0, z_{min})$的平面, 将远裁剪平面设定为与光空间的$z$轴垂直且通过$(0, 0, z_{max} $$ )$的平面. 该方法通过动态适配场景几何分布, 避免了传统方案中因固定裁剪范围导致的深度缓冲区精度损失的问题.

$\\$ 该算法的具体实现流程如下:
$\\$ $\cdot$ 空间变换: 首先将世界空间下的场景的AABB的8个顶点转换至光空间下, 此操作将三维裁剪问题简化为二维平面运算.
$\\$ $\cdot$ 平面降维: 在光空间下, 其正交视锥体的4个侧平面可被投影为二维直线($x$/$y$方向的水平/垂直线), 场景的AABB则表现为6个四边形面.
$\\$ $\cdot$ 三角形剖分: 将每个四边形拆分为2个三角形, 共生成12个裁剪基元, 为基于三角形的精确裁剪运算做准备.
$\\$ $\cdot$ 动态裁剪: 使用视锥体的4个已知平面(此时表现为二维直线) 对三角形进行裁剪. 当检测到落在$x$/$y$轴上的交点时, 同步对三维空间中的原始三角形进行截断操作.
$\\$ $\cdot$ 深度提取: 最终遍历所有裁剪后生成的三角形片段, 令其中最小的$z$分量值为$z_{min}$, 最大的$z$分量值为$z_{max}$, 将近裁剪平面设定为与光空间的$z$轴垂直且通过$(0, 0, z_{min})$的平面, 将远裁剪平面设定为与光空间的$z$轴垂直且通过$(0, 0, z_{max} $$ )$的平面.
$\\$ 还有另外两种技术可用于计算可能的最紧密的近裁剪平面与远裁剪平面. 通过将场景的层级结构或场景中的单个物体与光空间的视锥体进行相交测试, 可以计算出更紧密的近裁剪平面与远裁剪平面. 尽管这种方法的计算复杂度会更高, 但对于某些特定的分块而言, 这可能是一种有效的技术.
$\\$ 远裁剪平面距离光空间远点的距离可以通过取以下两个值中的最小值来计算:
$\\$ $\cdot$ 光空间的视锥体所有顶点的最大深度.
$\\$ $\cdot$ 光空间的视锥体与场景的AABB的相交部分的最大深度.

3.7 以纹素大小的增量移动光源

Shadow Depth Maps中常见的一个问题是Shadow边缘的闪烁问题. 当像机移动时, Shadow边缘的像素会呈现明暗交替的闪烁现象. 这种问题在静态图像中无法察觉, 但在实时渲染中会非常明显且令人分心. 下图突显了这一问题.

当像机从左向右移动时, Shadow边界的像素会在Shadow中时隐时现(反复进入/离开阴影区域).
$\\$ 下图则展示了Shadow边缘应有的理想效果.

当像机从左向右移动时, Shadow边缘保持稳定.
$\\$ 之所以产生Shadow边缘的闪烁错误, 是因为每当像机发生移动时, 光空间的投影矩阵都会被重新计算. 这会导致生成的Shadow Depth Maps产生细微差异. 以下所有因素都可能影响光空间的投影矩阵构建:
$\\$ $\cdot$ 光空间的视锥体尺寸;
$\\$ $\cdot$ 光空间的视锥体朝向;
$\\$ $\cdot$ 光源位置;
$\\$ $\cdot$ 像机位置.
$\\$ 每当该矩阵发生变化时, Shadow边缘都可能出现波动.
$\\$ 对于定向光源(平行光), 解决该问题的方案是: 将构成正交视锥体侧平面的$x$/$y$方向的最小值与最大值(决定投影范围的关键参数) 按像素尺寸的整数倍进行量化对齐. 具体可通过以下步骤实现: 首先用除法计算当前值与像素尺寸的比值, 接着通过向下取整(floor操作) 得到整数倍基数, 最后再乘以像素尺寸还原为对齐后的值.


vLightCameraOrthographicMin /= vWorldUnitsPerTexel;
vLightCameraOrthographicMin = XMVectorFloor( vLightCameraOrthographicMin );
vLightCameraOrthographicMin *= vWorldUnitsPerTexel;
vLightCameraOrthographicMax /= vWorldUnitsPerTexel;
vLightCameraOrthographicMax = XMVectorFloor( vLightCameraOrthographicMax );
vLightCameraOrthographicMax *= vWorldUnitsPerTexel;

vWorldUnitsPerTexel值的计算方式是: 通过获取视锥体的边界范围(如近/远裁剪平面距离), 再将其除以缓冲区(如Shadow Depth Maps) 的分辨率尺寸.


FLOAT fWorldUnitsPerTexel = fCascadeBound /
(float)m_CopyOfCascadeConfig.m_iBufferSize;
vWorldUnitsPerTexel = XMVectorSet( fWorldUnitsPerTexel, fWorldUnitsPerTexel, 0.0f, 0.0f );

当视锥体的大小被限制时, 视锥体可能无法完全紧密地包裹场景, 导致一些空间没有被充分利用, 或者投影范围可能过大, 从而影响Shadow Depth Maps的精度或性能.
$\\$ 需要注意的是, 采用该技术时, Shadow Depth Maps的宽度与高度需各增加1像素, 这样可以避免Shadow Depth Maps的采样坐标超出Shadow Depth Maps的采样范围.

3.8 背面与正面

在渲染Shadow Depth Maps时, 通常采用标准背面剔除技术, 该技术会跳过渲染不可见物体的光栅化过程, 从而加速场景渲染. 另一种常见做法是启用正面剔除来渲染Shadow Depth Maps,这意味着面向像机的物体会被剔除. 支持这种做法的论点是: 当构成物体背面的几何体存在微小偏移时, 此方法有助于改善Self-Shadowing效果. 不过该方案存在两个核心问题:
$\\$ $\cdot$ 任何正面/背面几何体处理不当的物体都会在Shadow Depth Maps中产生渲染Artifacts. 不过, 若几何体处理本身存在错误, 往往还会引发其它更严重的问题, 因此通常可以合理假设模型的正面/背面几何体已正确构建. 但对于基于Sprite渲染的几何体(如植被), 手动构建背面几何体往往不具备可操作性.
$\\$ $\cdot$ 物体底部(如墙壁) 出现Peter Panning现象和Shadow Gap的概率更高, 这是由于Shadow深度偏差值过小导致的.

3.9 对Shadow Depth Maps友好的几何结构

创建适用于Shadow Depth Maps的几何结构, 可以在应对Peter Panning现象与Shadow Acne等渲染Artifacts时提供更大的优化空间.
$\\$ 尖锐边缘在Self-Shadowing处理中容易引发问题. 这类边缘顶部的深度差异极小, 即使微小的偏移量也可能导致物体Shadow丢失(如下图所示).

厚度较薄的物体(如墙壁) 的背面深度与正面深度接近, 容易触发自阴影计算错误, 即使永不显示背面, 也应构建背面几何结构. 此举可显著增大物体边缘的深度差异.
$\\$ 确保几何体的朝向正确也至关重要, 即物体的外表面朝向应设置为背面朝外, 而内表面朝向应设置为正面朝内. 这一规范对启用背面剔除的渲染流程至关重要, 同时也有助于缓解深度偏移量可能引发的渲染异常现象.

4. 总结

本文介绍的技术可用于提升标准的Shadow Depth Maps的渲染质量. 下一步可探索与标准的Shadow Depth Maps协同工作的进阶方案: 推荐采用CSMs作为缓解Perspective Aliasing现象的优选技术; 可通过百分比渐进过滤技术(PCF) 或Variance Shadow Maps实现Shadow边缘柔化的效果.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注