feat(app): Phase A.2 — wire frustum culling into terrain + static-mesh renderers
Per-landblock AABB culling against the view frustum. Each loaded landblock has a 192×192 XY footprint + a Z range derived from the terrain vertex min/max (padded +50 above / -10 below for entities on top and basements). One AABB test per landblock per frame; landblocks fully outside the frustum skip ALL their terrain draws and entity draws (both opaque and translucent passes). GpuWorldState gains SetLandblockAabb + LandblockEntries (per-landblock iteration with AABB data). TerrainRenderer.Draw and StaticMeshRenderer.Draw both accept an optional FrustumPlanes and skip culled landblocks. GameWindow.OnRender extracts FrustumPlanes from camera.View * camera.Projection and passes to both. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
07fde88534
commit
3c9fc63af7
4 changed files with 156 additions and 64 deletions
|
|
@ -1189,6 +1189,28 @@ public sealed class GameWindow : IDisposable
|
|||
lb.Heightmap, lbXu, lbYu, _heightTable, _blendCtx, _surfaceCache);
|
||||
_terrain.AddLandblock(lb.LandblockId, meshData, origin);
|
||||
|
||||
// Compute the per-landblock AABB for frustum culling. XY from the
|
||||
// landblock's world origin + 192 footprint. Z from the terrain vertex
|
||||
// range padded +50 above (for trees/buildings) and -10 below (for
|
||||
// basements). TerrainRenderer already scans vertices internally; we
|
||||
// replicate here so GpuWorldState has the same bounds for the static
|
||||
// mesh renderer's culling pass.
|
||||
{
|
||||
float zMin = float.MaxValue, zMax = float.MinValue;
|
||||
foreach (var v in meshData.Vertices)
|
||||
{
|
||||
float z = v.Position.Z;
|
||||
if (z < zMin) zMin = z;
|
||||
if (z > zMax) zMax = z;
|
||||
}
|
||||
if (zMin == float.MaxValue) { zMin = 0f; zMax = 0f; }
|
||||
zMax += 50f; // generous pad for trees and buildings
|
||||
zMin -= 10f; // below-ground buffer for basements/cellars
|
||||
var aabbMin = new System.Numerics.Vector3(origin.X, origin.Y, zMin);
|
||||
var aabbMax = new System.Numerics.Vector3(origin.X + 192f, origin.Y + 192f, zMax);
|
||||
_worldState.SetLandblockAabb(lb.LandblockId, aabbMin, aabbMax);
|
||||
}
|
||||
|
||||
// Upload every GfxObj referenced by this landblock's entities.
|
||||
// EnsureUploaded is idempotent so duplicates across landblocks are free.
|
||||
if (_staticMesh is not null)
|
||||
|
|
@ -1320,8 +1342,10 @@ public sealed class GameWindow : IDisposable
|
|||
|
||||
if (_cameraController is not null)
|
||||
{
|
||||
_terrain?.Draw(_cameraController.Active);
|
||||
_staticMesh?.Draw(_cameraController.Active, _worldState.Entities);
|
||||
var camera = _cameraController.Active;
|
||||
var frustum = AcDream.App.Rendering.FrustumPlanes.FromViewProjection(camera.View * camera.Projection);
|
||||
_terrain?.Draw(camera, frustum);
|
||||
_staticMesh?.Draw(camera, _worldState.LandblockEntries, frustum);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue