shadowSystem
Cascaded shadow map (CSM) policy for crisp directional shadows across a large view distance. The rendering mechanism lives in the engine; this package is the per-frame policy that drives it.
Layout
shadowSystem.module— the policy: PSSM frustum splitting, per-cascade bounding-sphere fit + texel-snap stabilization, and the matrix math. Pushes per-cascade light-space matrices + split distances to the renderer via__rendering.setShadowCascadeseach frame.ShadowCascadeDriver.component— attach ONE to a scene entity to drive the module every frame from the active camera + sun.depthBounds.renderFeature— reduces the frame's depth target to the nearest and farthest view depth any surface occupies, and hands the result to the module.
Flow
- Add a
ShadowCascadeDrivercomponent to any entity in the scene. - Each frame it slices the camera frustum into N cascades (N from
render.shadow_cascades), fits a stable light-space ortho to each, and pushes the matrices + split distances to the renderer. - The renderer renders one shadow depth pass per cascade; the fragment shaders pick a cascade by the fragment's distance from the camera.
Fitting splits to the depth that is there
Splits are placed over a range. Taken from the camera's near and far planes that range is whatever the scene could occupy; taken from the depth buffer it is what the scene does occupy. A courtyard that stops at 40 m under a 200 m shadow distance spends most of its cascade texels on empty space.
entity.find("scene").component.add("ShadowCascadeDriver", {
fitToDepth = true, -- place splits over the measured depth
depthMargin = 0.1, -- room past the far end for a frame of movement
})
The far end is what moves. The near end stays where the camera puts it: the renderer picks a cascade from a fragment's distance and cascade 0 is fitted to the range's start, so raising that start would leave anything nearer sampling a box it does not sit inside.
The measurement is one frame old, because a GPU read-back cannot land in the
frame that produced it. depthMargin is the room that gives something to move
away in before it falls outside the last cascade.
With fitToDepth off, no reduction is dispatched and splits are placed exactly
as before.
Purely additive: with no driver the renderer falls back to its legacy single
camera-fit directional shadow. Quality is controlled by the
render.shadow_resolution / render.shadow_cascades / render.shadow_distance
/ render.shadow_split_lambda world settings. render.shadow_distance is a cap
on the range the splits run over, and its default of 0 leaves that range to the
frame — the depth its own renderables reach.
Documentation
See shadowSystem.module/README.md and ShadowCascadeDriver.component/README.md.
Scoped to this part · feeds back into the world's score.