This article描述了如何使用方差阴影贴图渲染阴影。
它表示在将场景渲染到阴影贴图时,应该存储深度和深度平方(使用偏导数进行偏差调整)。
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);
答案 0 :(得分:1)
如果你不过滤纹理,这是真的,但这种阴影贴图的主要思想是可以线性过滤。过滤(深度^ 2)不等于过滤(深度)^ 2。这就是差异的来源。
非常感谢作者清理它。