From d6d4671989291283b44e21da411be5a7d31d7bb0 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 30 May 2026 19:00:29 +0200 Subject: [PATCH] =?UTF-8?q?fix(render):=20Phase=20U.4=20=E2=80=94=20EnvCel?= =?UTF-8?q?lRenderer.Render=20uploads=20its=20own=20uViewProjection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause of the indoor cell-shell SEAM flicker ("transparent walls, oscillating when moving"): EnvCellRenderer.Render never set uViewProjection — it inherited WbDrawDispatcher's. But the opaque shell pass draws BEFORE the dispatcher's Draw (GameWindow ~7411 vs ~7418, the only other setter), so opaque shells rendered with the PREVIOUS frame's matrix — a stale gl_Position against this frame's clip planes, yielding pose-dependent clipping that's worst while moving. Make Render self-contained: stash the view-projection in PrepareRenderBatches and upload it in Render (same matrix the portal clip planes use). Same self-contained-GL-state precedent as the 2026-05-28 cull-state fix in this file. Visual re-test confirms this removes the wall-seam flicker. A separate residual ("some houses show only background on interior walls; some flicker remains") is a distinct root cause, under investigation — NOT this matrix bug. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Rendering/Wb/EnvCellRenderer.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs b/src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs index 68ba289..0307c13 100644 --- a/src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs +++ b/src/AcDream.App/Rendering/Wb/EnvCellRenderer.cs @@ -53,6 +53,13 @@ public sealed unsafe class EnvCellRenderer : IDisposable // API mapping: Bind() -> Use(), SetUniform(s, int) -> SetInt(s, int), // SetUniform(s, Vector4) -> SetVec4(s, Vector4). private AcDream.App.Rendering.Shader? _shader; + + // Phase U.4 root-cause fix: the view-projection captured in PrepareRenderBatches, + // re-uploaded by Render() so the cell-shell pass is self-contained and does NOT + // inherit WbDrawDispatcher's uViewProjection (which the opaque pass would read one + // frame stale, since it draws BEFORE the dispatcher's upload). Same matrix the + // portal clip planes are computed with (envCellViewProj). + private Matrix4x4 _lastViewProjection = Matrix4x4.Identity; private bool _initialized; // List pool — copied from WB ObjectRenderManagerBase. @@ -522,6 +529,9 @@ public sealed unsafe class EnvCellRenderer : IDisposable int? centerLbY = null, int? renderRadius = null) { + // Phase U.4 fix: stash the view-projection so Render() can upload it itself. + _lastViewProjection = viewProjection; + // WB EnvCellRenderManager.cs:249-250: if (!_initialized || cameraPosition.Z > 4000) return; @@ -815,6 +825,16 @@ public sealed unsafe class EnvCellRenderer : IDisposable _shader.SetInt("uRenderPass", (int)renderPass); _shader.SetInt("uFilterByCell", 0); + // Phase U.4 ROOT-CAUSE FIX (cell-shell flicker / "transparent walls when + // moving"): upload uViewProjection HERE rather than inheriting it from + // WbDrawDispatcher. The opaque shell pass runs BEFORE the dispatcher's + // Draw (GameWindow ~7411 vs ~7418, the only other setter), so without + // this the opaque shells used the PREVIOUS frame's matrix — a stale + // gl_Position against this frame's clip planes → pose-dependent clipping, + // worst while moving. Same self-contained-GL-state precedent as the + // 2026-05-28 cull-state cache fix above. + _shader.SetMatrix4("uViewProjection", _lastViewProjection); + var allInstances = new List(); var drawCalls = new List<(ObjectRenderData renderData, int count, int offset)>();