feat(render) Campaign FW1: the landscape replay world + first outdoor diff
WalkLandscapeDatBuilder assembles the replay grid with the LIVE-dumped retail landscape model (LScape mid_radius=25 -> 51x51; the resolution pyramid observed on the capture client: side_cell_count 8 in the 3x3 core, 4 at ring 2, 2 at rings 3-4, 1 beyond; buildings attach only to full-res blocks - matching the traces roster), retail z-slabs (heightTable[max]+200 / [min]-1 per CLandBlock unpack @0052f297), and camera-block-local coordinates. The replay context gains the building half (placements, active-view install, building-polygon clip). The street-outdoor conformance diff now reaches real adjudication: the walk over-culls six traced buildings (jagged boundary - not a clean frustum edge) and the look-in floods differ; the driving test is parked Skip while the visibility map is instrumented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e8df809c40
commit
e3f0c6a1a1
5 changed files with 222 additions and 21 deletions
|
|
@ -32,7 +32,14 @@ using AcDream.App.Rendering.Walk;
|
|||
/// </summary>
|
||||
public static class WalkWorldDatAdapter
|
||||
{
|
||||
/// <summary>One built building plus its landblock-local placement.</summary>
|
||||
public sealed record BuildingEntry(
|
||||
WalkBuilding Building, Matrix4x4 WorldTransform, Matrix4x4 InverseWorldTransform);
|
||||
|
||||
public static WalkCell? BuildCell(DatCollection dats, uint cellId)
|
||||
=> BuildCell(dats, cellId, Vector3.Zero);
|
||||
|
||||
public static WalkCell? BuildCell(DatCollection dats, uint cellId, Vector3 blockOffset)
|
||||
{
|
||||
if (dats.Get<EnvCell>(cellId) is not EnvCell envCell)
|
||||
return null;
|
||||
|
|
@ -67,9 +74,9 @@ public static class WalkWorldDatAdapter
|
|||
Matrix4x4 worldTransform =
|
||||
Matrix4x4.CreateFromQuaternion(envCell.Position.Orientation)
|
||||
* Matrix4x4.CreateTranslation(
|
||||
envCell.Position.Origin.X,
|
||||
envCell.Position.Origin.Y,
|
||||
envCell.Position.Origin.Z);
|
||||
envCell.Position.Origin.X + blockOffset.X,
|
||||
envCell.Position.Origin.Y + blockOffset.Y,
|
||||
envCell.Position.Origin.Z + blockOffset.Z);
|
||||
Matrix4x4.Invert(worldTransform, out Matrix4x4 inverse);
|
||||
return new WalkCell
|
||||
{
|
||||
|
|
@ -84,12 +91,17 @@ public static class WalkWorldDatAdapter
|
|||
|
||||
public static Dictionary<uint, WalkCell> BuildInteriorCells(
|
||||
DatCollection dats, uint landblockId)
|
||||
=> BuildInteriorCells(dats, landblockId, Vector3.Zero, null);
|
||||
|
||||
public static Dictionary<uint, WalkCell> BuildInteriorCells(
|
||||
DatCollection dats, uint landblockId, Vector3 blockOffset,
|
||||
Dictionary<uint, WalkCell>? into)
|
||||
{
|
||||
uint lbMask = landblockId & 0xFFFF0000u;
|
||||
var cells = new Dictionary<uint, WalkCell>();
|
||||
Dictionary<uint, WalkCell> cells = into ?? new Dictionary<uint, WalkCell>();
|
||||
for (uint low = 0x0100; low <= 0xFFFD; low++)
|
||||
{
|
||||
WalkCell? cell = BuildCell(dats, lbMask | low);
|
||||
WalkCell? cell = BuildCell(dats, lbMask | low, blockOffset);
|
||||
if (cell is null) break; // interior cells are contiguous from 0x0100
|
||||
cells[cell.CellId] = cell;
|
||||
}
|
||||
|
|
@ -97,11 +109,12 @@ public static class WalkWorldDatAdapter
|
|||
}
|
||||
|
||||
/// <summary>Buildings of one landblock, with their walk event ids
|
||||
/// (containing landcell), portal records, and drawing-BSP portal trees.</summary>
|
||||
public static List<WalkBuilding> BuildBuildings(DatCollection dats, uint landblockId)
|
||||
/// (containing landcell), portal records, drawing-BSP portal trees, and
|
||||
/// landblock-local placements.</summary>
|
||||
public static List<BuildingEntry> BuildBuildings(DatCollection dats, uint landblockId)
|
||||
{
|
||||
uint lbMask = landblockId & 0xFFFF0000u;
|
||||
var result = new List<WalkBuilding>();
|
||||
var result = new List<BuildingEntry>();
|
||||
if (dats.Get<LandBlockInfo>(lbMask | 0xFFFEu) is not LandBlockInfo info
|
||||
|| info.Buildings is null)
|
||||
{
|
||||
|
|
@ -138,12 +151,19 @@ public static class WalkWorldDatAdapter
|
|||
if (dats.Get<GfxObj>(buildingInfo.ModelId) is GfxObj gfxObj)
|
||||
bsp = ConvertDrawingBsp(gfxObj, gfxObj.DrawingBSP?.Root);
|
||||
|
||||
result.Add(new WalkBuilding
|
||||
{
|
||||
PositionCellId = positionCellId,
|
||||
Portals = portals,
|
||||
DrawingBsp = bsp,
|
||||
});
|
||||
Matrix4x4 worldTransform =
|
||||
Matrix4x4.CreateFromQuaternion(buildingInfo.Frame.Orientation)
|
||||
* Matrix4x4.CreateTranslation(origin);
|
||||
Matrix4x4.Invert(worldTransform, out Matrix4x4 inverse);
|
||||
result.Add(new BuildingEntry(
|
||||
new WalkBuilding
|
||||
{
|
||||
PositionCellId = positionCellId,
|
||||
Portals = portals,
|
||||
DrawingBsp = bsp,
|
||||
},
|
||||
worldTransform,
|
||||
inverse));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue