diag(render): Phase A8.F — portal-frame visual-gate triage apparatus
Env-gated diagnostics (off by default; do not affect the default game): - ACDREAM_A8_DUMP_PV=1: PortalVisibilityBuilder dumps local→NDC→clipped portal geometry + OutsideView poly count for the first 2 Build calls per camera cell. - ACDREAM_PROBE_ENVCELL=1: [opaque] line dumps the opaque cell-render stats (cells/tris) BEFORE the per-cell transparent loop overwrites _envCellRenderer.Stats. Used to diagnose the A8.F visual-gate failure (see handoff doc). Gated behind ACDREAM_A8_INDOOR_BRANCH=1 like the rest of the indoor branch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
452ee5b9a1
commit
7c3ee438bd
2 changed files with 42 additions and 0 deletions
|
|
@ -11069,6 +11069,9 @@ public sealed class GameWindow : IDisposable
|
|||
currentEnvCellIds.Add(id);
|
||||
gl.Disable(EnableCap.Blend);
|
||||
_envCellRenderer!.Render(AcDream.App.Rendering.Wb.WbRenderPass.Opaque, currentEnvCellIds);
|
||||
// TEMP A8.F triage (strip after): opaque wall-render stats BEFORE the transparent loop overwrites them.
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeEnvCellEnabled && _a8OpaqueDumped.Add(cameraCell.CellId))
|
||||
Console.WriteLine($"[opaque] camCell=0x{cameraCell.CellId:X8} cells={_envCellRenderer.Stats.CellsRendered} tris={_envCellRenderer.Stats.TrianglesDrawn} filterCnt={currentEnvCellIds.Count}");
|
||||
|
||||
// Phase A8.F (#2): translucent cell geometry clipped to each cell's portal-chain
|
||||
// region (stencil BIT 2). Opaque cells already clip correctly via depth (left
|
||||
|
|
@ -11378,6 +11381,9 @@ public sealed class GameWindow : IDisposable
|
|||
|
||||
private readonly HashSet<(uint cellId, ulong gfxObjId)> _phaseA8AuditLogged = new();
|
||||
|
||||
// TEMP A8.F triage (strip after): one-shot-per-camCell guard for the [opaque] wall-render probe.
|
||||
private static readonly System.Collections.Generic.HashSet<uint> _a8OpaqueDumped = new();
|
||||
|
||||
private void EmitEnvCellProbe(int ourBldgs, int otherBldgs, int filterCnt)
|
||||
{
|
||||
if (!AcDream.Core.Rendering.RenderingDiagnostics.ProbeEnvCellEnabled) return;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,12 @@ public static class PortalVisibilityBuilder
|
|||
private const int MaxReprocessPerCell = 4;
|
||||
private const float PortalSideEpsilon = 0.01f; // matches CellVisibility.PointInCellEpsilon
|
||||
|
||||
// TEMP diagnostic (Phase A8.F visual-gate triage; strip after): ACDREAM_A8_DUMP_PV=1 dumps the
|
||||
// local→NDC→clipped portal geometry for the first 2 Build calls per distinct camera cell.
|
||||
private static readonly bool s_pvDump =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_A8_DUMP_PV") == "1";
|
||||
private static readonly Dictionary<uint, int> s_pvDumpCount = new();
|
||||
|
||||
/// <param name="lookup">Resolve a full cell id to its LoadedCell, or null if not loaded.</param>
|
||||
/// <param name="buildingMembership">Optional: true if a cell id is in the camera building's cell
|
||||
/// set. When provided, a neighbour OUTSIDE the set routes to CrossBuildingViews instead of
|
||||
|
|
@ -64,6 +70,18 @@ public static class PortalVisibilityBuilder
|
|||
var queue = new Queue<LoadedCell>();
|
||||
queue.Enqueue(cameraCell);
|
||||
|
||||
bool pvDump = false;
|
||||
if (s_pvDump)
|
||||
{
|
||||
lock (s_pvDumpCount)
|
||||
{
|
||||
s_pvDumpCount.TryGetValue(cameraCell.CellId, out int dc);
|
||||
if (dc < 2) { s_pvDumpCount[cameraCell.CellId] = dc + 1; pvDump = true; }
|
||||
}
|
||||
if (pvDump)
|
||||
Console.WriteLine($"[pv-dump] camCell=0x{cameraCell.CellId:X8} portals={cameraCell.Portals.Count} polyLists={cameraCell.PortalPolygons.Count} vp[M11={viewProj.M11:F3} M22={viewProj.M22:F3} M33={viewProj.M33:F3} M34={viewProj.M34:F3} M43={viewProj.M43:F3} M44={viewProj.M44:F3}]");
|
||||
}
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var cell = queue.Dequeue();
|
||||
|
|
@ -80,15 +98,21 @@ public static class PortalVisibilityBuilder
|
|||
var poly = cell.PortalPolygons[i];
|
||||
if (poly == null || poly.Length < 3) continue;
|
||||
|
||||
bool dx = pvDump && cell.Portals[i].OtherCellId == 0xFFFF;
|
||||
|
||||
// Portal-side test: only traverse a portal the camera is on the interior side of
|
||||
// (mirrors CellVisibility.GetVisibleCells + retail's 'seen' flag). Culls back-facing
|
||||
// portals so we never feed a degenerate/wrong-facing projection downstream.
|
||||
if (i < cell.ClipPlanes.Count && !CameraOnInteriorSide(cell, i, cameraPos))
|
||||
{
|
||||
if (dx) Console.WriteLine($"[pv-dump] EXIT-CULLED(side) cell=0x{cell.CellId:X8} p{i} localN={poly.Length} hasClipPlane={(i < cell.ClipPlanes.Count)}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Project to NDC, then normalize to CCW for the CCW-only ScreenPolygonClip
|
||||
// (ProjectToNdc preserves input winding; portal dat polygons may be CW).
|
||||
Vector2[] portalNdc = PortalProjection.ProjectToNdc(poly, cell.WorldTransform, viewProj);
|
||||
if (dx) Console.WriteLine($"[pv-dump] EXIT-PROJ cell=0x{cell.CellId:X8} p{i} localN={poly.Length} ndcN={portalNdc.Length} local0=({poly[0].X:F2},{poly[0].Y:F2},{poly[0].Z:F2}) ndc=[{string.Join(" ", System.Array.ConvertAll(portalNdc, v => $"({v.X:F2},{v.Y:F2})"))}]");
|
||||
if (portalNdc.Length < 3) continue;
|
||||
EnsureCcw(portalNdc);
|
||||
|
||||
|
|
@ -99,12 +123,21 @@ public static class PortalVisibilityBuilder
|
|||
var clipped = ScreenPolygonClip.Intersect(portalNdc, vp.Vertices);
|
||||
if (clipped.Length >= 3) clippedRegion.Add(new ViewPolygon(clipped));
|
||||
}
|
||||
if (dx) Console.WriteLine($"[pv-dump] EXIT-CLIP cell=0x{cell.CellId:X8} p{i} currentViewPolys={currentView.Polygons.Count} clipResult={clippedRegion.Count}");
|
||||
if (clippedRegion.Count == 0) continue; // portal not visible through this chain
|
||||
|
||||
var portal = cell.Portals[i];
|
||||
|
||||
if (portal.OtherCellId == 0xFFFF)
|
||||
{
|
||||
if (pvDump)
|
||||
{
|
||||
Console.WriteLine($"[pv-dump] EXIT cell=0x{cell.CellId:X8} p{i} localN={poly.Length} ndcN={portalNdc.Length} clipPolys={clippedRegion.Count}");
|
||||
Console.WriteLine($"[pv-dump] local=[{string.Join(" ", System.Array.ConvertAll(poly, v => $"({v.X:F2},{v.Y:F2},{v.Z:F2})"))}]");
|
||||
Console.WriteLine($"[pv-dump] ndc=[{string.Join(" ", System.Array.ConvertAll(portalNdc, v => $"({v.X:F3},{v.Y:F3})"))}]");
|
||||
foreach (var cp in clippedRegion)
|
||||
Console.WriteLine($"[pv-dump] clipped({cp.Vertices.Length})=[{string.Join(" ", System.Array.ConvertAll((Vector2[])cp.Vertices, v => $"({v.X:F3},{v.Y:F3})"))}]");
|
||||
}
|
||||
// Exit portal -> outdoors visible through this (clipped) opening.
|
||||
foreach (var cp in clippedRegion) frame.OutsideView.Add(cp);
|
||||
continue;
|
||||
|
|
@ -135,6 +168,9 @@ public static class PortalVisibilityBuilder
|
|||
}
|
||||
}
|
||||
|
||||
if (pvDump)
|
||||
Console.WriteLine($"[pv-dump] OUTSIDEVIEW polys={frame.OutsideView.Polygons.Count} bfsCellViews={frame.CellViews.Count} crossBldg={frame.CrossBuildingViews.Count}");
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue