fix(render): Phase A8 R3.5 — gate stencil branch on PointInCell containment
Closes the transition-flicker symptom observed during R4 visual verification: brief 1-3 frames after exiting a building where outdoor scenery rendered with wrong stencil mask, "walls disappear and buildings show under ground" shimmer, and sky stayed suppressed. Root cause: CellVisibility.FindCameraCell holds the previous CameraCell for ~3 grace frames after the camera physically exits the cell volume (see _cellSwitchGraceFrames). The grace mechanism prevents flicker at the doorway threshold for sky/lighting/depth-clear, but the new R3 stencil branch was using `cameraInsideCell` directly — so during grace frames it ran MarkAndPunch with the previous cell's portals (now behind/ beside the camera) and the IndoorPass + stencil-gated outdoor produced the garbage frame. Fix: compute `cameraReallyInside` via the stricter CellVisibility.PointInCell containment check and use it (instead of `cameraInsideCell`) as the gate for the stencil branch. Sky, depth-clear, lighting, and particles continue to use `cameraInsideCell` so their smooth grace-aware behavior is unchanged. Handoff item #10 (docs/research/2026-05-26-a8-revert-handoff.md) flagged this exact concern: "Likely the CellSwitchGraceFrameCount = 3 interacting with stencil setup timing." Confirmed and closed. Visual-verification of the fix is part of R4 (re-run). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
60f07bc21b
commit
38d537491f
1 changed files with 23 additions and 1 deletions
|
|
@ -7141,7 +7141,29 @@ public sealed class GameWindow : IDisposable
|
||||||
animatedIds.Add(k);
|
animatedIds.Add(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cameraInsideCell && _indoorStencilPipeline is not null
|
// Phase A8 R3.5 — transition-flicker fix. `cameraInsideCell`
|
||||||
|
// stays true for ~3 grace frames after the camera physically
|
||||||
|
// exits a cell (see CellVisibility._cellSwitchGraceFrames).
|
||||||
|
// The grace mechanism prevents lighting/sky flicker at the
|
||||||
|
// doorway threshold, but if the stencil pipeline runs during
|
||||||
|
// grace frames it marks/punches at the OLD cell's portal
|
||||||
|
// silhouettes — which are now behind/beside the camera — and
|
||||||
|
// the subsequent IndoorPass + stencil-gated outdoor produce
|
||||||
|
// a brief frame of "walls disappear + buildings under ground"
|
||||||
|
// garbage. Gate the stencil branch on the stricter
|
||||||
|
// `PointInCell` containment check so the pipeline only runs
|
||||||
|
// when the camera is ACTUALLY inside its cell volume; sky /
|
||||||
|
// lighting / depth-clear continue to use `cameraInsideCell`
|
||||||
|
// for their smoother grace-aware behavior.
|
||||||
|
bool cameraReallyInside = visibility?.CameraCell is not null
|
||||||
|
&& CellVisibility.PointInCell(camPos, visibility.CameraCell);
|
||||||
|
|
||||||
|
// The `visibility?.CameraCell is not null` repeat is for the
|
||||||
|
// compiler's null-flow analysis: `cameraReallyInside` already
|
||||||
|
// implies it, but flow doesn't propagate through a separate
|
||||||
|
// local. Restating it inside the if condition lets the branch
|
||||||
|
// body use the un-`?`d form without null-forgiving.
|
||||||
|
if (cameraReallyInside && _indoorStencilPipeline is not null
|
||||||
&& visibility?.CameraCell is not null)
|
&& visibility?.CameraCell is not null)
|
||||||
{
|
{
|
||||||
// Phase A8 R3 — WB RenderInsideOut order.
|
// Phase A8 R3 — WB RenderInsideOut order.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue