test(render) Campaign FW1: the portal-gate microscope + its verdict
Per-portal dump for the street fixture (archived beside the fixtures): retail punched exactly the buildings whose portal polygons MY camera model clips to NOTHING (001a/0022: clipN=0, doorways ~75 deg off my north-facing axis) and skipped the ones mine puts on-screen (001e/0026: clipN=4-6) - a clean inversion isolating the final look-in delta to either the camera FACING decode (re-check the terrace-edge fixture against its known vista direction; the motion sweep's 20-degree residual is now suspect) or a portal-pass clip mechanism that does not gate on the active view (cdb ConstructView(CBldPortal) trace next retail session). All layers above are retail-pinned. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e23a589a6b
commit
5f18ba5507
2 changed files with 118 additions and 0 deletions
|
|
@ -0,0 +1,88 @@
|
|||
using AcDream.App.Tests.Rendering;
|
||||
using AcDream.App.Rendering.Walk;
|
||||
using DatReaderWriter;
|
||||
using DatReaderWriter.Options;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace AcDream.App.Tests.Rendering.Walk;
|
||||
|
||||
/// <summary>
|
||||
/// FW1 look-in gate microscope: for the street fixture pose, dump every
|
||||
/// gate input for building a9b4001a (retail punches it) vs a9b4001e
|
||||
/// (retail does not): raw portal flags, the BSP-emitted polygon's plane,
|
||||
/// the eye's signed distance and side, and the active-view clip count.
|
||||
/// Writes the dump to the scratch directory; always passes.
|
||||
/// </summary>
|
||||
[Trait("Lane", "InstalledDat")]
|
||||
public sealed class WalkPortalGateDumpTests
|
||||
{
|
||||
[Fact]
|
||||
public void Dump_the_gate_inputs_for_a_punching_and_a_silent_building()
|
||||
{
|
||||
string? datDir = CornerFloodReplayTests.ResolveDatDir();
|
||||
if (datDir is null)
|
||||
{
|
||||
Assert.Fail("Lane=InstalledDat requires an installed retail DAT directory.");
|
||||
}
|
||||
IReadOnlyList<WalkOracleFrame> frames =
|
||||
WalkOracleTrace.Load("posed/holtburg-street-outdoor");
|
||||
WalkOracleFrame frame = frames[1];
|
||||
Assert.NotNull(frame.Pose);
|
||||
using var dats = new DatCollection(datDir!, DatAccessType.Read);
|
||||
WalkLandscapeDatBuilder.BuiltWorld world =
|
||||
WalkLandscapeDatBuilder.Build(dats, frame.Pose!.CellId);
|
||||
var ctx = new WalkTraceReplayContext(frame.Pose, world.Cells)
|
||||
{
|
||||
Buildings = world.Buildings,
|
||||
};
|
||||
// Install the outdoor default view as the active clip context.
|
||||
var defaultView = new WalkPortalView();
|
||||
WalkCopyView.AppendFullViewportQuad(
|
||||
defaultView, ctx.Rays, ctx.WorldViewpoint,
|
||||
ctx.ViewportWidth, ctx.ViewportHeight);
|
||||
ctx.SetActiveView(defaultView, 0);
|
||||
|
||||
var dump = new StringBuilder();
|
||||
Span<WalkScreenPoint> clipped = stackalloc WalkScreenPoint[64];
|
||||
dump.AppendLine($"pose cell={frame.Pose.CellId:x8} origin={frame.Pose.Origin}");
|
||||
foreach (uint id in new[] { 0xA9B4001Au, 0xA9B4001Eu, 0xA9B40022u, 0xA9B40026u })
|
||||
{
|
||||
WalkBuilding building = world.Buildings.Keys.Single(b => b.PositionCellId == id);
|
||||
float dist = ctx.ViewerDistanceTo(building);
|
||||
Vector3 eyeInBuilding = ctx.ViewpointInBuilding(building);
|
||||
dump.AppendLine(
|
||||
$"building {id:x8}: dist={dist:f1} eff={MathF.Max(0f, dist - 100f):f1} "
|
||||
+ $"eyeLocal={eyeInBuilding} portals={building.Portals.Length}");
|
||||
WalkBspNode? bsp = building.SelectDrawingBsp(dist);
|
||||
var refs = new List<WalkPortalRef>();
|
||||
Collect(bsp, refs);
|
||||
dump.AppendLine($" level BSP portal refs: {refs.Count}");
|
||||
foreach (WalkPortalRef portalRef in refs)
|
||||
{
|
||||
ref WalkBldPortal bp = ref building.Portals[portalRef.PortalIndex];
|
||||
float d = Vector3.Dot(portalRef.Polygon.Plane.Normal, eyeInBuilding)
|
||||
+ portalRef.Polygon.Plane.D;
|
||||
int side = d > WalkVisibilityMath.Epsilon ? 0
|
||||
: d < -WalkVisibilityMath.Epsilon ? 1 : 2;
|
||||
int n = ctx.ClipBuildingPolygon(building, portalRef.Polygon, side, clipped);
|
||||
dump.AppendLine(
|
||||
$" ref idx={portalRef.PortalIndex} other={bp.OtherCellId:x8} "
|
||||
+ $"rawSide={bp.PortalSide} exact={bp.ExactMatch} "
|
||||
+ $"planeD@eye={d:f2} eyeSide={side} clipN={n} "
|
||||
+ $"gate(side==rawSide)={(side == bp.PortalSide ? "PASS" : "reject")}");
|
||||
}
|
||||
}
|
||||
string path = Path.Combine(Path.GetTempPath(), "fw1-portal-gate-dump.txt");
|
||||
File.WriteAllText(path, dump.ToString());
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
private static void Collect(WalkBspNode? node, List<WalkPortalRef> into)
|
||||
{
|
||||
if (node is null) return;
|
||||
if (node.InPortals is not null) into.AddRange(node.InPortals);
|
||||
Collect(node.PosNode, into);
|
||||
Collect(node.NegNode, into);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue