The cull A/B diagnostic (prior commit's ACDREAM_A8_DISABLE_CULL=1) in
visual-gate-#3 confirmed: cell-mesh polys are being culled by back-face
culling, which is why floors disappear when looking down from inside a
room. Per-cell audit data showed every cell-mesh batch has
CullMode.Landblock — assigned because AC's CellStruct polys carry
SidesType=Landblock in the dat. Our SetCullMode maps Landblock to
glCullFace(Back), matching WB.
Root cause:
WB sets `glFrontFace(GLEnum.CW)` globally at GameScene.cs:843. Our
WbDrawDispatcher.cs:1056 sets `glFrontFace(CCW)` — the GL default,
opposite of WB. With our flipped-from-natural fan triangulation in
BuildCellStructPolygonIndices (which emits (i, i-1, 0) for each fan
triangle, reversing the input vertex order), the resulting effective
winding from the camera's perspective is OPPOSITE WB's. Cull-back then
removes the OPPOSITE face from what WB does — hiding the floor side
that should be visible from inside the room.
Within a single cell-mesh batch, the polys face every direction (walls
outward, floor up, ceiling down) but all share CullMode.Landblock. No
single cull setting can be correct for all three orientations
simultaneously — the retail-faithful approach is to render cell polys
double-sided (cull off).
Two changes scoped to EnvCellRenderer.RenderModernMDIInternal so other
renderers aren't affected:
1. Remap CullMode.Landblock → None when iterating per-cull-mode
batch groups. Cell polys render with cull disabled, all faces
visible. CullMode.Landblock is only assigned by
PrepareCellStructMeshData (cell polys) in this codebase — terrain
uses a different render path. Scope is exactly right.
2. Explicitly Enable(CullFace) + CullFace(Back) at Render exit so the
dispatcher's subsequent IndoorPass + LiveDynamic Draws don't
inherit the cull-disabled state. The see-through-head symptom in
visual-gate-#3 was caused by exactly this state leak from the
ACDREAM_A8_DISABLE_CULL=1 diagnostic; the proper fix needs the
explicit restore. Also updates the static `_currentCullMode` cache
so the next Render call's first SetCullMode comparison is correct.
Removed the ACDREAM_A8_DISABLE_CULL diagnostic env var — its role as
A/B test is complete. 14/14 EnvCellRenderer tests pass. Build green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>