Skip to content

Cascaded shadow map cleanup and fixes - #749

Merged
brentyi merged 3 commits into
mainfrom
csm-shadow-cleanup
Jul 29, 2026
Merged

Cascaded shadow map cleanup and fixes#749
brentyi merged 3 commits into
mainfrom
csm-shadow-cleanup

Conversation

@brentyi

@brentyi brentyi commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Remove the unused CSM shader injection machinery, fix cascade desync on window resize plus a few lifecycle footguns, and rename the CSM classes to reflect what is actually implemented (per-cascade shadow cameras composited as overlapping directional lights, not true cascaded shadow mapping).

This PR should have no visual impact.

…bugs

The vendored three.js CSM addon carried a full shader-injection path
(setupMaterial / CSMShader / global ShaderChunk patching) that was never
activated: no material ever called setupMaterial, so every material
compiled the non-CSM fallback branch. What actually renders is N
overlapping shadow-casting directional lights at intensity/N. This
commit makes that design explicit and deletes the dead half:

- Delete CSMShader.js and the ShaderChunk save/restore bookkeeping. The
  injected chunk was a stale r174-era fork of lights_fragment_begin; the
  fallback branch every material used is identical to stock three r183,
  so removal also silently restores current-three behavior for
  iridescence and point-light shadow guards.
- Delete CSMShadowNode.js (WebGPU-only, unreachable in a WebGL app).
- Strip setupMaterial, uniform plumbing, fade, and the shaders map from
  CSM.js; document the layered-lights design at the top of the file.

Bug fixes along the way:

- Call updateFrustums() when the camera projection matrix changes.
  Cascade splits and shadow bounds were previously computed once at
  construction, so window resizes and fov/near/far updates desynced the
  shadow cameras from the view frustum.
- Use ?? instead of || for numeric CSM defaults: a shadow-casting light
  with intensity=0 was previously kicked back up to the default
  intensity of 3.
- Guard the degenerate zero light direction when a directional light
  sits exactly at the world origin (the add_light_directional position
  default); fall back to pointing straight down.
- Apply light color reliably on mount: the old color effect ran before
  the CSM instance existed and its deps never re-fired, so a non-default
  initial color was silently dropped.
- Simplify the wrapper: construct CSM directly in an effect (the
  CSMProxy indirection existed for the ShaderChunk bookkeeping), reuse
  CSMHelper.dispose() for debug-helper teardown, and drop the
  updateMaterialsInScene traversals (three re-selects shader programs
  itself when the light set changes; the manual needsUpdate sweep was
  only needed when ShaderChunk globals were being swapped).
@brentyi
brentyi force-pushed the csm-shadow-cleanup branch from bfb2b11 to 966a214 Compare July 28, 2026 19:03
brentyi added 2 commits July 28, 2026 23:58
What viser renders is not cascaded shadow mapping in the standard sense:
there is no per-fragment cascade selection. Each cascade is an ordinary
shadow-casting directional light whose shadow camera is fitted to a view
frustum slice, and cascades composite by summing lights, which leaves
distant shadows lighter than true CSM would. Rename the code so it stops
claiming otherwise:

- CsmDirectionalLight -> CascadedDirectionalLight
- csm/CSM.js (class CSM) -> shadows/ShadowCascades.js (ShadowCascades)
- csm/CSMFrustum.js -> shadows/CascadeFrustum.js
- csm/CSMHelper.js -> shadows/CascadeHelper.js

The ShadowCascades header documents the approximation and its tradeoff
explicitly. The files are also removed from the eslint/prettier ignore
lists: those exemptions existed to keep the vendored copy diffable
against upstream three.js, which no longer applies now that the code has
permanently diverged. No behavior change; the built client renders
pixel-identical.
@brentyi
brentyi merged commit ef0ecc0 into main Jul 29, 2026
23 checks passed
@brentyi
brentyi deleted the csm-shadow-cleanup branch July 29, 2026 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant