fix(render): Phase A8 — LiveDynamic in indoor branch + cull A/B gate

Two changes from visual-gate-#2 evidence.

LiveDynamic fix (real bug closure):
The user reported "can't see char ... door is missing" in visual gate #2.
Doors and the player char are LiveDynamic entities (ServerGuid != 0). The
outdoor branch's Draw(set: All) includes them; the indoor branch's
RenderInsideOutAcdream only renders IndoorPass + OutdoorScenery partitions,
implicitly excluding LiveDynamic. The method's own header comment promised
"LiveDynamic is drawn last in BOTH branches" but no call existed in the
indoor path — a documented behavior with no implementation. Wire the
LiveDynamic Draw after RenderInsideOutAcdream returns with stencil + state
restored to defaults at its cleanup block.

Cull A/B diagnostic (bisect floor-missing root cause):
ACDREAM_A8_DISABLE_CULL=1 forces every cell-mesh batch's effective CullMode
to None. The visual-gate-#2 audit confirmed cell meshes upload correctly
(every cell has multi-batch render data with non-zero indices, no null
data, no zero handles). Every batch uniformly reports CullMode.Landblock
which maps to glCullFace(Back) — identical to WB's mapping. So data is
fine and CullMode lookup is fine; only the BIND-TIME interaction (polygon
winding orientation in our coord system + cull-back) could still hide
specific polys. If floor appears with this gate set, cull/winding is the
remaining bug (need to either invert winding upstream or remap CullMode);
if not, the issue is elsewhere (lighting / depth / alpha) and we look
there. Tight bisect — one launch's evidence.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-27 20:00:54 +02:00
parent 772d69c7a6
commit b19f3c14a9
2 changed files with 30 additions and 0 deletions

View file

@ -81,6 +81,16 @@ public sealed unsafe class EnvCellRenderer : IDisposable
private static uint _currentVao;
private static CullMode? _currentCullMode;
// Phase A8 A/B diagnostic (2026-05-28 visual-gate-#2 follow-up):
// ACDREAM_A8_DISABLE_CULL=1 forces every batch's effective CullMode to
// None (no face culling). Used to isolate whether the missing-floor
// symptom is caused by polygon-winding+CullMode interaction or by
// something else (lighting, depth, alpha). If the floor appears with
// this set, cull/winding is the bug. If not, look elsewhere. Static
// because it's read once at startup; no need to re-query per draw.
private static readonly bool _forceCullModeNone =
string.Equals(Environment.GetEnvironmentVariable("ACDREAM_A8_DISABLE_CULL"), "1", StringComparison.Ordinal);
public bool NeedsPrepare { get; private set; } = true;
public bool IsDisposed { get; private set; }
@ -987,6 +997,10 @@ public sealed unsafe class EnvCellRenderer : IDisposable
foreach (var group in batchesByCullMode)
{
var cullMode = (CullMode)(group.Key % 4);
// A/B diagnostic: ACDREAM_A8_DISABLE_CULL=1 overrides every batch
// to no-culling. Reveals whether floor-missing is a cull/winding
// bug or something else.
if (_forceCullModeNone) cullMode = CullMode.None;
if (_currentCullMode != cullMode)
{
SetCullMode(cullMode);