diff --git a/src/AcDream.App/Rendering/PortalVisibilityBuilder.cs b/src/AcDream.App/Rendering/PortalVisibilityBuilder.cs index f828abfb..ebf70c94 100644 --- a/src/AcDream.App/Rendering/PortalVisibilityBuilder.cs +++ b/src/AcDream.App/Rendering/PortalVisibilityBuilder.cs @@ -200,6 +200,20 @@ public static class PortalVisibilityBuilder bool dx = pvDump && cell.Portals[i].OtherCellId == 0xFFFF; bool eyeInsideOpening = EyeInsidePortalOpening(poly, cell.WorldTransform, cameraPos); + + // (R-A2b Phase 1 pin, throwaway) Log the side-test inputs for EVERY portal so a back-portal + // traversal (cell=0x..0173 p->0x0171) can be attributed to B1 (eyeInsideOpening bypasses the + // side-cull) vs B2 (CameraOnInteriorSide returns interior where retail's InitCell culls). + // |D|<=1.75 means eyeInsideOpening is in range. Strip with the rest of the [pv-trace] apparatus. + if (trace != null) + { + bool camInterior = i >= cell.ClipPlanes.Count || CameraOnInteriorSide(cell, i, cameraPos); + float sideD = (i < cell.ClipPlanes.Count && cell.ClipPlanes[i].Normal.LengthSquared() >= 1e-8f) + ? Vector3.Dot(cell.ClipPlanes[i].Normal, Vector3.Transform(cameraPos, cell.InverseWorldTransform)) + cell.ClipPlanes[i].D + : float.NaN; + trace.Add($"sidechk cell=0x{cell.CellId:X8} p{i}->0x{portal.OtherCellId:X4} camInterior={camInterior} eyeIn={eyeInsideOpening} D={(float.IsNaN(sideD) ? "na" : sideD.ToString("F2"))}"); + } + bool sideAllowed = true; // Portal-side test: only traverse a portal the camera is on the interior side of