test(physics): BSPQuery.FindCollisions writes world-space plane with translated origin
Regression test for indoor BSP world-origin fix (Bug B). Verifies that BSPQuery.FindCollisions with path.StepDown=true and a non-zero worldOrigin parameter writes a world-space ContactPlane to CollisionInfo (not a cell-local-space one). Passes before the call-site fix at TransitionTypes.cs:1442 because BSPQuery itself is correct when called with the right args — it's the caller that was passing the defaults. This test locks in the BSPQuery contract so the relationship between worldOrigin/localToWorld input and ContactPlane.D output cannot regress silently. Spec: docs/superpowers/specs/2026-05-20-indoor-bsp-worldorigin-fix-design.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
56816fcbe4
commit
39d4e6512b
1 changed files with 92 additions and 0 deletions
|
|
@ -418,4 +418,96 @@ public class BSPQueryTests
|
||||||
|
|
||||||
Assert.False(found);
|
Assert.False(found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// FindCollisions — world-origin / world-rotation correctness (spec 2026-05-20)
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build a single-leaf BSP with one horizontal floor polygon at the given
|
||||||
|
/// cell-local Z. Vertex array forms a 4x4 m square centered at cell-local
|
||||||
|
/// (0, 0).
|
||||||
|
/// </summary>
|
||||||
|
private static (PhysicsBSPNode root, Dictionary<ushort, ResolvedPolygon> resolved)
|
||||||
|
BuildSingleFloorBsp(float floorZ)
|
||||||
|
{
|
||||||
|
var verts = new[]
|
||||||
|
{
|
||||||
|
new Vector3(-2f, -2f, floorZ),
|
||||||
|
new Vector3( 2f, -2f, floorZ),
|
||||||
|
new Vector3( 2f, 2f, floorZ),
|
||||||
|
new Vector3(-2f, 2f, floorZ),
|
||||||
|
};
|
||||||
|
|
||||||
|
var root = new PhysicsBSPNode
|
||||||
|
{
|
||||||
|
Type = BSPNodeType.Leaf,
|
||||||
|
BoundingSphere = new Sphere
|
||||||
|
{
|
||||||
|
Origin = new Vector3(0f, 0f, floorZ),
|
||||||
|
Radius = 3f,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
root.Polygons.Add(0);
|
||||||
|
|
||||||
|
var resolved = new Dictionary<ushort, ResolvedPolygon>
|
||||||
|
{
|
||||||
|
[0] = new ResolvedPolygon
|
||||||
|
{
|
||||||
|
Vertices = verts,
|
||||||
|
Plane = new Plane(Vector3.UnitZ, -floorZ),
|
||||||
|
NumPoints = 4,
|
||||||
|
SidesType = CullMode.None,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (root, resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindCollisions_StepDown_TranslatedWorldOrigin_WritesWorldSpacePlane()
|
||||||
|
{
|
||||||
|
// Cell is translated +94 m in world Z (i.e., the cell-local floor at
|
||||||
|
// Z=0 sits at world Z=94). This mirrors the Holtburg cottage scenario
|
||||||
|
// captured in launch-cp-probe.log (cell 0xA9B40150, floor world
|
||||||
|
// Z≈94.02).
|
||||||
|
var (root, resolved) = BuildSingleFloorBsp(floorZ: 0f);
|
||||||
|
|
||||||
|
var transition = new Transition();
|
||||||
|
transition.SpherePath.WalkableAllowance = PhysicsGlobals.FloorZ;
|
||||||
|
transition.SpherePath.WalkInterp = 1.0f;
|
||||||
|
transition.SpherePath.StepDown = true;
|
||||||
|
transition.SpherePath.StepDownAmt = 0.5f;
|
||||||
|
|
||||||
|
// Foot sphere in cell-local space: overlapping the floor (Z=0.4 with
|
||||||
|
// radius 0.48 → dist 0.4 < radius−epsilon = 0.4798, so the precise
|
||||||
|
// overlap test accepts the contact).
|
||||||
|
var localSphere = new Sphere
|
||||||
|
{
|
||||||
|
Origin = new Vector3(0f, 0f, 0.4f),
|
||||||
|
Radius = 0.48f,
|
||||||
|
};
|
||||||
|
|
||||||
|
var state = BSPQuery.FindCollisions(
|
||||||
|
root,
|
||||||
|
resolved,
|
||||||
|
transition,
|
||||||
|
localSphere,
|
||||||
|
localSphere1: null,
|
||||||
|
localCurrCenter: localSphere.Origin,
|
||||||
|
localSpaceZ: Vector3.UnitZ,
|
||||||
|
scale: 1.0f,
|
||||||
|
localToWorld: Quaternion.Identity,
|
||||||
|
engine: null,
|
||||||
|
worldOrigin: new Vector3(0f, 0f, 94f));
|
||||||
|
|
||||||
|
// Path 3 step-down should fire and adjust the sphere onto the floor.
|
||||||
|
Assert.Equal(TransitionState.Adjusted, state);
|
||||||
|
|
||||||
|
// ContactPlane must be in world space: normal stays (0,0,1) since the
|
||||||
|
// cell rotation is identity; D = -world_floor_Z = -94.
|
||||||
|
Assert.True(transition.CollisionInfo.ContactPlaneValid);
|
||||||
|
Assert.Equal(1.0f, transition.CollisionInfo.ContactPlane.Normal.Z, precision: 3);
|
||||||
|
Assert.Equal(-94.0f, transition.CollisionInfo.ContactPlane.D, precision: 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue