# Stable CSM

So… How can we fix this? First, lets agree to make the shadow map size in world space constant, say shadowMapSize, and decouple it from light and camera rotation. In my case I chose to align the shadow map to world space $X$ and $Z$ axis. I do so by exchanging the shadow view matrix for a matrix where the $X$ and $Y$ axis point in direction of world space $X$ and $Z$, positioned at mLightPosition like so:

// Remember: XNA uses a right handed coordinate system, i.e. -Z goes into the screen
var look = Vector3.Normalize(arena.BoundingSphere.Center - mLightPosition);
new Matrix(
1,              0,              0,             0,
0,              0,             -1,             0,
-look.X,        -look.Y,        -look.Z,        0,
mLightPosition.X, mLightPosition.Y, mLightPosition.Z,     1
)
);

Note that the $Y$ axis is flipped in order to preserve culling order in the final view transform. Also note that this approach only works as long as mLightPosition does not lie in the $y=0$ plane in world space as then the resulting matrix becomes singular.

Now lets tackle camera movement: As outlined before, the problem is that even the slightest movement of the shadow map will affect all the scene as each scene position will change position in the shadow map (subpixel-wise speaking). What we need, however, is that the scene positions stay constant (at least relative to their corresponding pixel). So instead of moving the shadow map continuously, lets move it in fixed increments of one shadow map pixel. When moving the shadow map this way, each world space position might fall into a different shadow map texel than the frame before – but the relative position within the shadow map texel will stay the same, which means no more moving shadow boundaries.

So how can we implement this? Given our view transform defined like above, all we need to do is adjust the shadow projections: We want to place the shadow map corners at discrete positions only, separated by some value, e.g. quantizationStep. Remember, in one of my previous posts Cascaded Shadow Mapping (1), we defined the extent of the shadow projection matrices based on values min and max which were determined from the view frustum. All we need to do now is make sure the $X$ and $Y$ coordinates of min and max are properly discretized:

var quantizationStep = 1.0f / shadowMapSize;
var qx = (float)Math.IEEERemainder(min.X, quantizationStep);
var qy = (float)Math.IEEERemainder(min.Y, quantizationStep);

min.X -= qx;
min.Y -= qy;