级联阴影映射

级联阴影映射 (CSM) 是与阴影:透视锯齿对抗最普遍的错误之一的最佳方式。 此技术文章假设读者熟悉阴影映射,可处理 CSM 的主题。 具体而言,它:

  • 说明 CSM 的复杂性;
  • 提供有关 CSM 算法可能变体的详细信息;
  • 介绍两种最常见的筛选技术-百分比更接近筛选 (PCF) ,并使用方差阴影映射筛选 (VSM) ;
  • 标识和解决与向 CSM 添加筛选相关的一些常见陷阱;和
  • 演示如何将 CSM 映射到 Direct3D 10 到 Direct3D 11 硬件。

本文中使用的代码可在 CascadedShadowMaps11 和 VarianceShadows11 示例中的 DirectX 软件开发工具包 (SDK) 中找到。 本文将在实施技术文章中介绍的技术(改进阴影深度的常见技术地图)后证明最有用。

级联阴影地图和透视别名

阴影图中的透视别名是克服的最困难问题之一。 在技术文章中,介绍了改进阴影深度地图的常见技术、透视别名以及一些缓解问题的方法。 在实践中,CSM 往往是最佳解决方案,通常采用现代游戏。

CSM 的基本概念易于理解。 相机 Frustum 的不同区域需要具有不同分辨率的阴影地图。 距离眼睛最近的对象需要比更远的对象更高的分辨率。 事实上,当眼睛非常接近几何图形时,最接近眼睛的像素可能需要这么多分辨率,即使 4096 × 4096 阴影图是不够的。

CSM 的基本概念是将 frustum 分区为多个 frusta。 为每个子图元呈现阴影映射;然后,像素着色器从地图中采样,最符合所需分辨率 (图 2) 。

图 1. 阴影地图覆盖率

shadow map coverage

图 1 显示质量 (从最高到最低) 从左到右。 表示阴影映射的一系列网格,在红色) 显示像素覆盖率如何受到不同分辨率阴影映射的影响 (反转圆锥。 当阴影空间中有一个 1:1 的比例映射像素到阴影图中的纹素时,阴影是质量最高的 (白色像素) 。 当像素过多映射到同一阴影纹素时,透视别名以大块纹理映射的形式出现, (左图像) 。 当阴影图太大时,它正在采样下。 在这种情况下,跳过纹素,引入闪闪发光的项目,并影响性能。

图 2. CSM 阴影质量

csm shadow quality

图 2 显示了图 1 中每个阴影地图中最高质量的部分的剪切。 位于顶点) 最贴靠像素的阴影图 (距离眼睛最接近。 从技术上说,这些是大小相同的地图,白色和灰色用于演示级联阴影地图的成功。 白色是理想的,因为它显示良好的覆盖率 - 1:1 比率的眼空间像素和阴影地图纹素。

CSM 需要每个帧执行以下步骤。

  1. 将 frustum 分区为子frusta。

  2. 计算每个子图形的正交投影。

  3. 为每个子图形呈现阴影映射。

  4. 呈现场景。

    1. 绑定阴影映射和呈现。

    2. 顶点着色器执行以下操作:

      • 计算每个光子图形 (的纹理坐标,除非在像素着色器) 中计算所需的纹理坐标。
      • 转换和点亮顶点等。
    3. 像素着色器执行以下操作:

      • 确定适当的阴影映射。
      • 如有必要,转换纹理坐标。
      • 对级联进行采样。
      • 照亮像素。

对 Frustum 进行分区

对 frustum 进行分区是创建子frusta 的行为。 拆分 Frustum 的一种方法是计算从零到 Z 方向的百分之一百的间隔。 然后,每个间隔表示一个近平面和一个远平面作为 Z 轴的百分比。

图 3. 查看任意分区的 frustum

view frustums partitioned arbitrarily

实际上,重新计算每个帧的棱锥拆分会导致阴影边缘闪闪发光。 通常接受的做法是为每个方案使用一组静态级联间隔。 在此方案中,沿 Z 轴的间隔用于描述分区 frustum 时发生的子图形。 确定给定场景的正确大小间隔取决于几个因素。

场景几何图形的方向

对于场景几何图形,相机方向会影响级联间隔选择。 例如,在足球比赛中非常接近地面的相机(如足球比赛中的地面摄像头)具有与天空中的相机不同的静态级联间隔集。

图 4 显示了一些不同的相机及其各自的分区。 当场景的 Z 范围非常大时,需要更多的拆分平面。 例如,当眼睛非常接近地面平面时,但遥远的对象仍然可见,可能需要多个级联。 分割 frustum,使更多的拆分接近眼睛 (透视锯齿正在改变最快的) 也是有价值的。 当大多数几何图形都缩进一个小节 ((例如开销视图或飞行模拟器)) 视图 frustum 时,需要较少的级联。

图 4。 不同的配置需要不同的 frustum 拆分

different configurations require different frustum splits

(左) 当几何图形在 Z 中具有高动态范围时,需要大量级联。 (中心) 当几何图形在 Z 中具有低动力学范围时,多个球形几乎没有好处。 (右) 当动态范围为中等时,只需要三个分区。

浅色和相机的方向

每个级联的投影矩阵紧贴在其相应的子图元周围。 在视图相机和光方向是正交的配置中,级联可以紧密拟合,几乎没有重叠。 当光线和视图相机进入并行对齐 (图 5) 时,重叠会变大。 当光线和视图相机几乎并行时,它被称为“决斗 frusta”,对于大多数阴影算法来说,这是一个非常困难的场景。 约束光线和相机并不罕见,因此这种情况不会发生。 但是,CSM 在此方案中比其他许多算法的性能要好得多。

图 5。 随着光方向与相机方向的并行,级联重叠增加

cascade overlap increases as light direction becomes parallel with camera direction

许多 CSM 实现使用固定大小的 frusta。 像素着色器可以使用 Z 深度索引到级联数组中,当 frustum 拆分为固定大小间隔时。

计算View-Frustum绑定

选择 frustum 间隔后,使用两个之一创建子frusta:适合场景并适合级联。

适合场景

可以使用相同的近平面创建所有 frusta。 这强制级联重叠。 CascadedShadowMaps11 示例调用适用于场景的此方法。

适合级联

或者,可以使用用作近平面和远平面的实际分区间隔来创建 frusta。 这会导致更紧密的拟合,但在决斗 frusta 的情况下,退化以适应场景。 CascadedShadowMaps11 示例调用此技术适合级联。

图 6 中显示了这两种方法。 适合级联浪费更少的分辨率。 适合级联的问题在于,正交投影根据视线方向增长和缩小。 适合场景技术通过视图的正向量的最大大小填充正交投影,从而删除在视图相机移动时出现的项目。 改进阴影深度的常见技术地图解决了在“以纹素大小递增移动光”部分中的光线时出现的项目。

图 6。 适合场景,适合级联

fit to scene versus fit to cascade

呈现阴影映射

CascadedShadowMaps11 示例将阴影映射呈现到一个大型缓冲区中。 这是因为纹理数组上的 PCF 是 Direct3D 10.1 功能。 对于每个级联,都会创建一个视区,该视区涵盖对应于该级联的深度缓冲区部分。 由于只需要深度,所以绑定了 null 像素着色器。 最后,为每个级联设置正确的视区和阴影矩阵,因为深度映射一次呈现到主阴影缓冲区中。

呈现场景

包含阴影的缓冲区现在绑定到像素着色器。 有两种方法可用于选择 CascadedShadowMaps11 示例中实现的级联。 这两种方法通过着色器代码进行说明。

Interval-Based级联选择

图 7。 基于间隔的级联选择

interval-based cascade selection

在基于间隔的选择 (图 7) 中,顶点着色器计算顶点世界空间中的位置。

Output.vDepth = mul( Input.vPosition, m_mWorldView ).z;

像素着色器接收内插深度。

fCurrentPixelDepth = Input.vDepth;

基于间隔的级联选择使用矢量比较和点积来确定正确的 cacade。 CASCADE_COUNT_FLAG指定级联的数目。 m_fCascadeFrustumsEyeSpaceDepths_data约束视图 frustum 分区。 比较后,fComparison 包含一个值 1,其中当前像素大于屏障,当当前级联更小时,值为 0。 点积将这些值求和到数组索引中。

        float4 vCurrentPixelDepth = Input.vDepth;
        float4 fComparison = ( vCurrentPixelDepth > m_fCascadeFrustumsEyeSpaceDepths_data[0]);
        float fIndex = dot(
        float4( CASCADE_COUNT_FLAG > 0,
        CASCADE_COUNT_FLAG > 1,
        CASCADE_COUNT_FLAG > 2,
        CASCADE_COUNT_FLAG > 3)
        , fComparison );

        fIndex = min( fIndex, CASCADE_COUNT_FLAG );
        iCurrentCascadeIndex = (int)fIndex;

选择级联后,纹理坐标必须转换为正确的级联。

vShadowTexCoord = mul( InterpolatedPosition, m_mShadow[iCascadeIndex] );

然后,此纹理坐标用于使用 X 坐标和 Y 坐标对纹理采样。 Z 坐标用于执行最终深度比较。

Map-Based级联选择

基于地图的选择 (图 8) 对级联的四侧进行测试,以查找覆盖特定像素的最紧密地图。 顶点着色器不计算世界空间中的位置,而是计算每个级联的视图空间位置。 像素着色器循环访问级联,以便缩放和移动纹理坐标,以便为当前级联编制索引。 然后,针对纹理边界测试纹理坐标。 当纹理坐标的 X 和 Y 值落入级联内时,它们用于采样纹理。 Z 坐标用于执行最终深度比较。

图 8。 基于映射的级联选择

map-based cascade selection

Interval-Based选择与Map-Based选择

基于间隔的选择比基于地图的选择要快一些,因为可以直接进行级联选择。 基于地图的选择必须与级联边界相交纹理坐标。

当阴影映射不完全对齐时,基于地图的选择更有效地使用级联, (见图 8) 。

在级联之间混合

本文稍后讨论的 VSM () 和筛选技术(如 PCF)可用于低分辨率 CSM 来生成软阴影。 遗憾的是,这会导致级联层之间的可见接缝 (图 9) ,因为分辨率不匹配。 解决方案是在阴影映射之间创建一个带状图,其中对两个级联执行阴影测试。 然后,着色器根据混合带中的像素位置在两个值之间线性内插。 示例 CascadedShadowMaps11 和 VarianceShadows11 提供了一个 GUI 滑块,可用于增加和减少此模糊带。 着色器执行动态分支,以便绝大多数像素仅从当前级联读取。

图 9. 级联接缝

cascade seams

(左) 可见接缝可以看到级联重叠的位置。 (右) 当级联混合时,不会发生接缝。

筛选阴影地图

PCF

筛选普通阴影映射不会产生柔和模糊的阴影。 筛选硬件模糊深度值,然后将这些模糊值与光空间纹素进行比较。 通过/失败测试产生的硬边缘仍然存在。 模糊的阴影映射只能错误地移动硬边缘。 PCF 支持对阴影映射进行筛选。 PCF 的一般思路是根据通过深度测试的子采样数计算阴影中像素的百分比。

Direct3D 10 和 Direct3D 11 硬件可以执行 PCF。 PCF 采样器的输入由纹理坐标和比较深度值组成。 为简单起见,PCF 使用四点击筛选器进行说明。 纹理采样器读取纹理四次,类似于标准筛选器。 但是,返回的结果是通过深度测试的像素的百分比。 图 10 显示了如何通过四个深度测试之一的像素在阴影中达到 25%。 返回的实际值是基于纹理读取的子纹素坐标的线性内插,以生成平滑渐变。 如果没有这种线性内插,四点击 PCF 只能返回五个值:{ 0.0,0.25,0.5,0.75,1.0 }。

图 10. PCF 筛选的图像,其中 25% 的选定像素被覆盖

pcf filtered image, with 25 percent of the selected pixel covered

还可以在没有硬件支持的情况下执行 PCF,或者将 PCF 扩展到更大的内核。 某些技术甚至使用加权内核进行采样。 为此,请为 N × N 网格创建内核 (,例如 Gaussian) 。 权重必须加起来最多 1。 然后对纹理采样 N2 次。 每个样本按内核中的相应权重进行缩放。 CascadedShadowMaps11 示例使用此方法。

深度偏差

使用大型 PCF 内核时,深度偏差变得更加重要。 仅当像素的光空间深度与它映射到深度地图的像素进行比较时,它才有效。 深度地图纹素的邻居引用不同的位置。 此深度可能类似,但根据场景的不同,可能大不相同。 图 11 突出显示了发生的项目。 单个深度与阴影图中的三个相邻纹素进行比较。 其中一个深度测试错误失败,因为它的深度与当前几何图形的计算光空间深度无关。 建议解决此问题的解决方案是使用更大的偏移量。 然而,过大的偏移量可能导致彼得·潘宁。 计算紧近平面和远平面有助于减少使用偏移的影响。

图 11. 错误自我阴影

erroneous self-shadowing

错误的自我阴影结果,从将光空间深度中的像素与不关联的阴影映射中的纹素进行比较。 浅空间中的深度与深度地图中的阴影纹素 2 相关。 纹素 1 大于光空间深度,而 2 等于,3 小于。 纹素 2 和 3 通过深度测试,而纹素 1 失败。

使用 DDX 和 DDY 计算大型 PCF 的Per-Texel深度偏差

计算大型 PCF 的 ddxddy 的每个纹素深度偏差是计算相邻阴影图纹素的正确深度偏差(假设表面是平面)的技术。

此方法使用派生信息将比较深度拟合到平面。 由于此方法在计算上很复杂,因此仅当 GPU 具有备用计算周期时,才应使用它。 使用非常大的内核时,这可能是唯一一种在不导致 Peter Panning 的情况下删除自我阴影项目的方法。

图 12 突出显示了问题。 光空间的深度以比较的纹素而闻名。 与深度图中的相邻纹素相对应的光空间深度未知。

图 12. 场景和深度地图

scene and depth map

呈现的场景显示在左侧,带有示例纹素块的深度地图显示在右侧。 眼空纹素映射到块中心标有 D 的像素。 此比较准确。 与邻居 D 未知的像素相关的眼睛空间中的正确深度。 仅当假定像素与 D 相同的三角形相关时,才能将相邻纹素映射回眼睛空间。

深度以与光空间位置关联的纹素而闻名。 深度图中相邻纹素的深度未知。

在高级别上,此方法使用 ddxddy HLSL 操作来查找光空间位置的派生值。 这是非琐碎的,因为派生运算返回光空间深度相对于屏幕空间的渐变。 若要将其转换为光空间深度相对于光空间的渐变,必须计算转换矩阵。

着色器代码的说明

算法的其余部分的详细信息作为执行此操作的着色器代码的说明提供。 可以在 CascadedShadowMaps11 示例中找到此代码。 图 13 显示了光空间纹理坐标如何映射到深度地图,以及如何使用 X 和 Y 中的派生体来创建转换矩阵。

图 13. 屏幕空间到浅空间矩阵

screen-space to light-space matrix

X 和 Y 中光空间位置的衍生值用于创建此矩阵。

第一步是计算光视图空间位置的派生值。

          float3 vShadowTexDDX = ddx (vShadowMapTextureCoordViewSpace);
          float3 vShadowTexDDY = ddy (vShadowMapTextureCoordViewSpace);

Direct3D 11 类 GPU 通过并行运行 2 × 2 个像素的四边形并减去 X 中 ddx 的纹理坐标和 Y 表示 ddy 的邻居中的纹理坐标来计算这些衍生值。 这两个派生体组成 2 × 2 矩阵的行。 在此矩阵的当前形式中,此矩阵可用于将屏幕空间相邻像素转换为光空间斜率。 但是,需要此矩阵的反函数。 需要将光空间相邻像素转换为屏幕空间斜率的矩阵。

          float2x2 matScreentoShadow = float2x2( vShadowTexDDX.xy, vShadowTexDDY.xy );
          float fInvDeterminant = 1.0f / fDeterminant;

          float2x2 matShadowToScreen = float2x2 (
          matScreentoShadow._22 * fInvDeterminant,
          matScreentoShadow._12 * -fInvDeterminant,
          matScreentoShadow._21 * -fInvDeterminant,
          matScreentoShadow._11 * fInvDeterminant );

图 14. 浅色到屏幕空间

light-space to screen-space

然后,此矩阵用于转换当前纹素上方和右侧的两个纹素。 这些邻居表示为当前纹素的偏移量。

          float2 vRightShadowTexelLocation = float2( m_fTexelSize, 0.0f );
          float2 vUpShadowTexelLocation = float2( 0.0f, m_fTexelSize );
          float2 vRightTexelDepthRatio = mul( vRightShadowTexelLocation,
          matShadowToScreen );
          float2 vUpTexelDepthRatio = mul( vUpShadowTexelLocation,
          matShadowToScreen );

矩阵创建的比率最终乘以深度派生,以计算相邻像素的深度偏移量。

            float fUpTexelDepthDelta =
            vUpTexelDepthRatio.x * vShadowTexDDX.z
            + vUpTexelDepthRatio.y * vShadowTexDDY.z;
            float fRightTexelDepthDelta =
            vRightTexelDepthRatio.x * vShadowTexDDX.z
            + vRightTexelDepthRatio.y * vShadowTexDDY.z;

这些权重现在可以在 PCF 循环中使用,以向位置添加偏移量。

    for( int x = m_iPCFBlurForLoopStart; x < m_iPCFBlurForLoopEnd; ++x ) 
    {
        for( int y = m_iPCFBlurForLoopStart; y < m_iPCFBlurForLoopEnd; ++y )
            {
            if ( USE_DERIVATIVES_FOR_DEPTH_OFFSET_FLAG )
            {
            depthcompare += fRightTexelDepthDelta * ( (float) x ) +
            fUpTexelDepthDelta * ( (float) y );
            }
            // Compare the transformed pixel depth to the depth read
            // from the map.
            fPercentLit += g_txShadow.SampleCmpLevelZero( g_samShadow,
            float2(
            vShadowTexCoord.x + ( ( (float) x ) * m_fNativeTexelSizeInX ) ,
            vShadowTexCoord.y + ( ( (float) y ) * m_fTexelSize )
            ),
            depthcompare
            );
            }
     }

PCF 和 CSM

PCF 不适用于 Direct3D 10 中的纹理数组。 若要使用 PCF,所有级联都存储在一个大型纹理图集中。

Derivative-Based偏移量

为 CSM 添加基于派生的偏移量会带来一些挑战。 这是因为分流控制中的派生计算。 由于 GPU 运行的基本方式,因此会出现此问题。 Direct3D11 GPU 在 2 × 2 个像素的四个象限上运行。 若要执行派生,GPU 通常从相邻像素的同一变量副本中减去当前像素的变量副本。 这种情况的发生方式因 GPU 而异。 纹理坐标由基于地图或基于间隔的级联选择确定。 像素象限中的某些像素选择不同于其余像素的级联。 这会导致阴影映射之间的可见接缝,因为基于派生的偏移量现在完全错误。 解决方法是对浅视图空间纹理坐标执行派生。 对于每个级联,这些坐标都是相同的。

PCF 内核的填充

如果未填充阴影缓冲区,则 PCF 内核在级联分区之外编制索引。 解决方法是将级联的外部边缘填充 PCF 内核大小的一半。 这必须在选择级联的着色器中实现,并且必须在投影矩阵中实现,该矩阵必须呈现足够大的级联,以便保留边框。

方差阴影地图

VSM (请参阅 Donnelly 和 Lauritzen 的 方差阴影映射 ,了解) 启用直接阴影映射筛选的详细信息。 使用 VSM 时,可以使用纹理筛选硬件的所有功能。 可以使用三线性和异性 (图 15) 筛选。 此外,VSM 可以通过卷积直接模糊化。 VSM 确实有一些缺点:深度数据的两个通道必须存储在深度和深度平方) (。 当阴影重叠时,轻出血是常见的。 但是,它们的工作方式非常出色,分辨率较低,可与 CSM 结合使用。

图 15. 异性筛选

anisotropic filtering

算法详细信息

VSM 的工作原理是将深度和深度平方为双通道阴影图。 然后,这种双通道阴影图可以像普通纹理一样模糊和筛选。 然后,该算法在像素着色器中使用 Chebychev 的相等性来估计通过深度测试的像素区域的分数。

像素着色器提取深度和深度平方值。

        float  fAvgZ  = mapDepth.x; // Filtered z
        float  fAvgZ2 = mapDepth.y; // Filtered z-squared

执行深度比较。

        if ( fDepth <= fAvgZ )
        {
        fPercentLit = 1;
        }

如果深度比较失败,则估计点亮像素的百分比。 方差计算为平方的平均值减去平均值。

        float variance = ( fAvgZ2 ) − ( fAvgZ * fAvgZ );
        variance = min( 1.0f, max( 0.0f, variance + 0.00001f ) );

根据 Chebychev 的不平等估计 fPercentLit 值。

        float mean           = fAvgZ;
        float d              = fDepth - mean;
        float fPercentLit    = variance / ( variance + d*d );

浅出血

VSM 的最大缺点是光出血 (图 16) 。 当多个阴影投手沿边缘相互遮挡时,会出现光出血。 VSM 根据深度差异对阴影的边缘进行着色。 当阴影相互重叠时,深度差异存在于应隐藏的区域的中心。 使用 VSM 算法时出现问题。

图 16. VSM 光出血

vsm light bleeding

问题的一个部分解决方法是将 fPercentLit 提升到电源。 这会影响抑制模糊,这可能导致深度差异很小的项目。 有时存在一个神奇的价值,可以缓解问题。

fPercentLit = pow( p_max, MAGIC_NUMBER );

将百分比提升为电源的替代方法是避免阴影重叠的配置。 即使是高度优化的阴影配置,对光线、相机和几何图形也存在一些约束。 使用分辨率较高的纹理也会减少光出血。

分层方差阴影映射 (LVSM) 以牺牲将 frustum 分解为垂直于光的层来解决问题。 使用 CSM 时所需的映射数会相当大。

此外,有关 VSM 的论文合著者安德鲁·劳里森(Andrew Lauritzen)以及LVSM论文的作者,讨论了将指数阴影地图与 VSM (ESM) 相结合,以对抗 Beyond3D 论坛中的光混合。

具有 CSM 的 VSM

示例 VarianceShadow11 结合了 VSM 和 CSM。 组合相当简单。 该示例遵循与 CascadedShadowMaps11 示例相同的步骤。 由于未使用 PCF,因此阴影在双通道可分离卷积中模糊不通。 不使用 PCF 还使样本能够使用纹理数组而不是纹理图集。 纹理数组上的 PCF 是 Direct3D 10.1 功能。

使用 CSM 的渐变

将渐变与 CSM 配合使用可以沿两个级联之间的边界生成接缝,如图 17 所示。 示例指令使用像素之间的派生值来计算筛选器所需的 mipmap 级别等信息。 这尤其会导致 mipmap 选择或异性筛选出现问题。 当象限中的像素采用着色器中的不同分支时,GPU 硬件计算的派生体无效。 这会导致阴影图上出现锯齿状接缝。

图 17. 由于具有不同流量控制的异性筛选,级联边界上的接缝

seams on cascade borders due to anisotropic filtering with divergent flow control

通过计算光视空间中位置的衍生值来解决此问题:浅视图空间坐标不特定于所选级联。 计算派生可以按投影纹理矩阵的刻度部分缩放到正确的 mipmap 级别。

        float3 vShadowTexCoordDDX = ddx( vShadowMapTextureCoordViewSpace );
        vShadowTexCoordDDX *= m_vCascadeScale[iCascade].xyz;
        float3 vShadowTexCoordDDY = ddy( vShadowMapTextureCoordViewSpace );
        vShadowTexCoordDDY *= m_vCascadeScale[iCascade].xyz;

        mapDepth += g_txShadow.SampleGrad( g_samShadow, vShadowTexCoord.xyz,
        vShadowTexCoordDDX, vShadowTexCoordDDY );

VSM 与 PCF 的标准阴影相比

VSM 和 PCF 都尝试近似通过深度测试的像素区域的分数。 VSM 适用于筛选硬件,可以使用可分离内核模糊处理。 与完整内核相比,可分离卷积内核的实现成本要便宜得多。 此外,VSM 将一个光空间深度与光空间深度映射中的一个值进行比较。 这意味着 VSM 与 PCF 没有相同的偏移量问题。 从技术上说,VSM 在更大的区域采样深度,以及执行统计分析。 这比 PCF 更精确。 实际上,VSM 在混合方面做得非常好,因此需要较少的偏移量。 如上所述,VSM 的头号缺点是轻出血。

VSM 和 PCF 表示 GPU 计算能力和 GPU 纹理带宽之间的权衡。 VSM 需要执行更多数学运算才能计算方差。 PCF 需要更多的纹理内存带宽。 大型 PCF 内核可能很快因纹理带宽而成为瓶颈。 由于 GPU 计算能力比 GPU 带宽更快增长,VSM 正在成为这两种算法的更实用。 由于混合和筛选,VSM 在分辨率较低的阴影映射中看起来也更好。

总结

CSM 为透视别名问题提供解决方案。 有多种可能的配置可以获取游戏所需的视觉保真度。 PCF 和 VSM 广泛使用,应与 CSM 结合使用以减少别名。

参考

唐纳利、W. 和劳里森,A. 方差阴影地图。 在 SI3D '06:2006 年交互式 3D 图形和游戏研讨会的论文集。 2006. pp. 161–165. 纽约,纽约,美国:ACM出版社。

劳里森、安德鲁和麦考尔,迈克尔。 分层方差阴影映射。 2008 年 5 月 28 日至 30 日,加拿大安大略省温莎的图形界面程序。

恩格尔, 沃弗刚 F. 第 4 节。 级联阴影地图。 ShaderX5、高级渲染技术、Wolfgang F. Engel、Ed。 查尔斯河媒体,波士顿,马萨诸塞州。 2006. pp. 197–206.