From b19f3c14a9cef38d089a94584a4f72becbf49a92 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 27 May 2026 20:00:54 +0200 Subject: [PATCH] =?UTF-8?q?fix(render):=20Phase=20A8=20=E2=80=94=20LiveDyn?= =?UTF-8?q?amic=20in=20indoor=20branch=20+=20cull=20A/B=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/AcDream.App/Rendering/GameWindow.cs | 16 ++++++++++++++++ src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs | 14 ++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 3815737..7773441 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -7361,6 +7361,22 @@ public sealed class GameWindow : IDisposable camBuildings, otherBuildings, camera, frustum, playerLb, animatedIds, visibility?.VisibleCellIds); + + // Phase A8 fix (2026-05-28 visual-gate-#2 follow-up): LiveDynamic + // entities (player char, NPCs, dropped items, doors) were missing + // inside buildings because RenderInsideOutAcdream only renders the + // IndoorPass + OutdoorScenery partitions; LiveDynamic was implicitly + // excluded. The method's own header comment promised "LiveDynamic + // is drawn last in BOTH branches" but no call existed in the indoor + // path. Wire it here, after RenderInsideOutAcdream returns with + // stencil + state restored to defaults at its cleanup block. Same + // shape as the outdoor branch's Draw(All) for the LiveDynamic + // subset only. + _wbDrawDispatcher!.Draw(camera, _worldState.LandblockEntries, frustum, + neverCullLandblockId: playerLb, + visibleCellIds: visibility?.VisibleCellIds, + animatedEntityIds: animatedIds, + set: AcDream.App.Rendering.Wb.WbDrawDispatcher.EntitySet.LiveDynamic); } else { diff --git a/src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs b/src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs index 32e1a96..085c371 100644 --- a/src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs +++ b/src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs @@ -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);