diag(render/physics): flap root-caused to physics rest µm-jitter; refute prior diagnoses

Apparatus + handoff for the indoor flap. Confirmed (primary evidence): the flap is the
portal-flood clip being µm-sensitive at the threshold, driven by a ~1-8µm jitter in the
player RenderPosition (physics resting position not bit-stable; Lerp surfaces it). REFUTES
the 2026-06-07 see-through/EnvCell/outdoor-node diagnosis (ModelId GfxObj 0x01000A2B IS the
solid exterior) AND an enqueue-once attempt (retail propagates late slices via AddToCell;
the existing PropagatesNewSlicesToExit test caught it; reverted). Adds: Build determinism
test, A8CellAudit gfxobj dump, [pv-input] 6dp probe + [render-sig] outRoot/bshell fields.
No functional fix shipped. Next: higher-precision physics rest trace -> port retail
kill_velocity/contact rest-stability. Canonical: docs/research/2026-06-08-flap-rootcause-physics-rest-handoff.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-08 09:16:12 +02:00
parent d0b65c4170
commit d6aa526dd3
6 changed files with 300 additions and 1 deletions

View file

@ -7560,6 +7560,19 @@ public sealed class GameWindow : IDisposable
clipAssembly = pviewResult.ClipAssembly;
envCellShellFilter = pviewResult.DrawableCells;
_interiorPartition = pviewResult.Partition;
// Flap root-cause apparatus (2026-06-07): per-frame, the EXACT Build inputs at 6 dp +
// the resulting flood count. The live flap shows flood flipping 2↔6 at an eye/player
// identical to cm; this answers whether the inputs differ sub-cm (jitter) or are
// byte-identical (nondeterminism). See RenderingDiagnostics.ProbePvInputEnabled.
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbePvInputEnabled && pvFrame is not null)
{
var vp = envCellViewProj;
char pvOutRoot = ReferenceEquals(clipRoot, _outdoorNode) ? 'Y' : 'n';
Console.WriteLine(System.FormattableString.Invariant(
$"[pv-input] outRoot={pvOutRoot} flood={pvFrame.OrderedVisibleCells.Count} eye=({camPos.X:F6},{camPos.Y:F6},{camPos.Z:F6}) player=({playerViewPos.X:F6},{playerViewPos.Y:F6},{playerViewPos.Z:F6}) vp=[{vp.M11:F6} {vp.M13:F6} {vp.M22:F6} {vp.M31:F6} {vp.M33:F6} {vp.M41:F6} {vp.M42:F6} {vp.M43:F6}]"));
}
sigPvFrame = pviewResult.PortalFrame;
sigClipAssembly = pviewResult.ClipAssembly;
sigDrawableCells = pviewResult.DrawableCells;
@ -9190,6 +9203,22 @@ public sealed class GameWindow : IDisposable
sb.Append(" outdoorRootObjs=").Append(outdoorRootObjectCount);
sb.Append(" liveDynDraw=").Append(liveDynamicDrawnCount);
// Diagnosis 2026-06-07: draw-vs-occlude probe for the see-through residual.
// outRoot=Y means clipRoot is the synthetic outdoor node (eye outdoors). bshell=total/withMesh
// counts the building ModelId exterior shells queued in partition.Outdoor for this frame — the
// GfxObj exteriors that SHOULD draw the solid walls. Correlate with ids= (the flooded interior
// cells): if bshell=N/N and ids=[node only] but the wall is still see-through, the exterior is
// failing to rasterize (draw/clip bug, not EnvCell sidedness); if ids includes interior cells,
// the outdoor flood is drawing interiors over the exterior.
sb.Append(" outRoot=").Append(ReferenceEquals(clipRoot, _outdoorNode) ? 'Y' : 'n');
if (partition is not null)
{
int shellTotal = 0, shellMesh = 0;
foreach (var e in partition.Outdoor)
if (e.IsBuildingShell) { shellTotal++; if (e.MeshRefs.Count > 0) shellMesh++; }
sb.Append(" bshell=").Append(shellTotal).Append('/').Append(shellMesh);
}
if (outdoorPortalDrawn || exteriorPvFrame is not null || exteriorClipAssembly is not null)
{
sb.Append(" extPortal=").Append(outdoorPortalDrawn ? 'Y' : 'n');