refactor(render): cull terrain by walk in-view cells
This commit is contained in:
parent
98d2d43fdc
commit
837a33baff
3 changed files with 54 additions and 14 deletions
|
|
@ -10,6 +10,11 @@ namespace AcDream.App.Rendering;
|
||||||
/// methods — the cutover changes ORDER only.</summary>
|
/// methods — the cutover changes ORDER only.</summary>
|
||||||
internal sealed partial class RetailPViewPassExecutor
|
internal sealed partial class RetailPViewPassExecutor
|
||||||
{
|
{
|
||||||
|
private IReadOnlySet<uint>? _walkTerrainInViewLandcells;
|
||||||
|
|
||||||
|
internal void SetWalkTerrainInViewLandcells(IReadOnlySet<uint>? cells) =>
|
||||||
|
_walkTerrainInViewLandcells = cells;
|
||||||
|
|
||||||
/// <summary>The walk's single sky turn: retail draws GameSky once
|
/// <summary>The walk's single sky turn: retail draws GameSky once
|
||||||
/// inside <c>LScape::draw</c>, clipped by the active views; looping
|
/// inside <c>LScape::draw</c>, clipped by the active views; looping
|
||||||
/// today's per-slice scissor + terrain-clip block reproduces today's
|
/// today's per-slice scissor + terrain-clip block reproduces today's
|
||||||
|
|
@ -105,7 +110,8 @@ internal sealed partial class RetailPViewPassExecutor
|
||||||
frame.Frustum,
|
frame.Frustum,
|
||||||
neverCullLandblockId: frame.PlayerLandblockId,
|
neverCullLandblockId: frame.PlayerLandblockId,
|
||||||
clipPlanes: default,
|
clipPlanes: default,
|
||||||
ndcClipAabb: new Vector4(-1f, -1f, 1f, 1f));
|
ndcClipAabb: new Vector4(-1f, -1f, 1f, 1f),
|
||||||
|
inViewLandcells: _walkTerrainInViewLandcells);
|
||||||
_terrainDiagnostics.Complete();
|
_terrainDiagnostics.Complete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -120,7 +126,8 @@ internal sealed partial class RetailPViewPassExecutor
|
||||||
frame.Frustum,
|
frame.Frustum,
|
||||||
neverCullLandblockId: frame.PlayerLandblockId,
|
neverCullLandblockId: frame.PlayerLandblockId,
|
||||||
clipPlanes: slice.Planes,
|
clipPlanes: slice.Planes,
|
||||||
ndcClipAabb: slice.NdcAabb);
|
ndcClipAabb: slice.NdcAabb,
|
||||||
|
inViewLandcells: _walkTerrainInViewLandcells);
|
||||||
_terrainDiagnostics.Complete();
|
_terrainDiagnostics.Complete();
|
||||||
DisableClipDistances();
|
DisableClipDistances();
|
||||||
if (scissor)
|
if (scissor)
|
||||||
|
|
|
||||||
|
|
@ -1349,7 +1349,15 @@ public sealed class RetailPViewRenderer
|
||||||
Walk.WalkFrameDriver driver)
|
Walk.WalkFrameDriver driver)
|
||||||
{
|
{
|
||||||
var (frame, encoder) = passes.RequireWalkSubmission();
|
var (frame, encoder) = passes.RequireWalkSubmission();
|
||||||
|
passes.SetWalkTerrainInViewLandcells(driver.VisitedLandscapeCellIds);
|
||||||
|
try
|
||||||
|
{
|
||||||
driver.Replay(frame, encoder);
|
driver.Replay(frame, encoder);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
passes.SetWalkTerrainInViewLandcells(null);
|
||||||
|
}
|
||||||
|
|
||||||
// Landscape-stage static-owner particles (candles, the cathedral
|
// Landscape-stage static-owner particles (candles, the cathedral
|
||||||
// falls) submit AT THEIR OWN WALK TURNS inside Replay
|
// falls) submit AT THEIR OWN WALK TURNS inside Replay
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ public sealed partial class TerrainModernRenderer : IDisposable
|
||||||
// Reusable per-frame buffers.
|
// Reusable per-frame buffers.
|
||||||
private readonly List<int> _visibleSlots = new();
|
private readonly List<int> _visibleSlots = new();
|
||||||
private readonly HashSet<uint> _visibleCellIds = new();
|
private readonly HashSet<uint> _visibleCellIds = new();
|
||||||
|
private readonly HashSet<uint> _walkVisibleLandblocks = new();
|
||||||
private DrawElementsIndirectCommand[] _deicScratch = Array.Empty<DrawElementsIndirectCommand>();
|
private DrawElementsIndirectCommand[] _deicScratch = Array.Empty<DrawElementsIndirectCommand>();
|
||||||
|
|
||||||
// Diag.
|
// Diag.
|
||||||
|
|
@ -204,24 +205,47 @@ public sealed partial class TerrainModernRenderer : IDisposable
|
||||||
FrustumPlanes? frustum = null,
|
FrustumPlanes? frustum = null,
|
||||||
uint? neverCullLandblockId = null,
|
uint? neverCullLandblockId = null,
|
||||||
ReadOnlySpan<Vector4> clipPlanes = default,
|
ReadOnlySpan<Vector4> clipPlanes = default,
|
||||||
Vector4? ndcClipAabb = null)
|
Vector4? ndcClipAabb = null,
|
||||||
|
IReadOnlySet<uint>? inViewLandcells = null)
|
||||||
{
|
{
|
||||||
if (_alloc.LoadedCount == 0) return;
|
if (_alloc.LoadedCount == 0) return;
|
||||||
|
|
||||||
Matrix4x4 viewProjection = camera.View * camera.Projection;
|
Matrix4x4 viewProjection = camera.View * camera.Projection;
|
||||||
|
|
||||||
|
// Campaign FW4: RetailFrameWalk is the sole visibility authority.
|
||||||
|
// Terrain remains one full-landblock MDI draw, but only landblocks
|
||||||
|
// containing a walk-admitted landcell participate, and the published
|
||||||
|
// landcell set is the walk's exact in_view set rather than a second
|
||||||
|
// frustum-derived approximation.
|
||||||
|
_walkVisibleLandblocks.Clear();
|
||||||
|
if (inViewLandcells is not null)
|
||||||
|
{
|
||||||
|
foreach (uint cellId in inViewLandcells)
|
||||||
|
{
|
||||||
|
_walkVisibleLandblocks.Add(cellId & 0xFFFF0000u);
|
||||||
|
_visibleCellIds.Add(cellId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build visible slot list with per-slot frustum cull.
|
// Build visible slot list with per-slot frustum cull.
|
||||||
_visibleSlots.Clear();
|
_visibleSlots.Clear();
|
||||||
for (int slot = 0; slot < _slots.Length; slot++)
|
for (int slot = 0; slot < _slots.Length; slot++)
|
||||||
{
|
{
|
||||||
var data = _slots[slot];
|
var data = _slots[slot];
|
||||||
if (data is null) continue;
|
if (data is null) continue;
|
||||||
|
if (inViewLandcells is not null
|
||||||
|
&& !_walkVisibleLandblocks.Contains(data.LandblockId & 0xFFFF0000u))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (frustum is not null && data.LandblockId != neverCullLandblockId)
|
if (frustum is not null && data.LandblockId != neverCullLandblockId)
|
||||||
{
|
{
|
||||||
if (!FrustumCuller.IsAabbVisible(frustum.Value, data.AabbMin, data.AabbMax))
|
if (!FrustumCuller.IsAabbVisible(frustum.Value, data.AabbMin, data.AabbMax))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_visibleSlots.Add(slot);
|
_visibleSlots.Add(slot);
|
||||||
|
if (inViewLandcells is null)
|
||||||
|
{
|
||||||
CollectVisibleCells(
|
CollectVisibleCells(
|
||||||
_visibleCellIds,
|
_visibleCellIds,
|
||||||
data.LandblockId,
|
data.LandblockId,
|
||||||
|
|
@ -233,6 +257,7 @@ public sealed partial class TerrainModernRenderer : IDisposable
|
||||||
clipPlanes,
|
clipPlanes,
|
||||||
ndcClipAabb);
|
ndcClipAabb);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (_visibleSlots.Count == 0) return;
|
if (_visibleSlots.Count == 0) return;
|
||||||
|
|
||||||
BuildIndirectCommands();
|
BuildIndirectCommands();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue