fix(render): Phase U.4 — EnvCellRenderer sets its own BLEND + DepthMask per pass

Second self-contained-GL-state fix (after uViewProjection): EnvCellRenderer.Render set
BlendFunc per-batch but never the BLEND enable or DepthMask. The opaque shell pass —
drawn after terrain (which sets neither) and after particles / last frame's transparent
pass — inherited whatever left GL_BLEND enabled, making opaque walls composite their
sub-1.0-alpha textures against the bluish clear color (terrain Skip'd indoors) →
"transparent walls / only background," flickering with per-frame ordering. Mirror the
working WbDrawDispatcher: Disable(Blend)+DepthMask(true) opaque, Enable(Blend)+
DepthMask(false) transparent, restore opaque defaults after the draw loop.

Does NOT address the threshold "flap" (OutsideView instability from the per-frame
view-dependent BFS) — that is a distinct, deeper root cause tracked separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-31 09:11:06 +02:00
parent d6d4671989
commit 9be9547ddc

View file

@ -959,6 +959,27 @@ public sealed unsafe class EnvCellRenderer : IDisposable
shader.Use(); shader.Use();
shader.SetInt("uFilterByCell", 0); shader.SetInt("uFilterByCell", 0);
// Phase U.4 ROOT-CAUSE FIX (cell-shell "transparent walls / only bluish
// background, flickering when moving"): establish this pass's BLEND + DepthMask
// state OURSELVES rather than inheriting it. Render(Opaque) runs right after the
// terrain draw (which sets neither) and after particles / last frame's transparent
// pass — so whatever left GL_BLEND enabled made the OPAQUE shells composite their
// (often sub-1.0 alpha) wall textures against the bluish clear color (terrain is
// Skip'd indoors), toggling with per-frame ordering → flicker. Mirror the working
// WbDrawDispatcher passes (Disable(Blend)+DepthMask(true) opaque;
// Enable(Blend)+DepthMask(false) transparent). Restored to opaque defaults at the
// end of the draw loop so a Transparent pass can't leak into later draws.
if (renderPass == WbRenderPass.Transparent)
{
_gl.Enable(EnableCap.Blend);
_gl.DepthMask(false);
}
else
{
_gl.Disable(EnableCap.Blend);
_gl.DepthMask(true);
}
// WB BaseObjectRenderManager.cs:718-740: group batches by CullMode + additive flag. // WB BaseObjectRenderManager.cs:718-740: group batches by CullMode + additive flag.
var batchesByCullMode = new Dictionary<int, List<(ObjectRenderBatch batch, int instanceCount, int instanceOffset)>>(); var batchesByCullMode = new Dictionary<int, List<(ObjectRenderBatch batch, int instanceCount, int instanceOffset)>>();
int totalDraws = 0; int totalDraws = 0;
@ -1174,6 +1195,12 @@ public sealed unsafe class EnvCellRenderer : IDisposable
currentDrawOffset += numDraws; currentDrawOffset += numDraws;
} }
// Phase U.4: leave a clean opaque-default render state (mirrors WbDrawDispatcher's
// post-transparent restore) so a Transparent pass's Blend-on / DepthMask-off does
// not leak into particles or the next frame's draws.
_gl.Disable(EnableCap.Blend);
_gl.DepthMask(true);
// WB BaseObjectRenderManager.cs:845-847: // WB BaseObjectRenderManager.cs:845-847:
shader.SetInt("uDrawIDOffset", 0); shader.SetInt("uDrawIDOffset", 0);
_gl.BindBuffer(GLEnum.DrawIndirectBuffer, 0); _gl.BindBuffer(GLEnum.DrawIndirectBuffer, 0);