本文介绍如何使用 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);