Fix shadow shimmering
Shadow shimmering is a visual artefact where the outlines of shadow mapped objects don't stay stable when the camera is moved or rotated. The reason is that as the shadow map's origin moves, the objects rendered to the shadow map have temporal aliasing around their edges. The solution is to only move the shadow map in texel-sized increments. Because the shadow map's projection is orthographic, moving the shadow map origin in texel increments ensures that objects that aren't moving don't show any temporal aliasing, as the position of the samples of the object in worldspace stay the same.1008-fix
parent
fdf67b8217
commit
abeb7fceb2
|
@ -3819,9 +3819,23 @@ void CEngine::RenderShadowMap()
|
|||
|
||||
Math::Vector pos = m_lookatPt + 0.25f * dist * dir;
|
||||
|
||||
pos.x = round(pos.x);
|
||||
pos.y = round(pos.y);
|
||||
pos.z = round(pos.z);
|
||||
{
|
||||
// To prevent 'shadow shimmering', we ensure that the position only moves in texel-sized
|
||||
// increments. To do this we transform the position to a space where the light's forward/right/up
|
||||
// axes are aligned with the x/y/z axes (not necessarily in that order, and +/- signs don't matter).
|
||||
Math::Matrix lightRotation;
|
||||
Math::LoadViewMatrix(lightRotation, Math::Vector{}, lightDir, worldUp);
|
||||
pos = Math::MatrixVectorMultiply(lightRotation, pos);
|
||||
// ...then we round to the nearest worldUnitsPerTexel:
|
||||
const float worldUnitsPerTexel = (dist * 2.0f) / m_shadowMap.size.x;
|
||||
pos /= worldUnitsPerTexel;
|
||||
pos.x = round(pos.x);
|
||||
pos.y = round(pos.y);
|
||||
pos.z = round(pos.z);
|
||||
pos *= worldUnitsPerTexel;
|
||||
// ...and convert back to world space.
|
||||
pos = Math::MatrixVectorMultiply(lightRotation.Inverse(), pos);
|
||||
}
|
||||
|
||||
Math::Vector lookAt = pos - lightDir;
|
||||
|
||||
|
|
Loading…
Reference in New Issue