docs(three): document sun shadow needsUpdate fix
Update three-debugging.md to reflect that the shadow intermittence is resolved by explicit sun.shadow.needsUpdate = true at mount and in useFrame after updateMatrixWorld.
This commit is contained in:
@@ -41,29 +41,33 @@ The octree visualization reads the live `Octree` instance from `World`. The
|
|||||||
mesh uses `depthTest: false` and a high `renderOrder`, so cells stay visible
|
mesh uses `depthTest: false` and a high `renderOrder`, so cells stay visible
|
||||||
through opaque geometry.
|
through opaque geometry.
|
||||||
|
|
||||||
## Shadow rendering intermittence (open investigation)
|
## Shadow rendering intermittence
|
||||||
|
|
||||||
Shadows occasionally fail to render on initial load even though the
|
Shadows occasionally failed to render on initial load and could disappear
|
||||||
`Lighting` configuration runs to completion (verified through diagnostic logs).
|
mid-session even though the `Lighting` configuration ran to completion.
|
||||||
The issue is not deterministic across runs with identical config. Suspected
|
|
||||||
contributors:
|
|
||||||
|
|
||||||
- WebGL context restoration timing (`webglcontextrestored` rebinds shadow map
|
Root cause: the sun follows the camera (its world matrix is dirty every frame
|
||||||
state in `src/pages/page.tsx`).
|
via `updateMatrixWorld()` inside `Lighting.useFrame`). With `shadow.autoUpdate`
|
||||||
- First-frame shadow map being rendered before any mesh has its
|
alone, three.js can skip the shadow map re-render on a frame where the matrix
|
||||||
`castShadow`/`receiveShadow` flag set; `autoUpdate=true` should fix it on the
|
update has happened but the renderer's internal dirty tracking does not pick
|
||||||
next frame, but a single dropped frame is still visible at very first paint.
|
it up, leaving the shadow map stale or unrendered.
|
||||||
- HMR/state interactions in dev mode that do not occur in production builds.
|
|
||||||
|
|
||||||
Mitigations already applied:
|
Fix in `src/world/Lighting.tsx`: explicit `sun.shadow.needsUpdate = true` in
|
||||||
|
two places, restoring the belt-and-suspenders pattern from `develop`:
|
||||||
|
|
||||||
|
- After `configureSunShadow(...)` in the mount `useEffect`.
|
||||||
|
- At the end of the `useFrame` block, right after `sun.updateMatrixWorld()`.
|
||||||
|
|
||||||
|
Mitigations also in place:
|
||||||
|
|
||||||
- Shadow config centralized in `src/data/world/lightingConfig.ts`
|
- Shadow config centralized in `src/data/world/lightingConfig.ts`
|
||||||
(`bias=0`, `normalBias=0`, `cameraSize=95`, matching the historically working
|
(`bias=0`, `normalBias=0`, `cameraSize=95`).
|
||||||
values from `develop`).
|
|
||||||
- Late-suspension Suspense boundaries in `World.tsx` to prevent global scene
|
- Late-suspension Suspense boundaries in `World.tsx` to prevent global scene
|
||||||
remounts that would re-run shadow setup mid-load.
|
remounts that would re-run shadow setup mid-load.
|
||||||
|
- `gl.shadowMap.needsUpdate = true` on `onCreated` and on
|
||||||
|
`webglcontextrestored` in `src/pages/page.tsx`.
|
||||||
|
|
||||||
If the issue reproduces in production, capture a screenshot plus the
|
If the issue reproduces, capture `[diag]`-style logs from `useOctreeGraphNode`,
|
||||||
`[diag]`-style logs from `useOctreeGraphNode`, `Lighting`, and `GameMapCollision`
|
`Lighting`, and `GameMapCollision` to confirm there is no extra configuration
|
||||||
to confirm whether the third configuration pass is happening (which would
|
pass (which would indicate a remaining suspending hook outside the existing
|
||||||
indicate a remaining suspending hook outside the existing Suspense boundaries).
|
Suspense boundaries).
|
||||||
|
|||||||
Reference in New Issue
Block a user