feat(render): Phase 3 (Task 2) — build the outdoor node each frame (additive, unconsumed)
Builds the synthetic outdoor cell node (OutdoorCellNode.Build) every outdoor frame from the nearby building-entrance portals (Chebyshev <=1 landblocks), stored in _outdoorNode. NOT yet rooted — clipRoot/viewerRoot unchanged, so behaviour is identical this commit. [outdoor-node] probe (ACDREAM_PROBE_FLAP) reports the live portal count so the next (cutover) step can confirm real building entrances were found before flipping the render root. App.Tests 214/214, build green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1e9485532f
commit
d01fe30ac0
1 changed files with 41 additions and 0 deletions
|
|
@ -184,6 +184,14 @@ public sealed class GameWindow : IDisposable
|
||||||
private readonly HashSet<uint> _outdoorRootNoCells = new(0);
|
private readonly HashSet<uint> _outdoorRootNoCells = new(0);
|
||||||
private readonly HashSet<uint> _exteriorPortalLandblocks = new();
|
private readonly HashSet<uint> _exteriorPortalLandblocks = new();
|
||||||
private readonly List<LoadedCell> _exteriorPortalCandidateCells = new();
|
private readonly List<LoadedCell> _exteriorPortalCandidateCells = new();
|
||||||
|
|
||||||
|
// Phase 3 (render unification, 2026-06-07): the synthetic outdoor cell node — the outdoor
|
||||||
|
// world as a flood-graph cell (spec 2026-06-07-render-unification-outdoor-as-cell). Rebuilt
|
||||||
|
// each outdoor frame from nearby building-entrance portals. ADDITIVE for now (built but not
|
||||||
|
// yet rooted; the clipRoot flip + OutsideView terrain integration is the cutover step).
|
||||||
|
private LoadedCell? _outdoorNode;
|
||||||
|
private readonly List<LoadedCell> _outdoorNodeBuildingCells = new();
|
||||||
|
private readonly HashSet<uint> _outdoorNodeSeenLbs = new();
|
||||||
private readonly HashSet<uint> _outdoorSceneParticleEntityIds = new();
|
private readonly HashSet<uint> _outdoorSceneParticleEntityIds = new();
|
||||||
private readonly HashSet<uint> _visibleSceneParticleEntityIds = new();
|
private readonly HashSet<uint> _visibleSceneParticleEntityIds = new();
|
||||||
private string? _lastRenderSignature;
|
private string? _lastRenderSignature;
|
||||||
|
|
@ -7339,6 +7347,39 @@ public sealed class GameWindow : IDisposable
|
||||||
// (mesh SSBO) + binding=2 (terrain UBO); each renderer re-binds its
|
// (mesh SSBO) + binding=2 (terrain UBO); each renderer re-binds its
|
||||||
// binding=2 defensively from the ids we hand it.
|
// binding=2 defensively from the ids we hand it.
|
||||||
_clipFrame ??= ClipFrame.NoClip();
|
_clipFrame ??= ClipFrame.NoClip();
|
||||||
|
|
||||||
|
// Phase 3 (render unification, additive): build the synthetic outdoor cell node when
|
||||||
|
// the eye is outdoors (no interior viewerRoot). Stored in _outdoorNode but NOT yet
|
||||||
|
// rooted — behaviour is unchanged this commit. The nearby-building enumeration mirrors
|
||||||
|
// the look-in candidate gather in the OUTDOOR branch below (Chebyshev <=1 landblocks);
|
||||||
|
// OutdoorCellNode.Build filters to exit portals internally. The clipRoot flip +
|
||||||
|
// OutsideView terrain integration that consumes this is the next (cutover) step.
|
||||||
|
_outdoorNode = null;
|
||||||
|
if (viewerRoot is null && viewerCellId != 0u)
|
||||||
|
{
|
||||||
|
_outdoorNodeBuildingCells.Clear();
|
||||||
|
_outdoorNodeSeenLbs.Clear();
|
||||||
|
int onGridX = playerLb.HasValue ? (int)((playerLb.Value >> 24) & 0xFFu) : -1;
|
||||||
|
int onGridY = playerLb.HasValue ? (int)((playerLb.Value >> 16) & 0xFFu) : -1;
|
||||||
|
foreach (var onEntry in _worldState.LandblockEntries)
|
||||||
|
{
|
||||||
|
uint onLb = (onEntry.LandblockId >> 16) & 0xFFFFu;
|
||||||
|
if (playerLb.HasValue)
|
||||||
|
{
|
||||||
|
int gX = (int)((onLb >> 8) & 0xFFu);
|
||||||
|
int gY = (int)(onLb & 0xFFu);
|
||||||
|
if (Math.Max(Math.Abs(gX - onGridX), Math.Abs(gY - onGridY)) > 1) continue;
|
||||||
|
}
|
||||||
|
if (!_outdoorNodeSeenLbs.Add(onLb)) continue;
|
||||||
|
foreach (var onCell in _cellVisibility.GetCellsForLandblock(onLb))
|
||||||
|
_outdoorNodeBuildingCells.Add(onCell);
|
||||||
|
}
|
||||||
|
_outdoorNode = AcDream.App.Rendering.OutdoorCellNode.Build(viewerCellId, _outdoorNodeBuildingCells);
|
||||||
|
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeFlapEnabled)
|
||||||
|
Console.WriteLine(System.FormattableString.Invariant(
|
||||||
|
$"[outdoor-node] cell=0x{viewerCellId:X8} nearbyCells={_outdoorNodeBuildingCells.Count} portals={_outdoorNode.Portals.Count}"));
|
||||||
|
}
|
||||||
|
|
||||||
uint playerCellId = _physicsEngine.DataCache?.CellGraph.CurrCell?.Id ?? 0u;
|
uint playerCellId = _physicsEngine.DataCache?.CellGraph.CurrCell?.Id ?? 0u;
|
||||||
bool playerIndoorGate = AcDream.Core.Rendering.RenderingDiagnostics.ShouldRenderIndoor(
|
bool playerIndoorGate = AcDream.Core.Rendering.RenderingDiagnostics.ShouldRenderIndoor(
|
||||||
playerCellId,
|
playerCellId,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue