From d366f36557161b33bf5b945768dc24b61917d05e Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 6 Jul 2026 21:46:49 +0200 Subject: [PATCH] diag #181 (refined): 0x0181's region is a zero-area sliver; the amplifier is per-drawn-cell state shifting with the cell list, not light-pool scoping Diagnostic_FlappingCellViewRegion_SliverOrLarge: at the flap pose the admitted region is one degenerate triangle (ndcArea ~0), and ClipPlaneSet.From handles degenerates correctly (area<1e-7 -> Empty) - the cell's own gated geometry costs ~zero pixels either way. The a7 pseudocode CORRECTION-2 re-read kills the flood-scoped-lights framing (the pool is already resident+player-anchored since d8984e87). Remaining suspects: per-cell light-set SSBO slot assignment (SelectForCell) or the seal/punch assembly keyed to the drawn-cell list. Next instrument: parked ACDREAM_PROBE_SEAMDRAW=1 run, diff the washed cell's [seam-blk] applied-set lines between vis=31 and vis=32 frames. ISSUES #181 + render digest updated. Co-Authored-By: Claude Fable 5 --- docs/ISSUES.md | 23 ++++++-- .../Rendering/Issue181VisFlapReplayTests.cs | 59 +++++++++++++++++++ 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 1cb02752..029008f3 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -91,12 +91,23 @@ may never have been disabled. independent — a sliver cell flapping costs retail a few pixels; it costs us whole lit regions (the washed-region strobe). -**The fix:** replace camera-flood light scoping with retail's registration-time light -reach sets (per-light cell-set walk from the light's own cell through the portal graph; -decomp pseudocode already on disk: -`docs/research/2026-07-06-a7-per-cell-lighting-pseudocode.md`). The wall-press wobble -and the binary knife-edge admission then match retail's visible behavior (sub-pixel -consequences). No hysteresis/damping band-aids on the flood. +**REFINEMENT (same night, after the a7-pseudocode CORRECTION-2 re-read):** the pool is +ALREADY resident-scoped + player-anchored (`d8984e87` deleted the flood-scoped slice-1), +so "flood-scoped lights" is NOT the amplifier as first framed. Measured: 0x0181's +admitted view region at the flap pose is ONE zero-NDC-area sliver triangle +(`Diagnostic_FlappingCellViewRegion_SliverOrLarge`), and `ClipPlaneSet.From` handles +degenerates correctly (area < 1e-7 → Empty; sliver planes otherwise) — so the cell's own +gated geometry costs ~zero pixels either way. **The amplifier is downstream of ADMISSION +but not the slice gate: 0x0181 joining/leaving changes the DRAWN-CELL LIST, and some +per-drawn-cell state keyed by list position/rebuild — prime suspects: the per-cell +light-set SSBO slots (`SelectForCell`, d8984e87) shifting so a DIFFERENT cell reads the +wrong 8-light set on minority frames, or the seal/punch assembly — flips a whole cell's +lighting.** That is cell-sized, matches the captures (washed region with hard +boundaries), and is directly instrumentable: run parked with `ACDREAM_PROBE_SEAMDRAW=1` +(+FLAP) and diff the `[seam-blk]` applied-set lines of the WASHED cell between vis=31 +and vis=32 frames — if its applied set (or slot index) changes with 0x0181's admission, +the indexing/rebuild site is the defect. NO band-aids on the flood admission itself +(the sliver flap is retail-class). **Acceptance:** parked pressed camera in the washed spot → lit regions steady (the `[flap]` vis 31↔32 flap may legitimately persist at sub-pixel visual cost); frame-pair diff --git a/tests/AcDream.App.Tests/Rendering/Issue181VisFlapReplayTests.cs b/tests/AcDream.App.Tests/Rendering/Issue181VisFlapReplayTests.cs index a035bed0..d026eb4d 100644 --- a/tests/AcDream.App.Tests/Rendering/Issue181VisFlapReplayTests.cs +++ b/tests/AcDream.App.Tests/Rendering/Issue181VisFlapReplayTests.cs @@ -55,6 +55,65 @@ public class Issue181VisFlapReplayTests private static string CellSetString(IEnumerable ids) => string.Join(" ", ids.Select(id => $"{id & 0xFFFFu:X4}")); + [Fact] + public void Diagnostic_FlappingCellViewRegion_SliverOrLarge() + { + var datDir = CornerFloodReplayTests.ResolveDatDir(); + if (datDir is null) { _out.WriteLine("SKIP: no dat dir"); return; } + using var dats = new DatCollection(datDir, DatAccessType.Read); + var cells = Issue120ReciprocalPingPongTests.LoadAllInteriorCells(dats, FacilityHub); + uint flapper = FacilityHub | 0x0181u; + + // The most unstable pose from the perturbation sweep. + float yaw = 15f * MathF.PI / 180f, pitch = -20f * MathF.PI / 180f; + var gaze = new Vector3( + MathF.Cos(pitch) * MathF.Cos(yaw), + MathF.Cos(pitch) * MathF.Sin(yaw), + MathF.Sin(pitch)); + + Func lookup = id => cells.TryGetValue(id, out var c) ? c : null; + + foreach (var (label, eye) in new (string, Vector3)[] + { + ("base ", LiveEye), + ("+0.5mm x ", LiveEye + new Vector3(0.0005f, 0, 0)), + ("-0.5mm x ", LiveEye - new Vector3(0.0005f, 0, 0)), + ("+5mm x ", LiveEye + new Vector3(0.005f, 0, 0)), + ("-5mm x ", LiveEye - new Vector3(0.005f, 0, 0)), + ("+2cm z ", LiveEye + new Vector3(0, 0, 0.02f)), + ("-2cm z ", LiveEye - new Vector3(0, 0, 0.02f)), + }) + { + var frame = PortalVisibilityBuilder.Build( + cells[LiveRoot], eye, lookup, ViewProjFor(eye, gaze), + buildingMembership: null, + drawLiftZ: PortalVisibilityBuilder.ShellDrawLiftZ); + + if (!frame.CellViews.TryGetValue(flapper, out var view) || view.IsEmpty) + { + _out.WriteLine($"{label}: 0181 NOT ADMITTED"); + continue; + } + + // NDC shoelace area of the admitted region (screen is 4.0 NDC-units total). + float area = 0f; int polys = 0, verts = 0; + foreach (var vp in view.Polygons) + { + var v = vp.Vertices; + polys++; verts += v.Length; + float a = 0f; + for (int i = 0; i < v.Length; i++) + { + var p = v[i]; var q = v[(i + 1) % v.Length]; + a += p.X * q.Y - q.X * p.Y; + } + area += MathF.Abs(a) * 0.5f; + } + _out.WriteLine(FormattableString.Invariant( + $"{label}: 0181 admitted polys={polys} verts={verts} ndcArea={area:F4} ({area / 4f * 100f:F1}% of screen)")); + } + } + [Fact] public void Diagnostic_SubMillimeterEyePerturbation_MustNotChangeAdmission() {