fix(physics): traverse prepared indoor portal topology
This commit is contained in:
parent
b12d94047c
commit
4d095be286
9 changed files with 400 additions and 5 deletions
|
|
@ -101,12 +101,21 @@ public static class CellTransit
|
|||
uint lbPrefix = currentCellId & 0xFFFF0000u;
|
||||
int sphereCount = EffectiveSphereCount(worldSpheres, numSpheres);
|
||||
|
||||
if (currentCell.PortalPolygons is null || sphereCount == 0) return;
|
||||
if (sphereCount == 0) return;
|
||||
|
||||
foreach (var portal in currentCell.Portals)
|
||||
for (int portalIndex = 0;
|
||||
portalIndex < currentCell.Portals.Count;
|
||||
portalIndex++)
|
||||
{
|
||||
if (!currentCell.PortalPolygons.TryGetValue(portal.PolygonId, out var poly))
|
||||
PortalInfo portal = currentCell.Portals[portalIndex];
|
||||
if (!TryGetPortalPlane(
|
||||
currentCell,
|
||||
portalIndex,
|
||||
portal,
|
||||
out Plane portalPlane))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (portal.OtherCellId == 0xFFFF)
|
||||
{
|
||||
|
|
@ -142,7 +151,9 @@ public static class CellTransit
|
|||
float pad = sphere.Radius + FEpsilon;
|
||||
var localCenter = Vector3.Transform(
|
||||
sphere.Origin, currentCell.InverseWorldTransform);
|
||||
float dist = Vector3.Dot(localCenter, poly.Plane.Normal) + poly.Plane.D;
|
||||
float dist =
|
||||
Vector3.Dot(localCenter, portalPlane.Normal) +
|
||||
portalPlane.D;
|
||||
if (dist > -pad && dist < pad)
|
||||
{
|
||||
exitOutside = true;
|
||||
|
|
@ -190,7 +201,9 @@ public static class CellTransit
|
|||
float rad = sphere.Radius + EPSILON;
|
||||
var localCenter = Vector3.Transform(
|
||||
sphere.Origin, currentCell.InverseWorldTransform);
|
||||
float dist = Vector3.Dot(localCenter, poly.Plane.Normal) + poly.Plane.D;
|
||||
float dist =
|
||||
Vector3.Dot(localCenter, portalPlane.Normal) +
|
||||
portalPlane.D;
|
||||
bool hit = portal.PortalSide ? dist > -rad : dist < rad;
|
||||
if (hit)
|
||||
{
|
||||
|
|
@ -201,6 +214,64 @@ public static class CellTransit
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the portal plane from whichever immutable representation owns
|
||||
/// this cell. Graph fixtures retain the DAT polygon dictionary; production
|
||||
/// cells intentionally retain only the prepared topology's direct polygon
|
||||
/// index and flat polygon table.
|
||||
/// </summary>
|
||||
private static bool TryGetPortalPlane(
|
||||
CellPhysics cell,
|
||||
int portalIndex,
|
||||
PortalInfo portal,
|
||||
out Plane plane)
|
||||
{
|
||||
if (cell.PortalPolygons is not null &&
|
||||
cell.PortalPolygons.TryGetValue(
|
||||
portal.PolygonId,
|
||||
out ResolvedPolygon? polygon))
|
||||
{
|
||||
plane = polygon.Plane;
|
||||
return true;
|
||||
}
|
||||
|
||||
FlatEnvCellTopology? topology = cell.FlatTopology;
|
||||
FlatPolygonTable? polygonTable = cell.FlatPortalPolygons;
|
||||
if (topology is null || polygonTable is null)
|
||||
{
|
||||
plane = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((uint)portalIndex >= (uint)topology.Portals.Length)
|
||||
{
|
||||
throw new InvalidDataException(
|
||||
$"Cell 0x{cell.SourceId:X8} portal {portalIndex} is absent " +
|
||||
"from its prepared topology.");
|
||||
}
|
||||
|
||||
FlatEnvCellPortal flatPortal = topology.Portals[portalIndex];
|
||||
if (flatPortal.OtherCellId != portal.OtherCellId ||
|
||||
flatPortal.PolygonId != portal.PolygonId ||
|
||||
flatPortal.Flags != portal.Flags)
|
||||
{
|
||||
throw new InvalidDataException(
|
||||
$"Cell 0x{cell.SourceId:X8} portal {portalIndex} does not " +
|
||||
"match its prepared topology.");
|
||||
}
|
||||
|
||||
int polygonIndex = flatPortal.PolygonIndex;
|
||||
if ((uint)polygonIndex >= (uint)polygonTable.Polygons.Length)
|
||||
{
|
||||
throw new InvalidDataException(
|
||||
$"Cell 0x{cell.SourceId:X8} portal {portalIndex} references " +
|
||||
$"invalid prepared polygon index {polygonIndex}.");
|
||||
}
|
||||
|
||||
plane = polygonTable.Polygons[polygonIndex].Plane;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outdoor neighbour expansion. Ported from
|
||||
/// <c>CLandCell::add_all_outside_cells</c> (sphere variant,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue