2

本文介绍如何使用 Variance Shadow Maps 渲染阴影。

它说当将场景渲染到阴影贴图中时,您应该存储深度和深度平方(使用偏导数调整偏差)。

float2 ComputeMoments(float Depth)
{
    float2 Moments;
    // First moment is the depth itself.
    Moments.x = Depth;
    // Compute partial derivatives of depth.
    float dx = ddx(Depth);
    float dy = ddy(Depth);
    // Compute second moment over the pixel extents.
    Moments.y = Depth*Depth + 0.25*(dx*dx + dy*dy);
    return Moments;
}

然后,您可以像这样检查阴影贴图的深度:

   float ChebyshevUpperBound(float2 Moments, float t)
   {
       // One-tailed inequality valid if t > Moments.x
       float p = (t <= Moments.x);
       // Compute variance.
       float Variance = Moments.y – (Moments.x*Moments.x);
       Variance = max(Variance, g_MinVariance);
       // Compute probabilistic upper bound.
       float d = t – Moments.x;
       float p_max = Variance / (Variance + d*d);
       return max(p, p_max);
    }

    float ShadowContribution(float2 LightTexCoord, float DistanceToLight)
    {
        // Read the moments from the variance shadow map.
        float2 Moments = texShadow.Sample(ShadowSampler, LightTexCoord).xy;
        // Compute the Chebyshev upper bound.
        return ChebyshevUpperBound(Moments, DistanceToLight);
    }

文章然后说,您可以完全不偏向深度平方,只要确保将方差限制在最小值即可。在本书附带的源代码中,计算偏差的代码被注释掉了,它说只是为了限制最小方差。

那么,为什么还要首先存储深度平方呢?此外,为什么不跳过方差的计算,而总是使用最小方差呢?如果矩 1 是深度,矩 2 是深度的平方,那么方差不应该总是为 0 吗?

float Variance = Moments.y – (Moments.x*Moments.x);
4

1 回答 1

1

如果不过滤纹理,这将是正确的,但这种类型的阴影贴图的主要思想是它可以被线性过滤。过滤(深度^2)不等于过滤(深度)^2。这就是方差的来源。

非常感谢作者澄清了这一点。

于 2013-04-16T22:41:14.023 回答