perf(physics): reuse reset-complete transition scratch
Mirror retail's ten-deep LIFO transition lifetime, retain all query scratch with complete reset contracts, and remove Tier-0 enum boxing without changing collision decisions. Fresh and retained engines are bit-identical across the expanded oracle, while measured transition profiles now allocate 0 bytes per resolve.
This commit is contained in:
parent
2effba5127
commit
16d182c2f0
19 changed files with 3037 additions and 1228 deletions
|
|
@ -6,7 +6,28 @@ namespace AcDream.Core.Physics;
|
|||
public readonly record struct TerrainSurfacePolygon(
|
||||
float Z,
|
||||
Vector3 Normal,
|
||||
Vector3[] Vertices);
|
||||
TerrainTriangleVertices Vertices);
|
||||
|
||||
/// <summary>
|
||||
/// The terrain surface beneath one point is always exactly one triangle.
|
||||
/// Keeping its three vertices inline avoids allocating two short arrays for
|
||||
/// every transition substep while retaining the same vertex order and floats.
|
||||
/// </summary>
|
||||
public readonly record struct TerrainTriangleVertices(
|
||||
Vector3 V0,
|
||||
Vector3 V1,
|
||||
Vector3 V2)
|
||||
{
|
||||
public int Length => 3;
|
||||
|
||||
public Vector3 this[int index] => index switch
|
||||
{
|
||||
0 => V0,
|
||||
1 => V1,
|
||||
2 => V2,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(index)),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outdoor terrain height resolver for a single landblock. Performs
|
||||
|
|
@ -27,8 +48,8 @@ public sealed class TerrainSurface
|
|||
public const int CellsPerSide = 8; // 192 / 24
|
||||
|
||||
private readonly float[,] _z; // pre-resolved heights [x, y]
|
||||
private readonly bool[,] _cornerIsWater; // per-VERTEX water flag [x, y] — SurfChar[(type >> 2) & 0x1F]
|
||||
private readonly byte[,] _cellWaterType; // per-CELL 0=NotWater, 1=Partially, 2=Entirely [cx, cy]
|
||||
private readonly bool[,] _cornerIsWater; // per-VERTEX water flag [x, y] — SurfChar[(type >> 2) & 0x1F]
|
||||
private readonly byte[,] _cellWaterType; // per-CELL 0=NotWater, 1=Partially, 2=Entirely [cx, cy]
|
||||
private readonly uint _landblockX;
|
||||
private readonly uint _landblockY;
|
||||
|
||||
|
|
@ -49,8 +70,8 @@ public sealed class TerrainSurface
|
|||
// Pre-resolve all 81 heights so SampleZ is a pure lookup + lerp.
|
||||
_z = new float[HeightmapSide, HeightmapSide];
|
||||
for (int x = 0; x < HeightmapSide; x++)
|
||||
for (int y = 0; y < HeightmapSide; y++)
|
||||
_z[x, y] = heightTable[heights[x * HeightmapSide + y]];
|
||||
for (int y = 0; y < HeightmapSide; y++)
|
||||
_z[x, y] = heightTable[heights[x * HeightmapSide + y]];
|
||||
|
||||
// Per-vertex water flag. TerrainType lives in bits 2-6 of each
|
||||
// TerrainInfo byte; water is types 0x10-0x14 inclusive (per
|
||||
|
|
@ -62,11 +83,11 @@ public sealed class TerrainSurface
|
|||
if (terrainTypes is not null && terrainTypes.Length >= 81)
|
||||
{
|
||||
for (int x = 0; x < HeightmapSide; x++)
|
||||
for (int y = 0; y < HeightmapSide; y++)
|
||||
{
|
||||
int typeBits = (terrainTypes[x * HeightmapSide + y] >> 2) & 0x1F;
|
||||
_cornerIsWater[x, y] = typeBits >= 0x10 && typeBits <= 0x14;
|
||||
}
|
||||
for (int y = 0; y < HeightmapSide; y++)
|
||||
{
|
||||
int typeBits = (terrainTypes[x * HeightmapSide + y] >> 2) & 0x1F;
|
||||
_cornerIsWater[x, y] = typeBits >= 0x10 && typeBits <= 0x14;
|
||||
}
|
||||
}
|
||||
|
||||
// Per-cell water classification (mirrors ACE
|
||||
|
|
@ -74,21 +95,21 @@ public sealed class TerrainSurface
|
|||
// vertex corners; count how many are water type.
|
||||
_cellWaterType = new byte[CellsPerSide, CellsPerSide];
|
||||
for (int cx = 0; cx < CellsPerSide; cx++)
|
||||
for (int cy = 0; cy < CellsPerSide; cy++)
|
||||
{
|
||||
int waterCorners = 0;
|
||||
if (_cornerIsWater[cx, cy ]) waterCorners++;
|
||||
if (_cornerIsWater[cx + 1, cy ]) waterCorners++;
|
||||
if (_cornerIsWater[cx + 1, cy + 1]) waterCorners++;
|
||||
if (_cornerIsWater[cx, cy + 1]) waterCorners++;
|
||||
|
||||
_cellWaterType[cx, cy] = waterCorners switch
|
||||
for (int cy = 0; cy < CellsPerSide; cy++)
|
||||
{
|
||||
0 => 0, // NotWater
|
||||
4 => 2, // EntirelyWater
|
||||
_ => 1, // PartiallyWater
|
||||
};
|
||||
}
|
||||
int waterCorners = 0;
|
||||
if (_cornerIsWater[cx, cy]) waterCorners++;
|
||||
if (_cornerIsWater[cx + 1, cy]) waterCorners++;
|
||||
if (_cornerIsWater[cx + 1, cy + 1]) waterCorners++;
|
||||
if (_cornerIsWater[cx, cy + 1]) waterCorners++;
|
||||
|
||||
_cellWaterType[cx, cy] = waterCorners switch
|
||||
{
|
||||
0 => 0, // NotWater
|
||||
4 => 2, // EntirelyWater
|
||||
_ => 1, // PartiallyWater
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -134,10 +155,10 @@ public sealed class TerrainSurface
|
|||
float ty = fy - cy;
|
||||
|
||||
// Four corner heights (BL=SW, BR=SE, TR=NE, TL=NW)
|
||||
float hBL = _z[cx, cy ];
|
||||
float hBR = _z[cx + 1, cy ];
|
||||
float hBL = _z[cx, cy];
|
||||
float hBR = _z[cx + 1, cy];
|
||||
float hTR = _z[cx + 1, cy + 1];
|
||||
float hTL = _z[cx, cy + 1];
|
||||
float hTL = _z[cx, cy + 1];
|
||||
|
||||
// Split direction — same formula as TerrainBlending.CalculateSplitDirection
|
||||
// and ACE's LandblockStruct.ConstructPolygons.
|
||||
|
|
@ -189,10 +210,10 @@ public sealed class TerrainSurface
|
|||
|
||||
// x-major heightmap indexing matches TerrainSurface's pre-resolution
|
||||
// (heights[x * 9 + y]) and ACE LandblockStruct.
|
||||
float hBL = heightTable[heights[cx * HeightmapSide + cy ]];
|
||||
float hBR = heightTable[heights[(cx+1) * HeightmapSide + cy ]];
|
||||
float hTR = heightTable[heights[(cx+1) * HeightmapSide + (cy+1)]];
|
||||
float hTL = heightTable[heights[cx * HeightmapSide + (cy+1)]];
|
||||
float hBL = heightTable[heights[cx * HeightmapSide + cy]];
|
||||
float hBR = heightTable[heights[(cx + 1) * HeightmapSide + cy]];
|
||||
float hTR = heightTable[heights[(cx + 1) * HeightmapSide + (cy + 1)]];
|
||||
float hTL = heightTable[heights[cx * HeightmapSide + (cy + 1)]];
|
||||
|
||||
bool splitSWtoNE = IsSplitSWtoNE(landblockX, (uint)cx, landblockY, (uint)cy);
|
||||
return InterpolateZInTriangle(hBL, hBR, hTR, hTL, tx, ty, splitSWtoNE);
|
||||
|
|
@ -227,10 +248,10 @@ public sealed class TerrainSurface
|
|||
float tx = fx - cx;
|
||||
float ty = fy - cy;
|
||||
|
||||
float hBL = heightTable[heights[cx * HeightmapSide + cy ]];
|
||||
float hBR = heightTable[heights[(cx+1) * HeightmapSide + cy ]];
|
||||
float hTR = heightTable[heights[(cx+1) * HeightmapSide + (cy+1)]];
|
||||
float hTL = heightTable[heights[cx * HeightmapSide + (cy+1)]];
|
||||
float hBL = heightTable[heights[cx * HeightmapSide + cy]];
|
||||
float hBR = heightTable[heights[(cx + 1) * HeightmapSide + cy]];
|
||||
float hTR = heightTable[heights[(cx + 1) * HeightmapSide + (cy + 1)]];
|
||||
float hTL = heightTable[heights[cx * HeightmapSide + (cy + 1)]];
|
||||
|
||||
bool splitSWtoNE = IsSplitSWtoNE(landblockX, (uint)cx, landblockY, (uint)cy);
|
||||
|
||||
|
|
@ -332,10 +353,10 @@ public sealed class TerrainSurface
|
|||
float tx = fx - cx;
|
||||
float ty = fy - cy;
|
||||
|
||||
float hBL = _z[cx, cy ];
|
||||
float hBR = _z[cx + 1, cy ];
|
||||
float hBL = _z[cx, cy];
|
||||
float hBR = _z[cx + 1, cy];
|
||||
float hTR = _z[cx + 1, cy + 1];
|
||||
float hTL = _z[cx, cy + 1];
|
||||
float hTL = _z[cx, cy + 1];
|
||||
|
||||
bool splitSWtoNE = IsSplitSWtoNE(_landblockX, (uint)cx, _landblockY, (uint)cy);
|
||||
|
||||
|
|
@ -352,14 +373,14 @@ public sealed class TerrainSurface
|
|||
if (tx > ty)
|
||||
{
|
||||
// {BL,BR,TR}: Z = hBL + (hBR-hBL)·tx + (hTR-hBR)·ty
|
||||
z = hBL + (hBR - hBL) * tx + (hTR - hBR) * ty;
|
||||
z = hBL + (hBR - hBL) * tx + (hTR - hBR) * ty;
|
||||
dzdx = (hBR - hBL) / CellSize;
|
||||
dzdy = (hTR - hBR) / CellSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// {BL,TR,TL}: Z = hBL + (hTR-hTL)·tx + (hTL-hBL)·ty
|
||||
z = hBL + (hTR - hTL) * tx + (hTL - hBL) * ty;
|
||||
z = hBL + (hTR - hTL) * tx + (hTL - hBL) * ty;
|
||||
dzdx = (hTR - hTL) / CellSize;
|
||||
dzdy = (hTL - hBL) / CellSize;
|
||||
}
|
||||
|
|
@ -370,7 +391,7 @@ public sealed class TerrainSurface
|
|||
if (tx + ty <= 1f)
|
||||
{
|
||||
// {BL,BR,TL}: Z = hBL + (hBR-hBL)·tx + (hTL-hBL)·ty
|
||||
z = hBL + (hBR - hBL) * tx + (hTL - hBL) * ty;
|
||||
z = hBL + (hBR - hBL) * tx + (hTL - hBL) * ty;
|
||||
dzdx = (hBR - hBL) / CellSize;
|
||||
dzdy = (hTL - hBL) / CellSize;
|
||||
}
|
||||
|
|
@ -378,7 +399,7 @@ public sealed class TerrainSurface
|
|||
{
|
||||
// {BR,TR,TL}: Z = hTR + (hTL-hTR)(1-tx) + (hBR-hTR)(1-ty)
|
||||
// Equivalent linear form: Z = [hBR+hTL-hTR] + (hTR-hTL)·tx + (hTR-hBR)·ty
|
||||
z = hTR + (hTL - hTR) * (1f - tx) + (hBR - hTR) * (1f - ty);
|
||||
z = hTR + (hTL - hTR) * (1f - tx) + (hBR - hTR) * (1f - ty);
|
||||
dzdx = (hTR - hTL) / CellSize;
|
||||
dzdy = (hTR - hBR) / CellSize;
|
||||
}
|
||||
|
|
@ -405,32 +426,32 @@ public sealed class TerrainSurface
|
|||
float tx = fx - cx;
|
||||
float ty = fy - cy;
|
||||
|
||||
float hBL = _z[cx, cy ];
|
||||
float hBR = _z[cx + 1, cy ];
|
||||
float hBL = _z[cx, cy];
|
||||
float hBR = _z[cx + 1, cy];
|
||||
float hTR = _z[cx + 1, cy + 1];
|
||||
float hTL = _z[cx, cy + 1];
|
||||
float hTL = _z[cx, cy + 1];
|
||||
|
||||
bool splitSWtoNE = IsSplitSWtoNE(_landblockX, (uint)cx, _landblockY, (uint)cy);
|
||||
|
||||
Vector3 bl = new(cx * CellSize, cy * CellSize, hBL);
|
||||
Vector3 br = new((cx + 1) * CellSize, cy * CellSize, hBR);
|
||||
Vector3 bl = new(cx * CellSize, cy * CellSize, hBL);
|
||||
Vector3 br = new((cx + 1) * CellSize, cy * CellSize, hBR);
|
||||
Vector3 tr = new((cx + 1) * CellSize, (cy + 1) * CellSize, hTR);
|
||||
Vector3 tl = new(cx * CellSize, (cy + 1) * CellSize, hTL);
|
||||
Vector3 tl = new(cx * CellSize, (cy + 1) * CellSize, hTL);
|
||||
|
||||
float z;
|
||||
Vector3[] vertices;
|
||||
TerrainTriangleVertices vertices;
|
||||
|
||||
if (splitSWtoNE)
|
||||
{
|
||||
if (tx > ty)
|
||||
{
|
||||
z = hBL + (hBR - hBL) * tx + (hTR - hBR) * ty;
|
||||
vertices = new[] { bl, br, tr };
|
||||
vertices = new TerrainTriangleVertices(bl, br, tr);
|
||||
}
|
||||
else
|
||||
{
|
||||
z = hBL + (hTR - hTL) * tx + (hTL - hBL) * ty;
|
||||
vertices = new[] { bl, tr, tl };
|
||||
vertices = new TerrainTriangleVertices(bl, tr, tl);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -438,12 +459,12 @@ public sealed class TerrainSurface
|
|||
if (tx + ty <= 1f)
|
||||
{
|
||||
z = hBL + (hBR - hBL) * tx + (hTL - hBL) * ty;
|
||||
vertices = new[] { bl, br, tl };
|
||||
vertices = new TerrainTriangleVertices(bl, br, tl);
|
||||
}
|
||||
else
|
||||
{
|
||||
z = hTR + (hTL - hTR) * (1f - tx) + (hBR - hTR) * (1f - ty);
|
||||
vertices = new[] { br, tr, tl };
|
||||
vertices = new TerrainTriangleVertices(br, tr, tl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue