fix(render): FW4 slice 1 - interior outside-view slices come from the walk
The FW3 visual gate's stairwell/grass transition flash (grass briefly covering floor openings at doorway crossings - the #119 family) was the FW3 dual path leaking: the walk decided WHETHER terrain draws while the old PortalVisibilityBuilder assembly decided WHERE (slice planes, count, scissor), and punch fans indexed the old slice array with walk view indices. The new ACDREAM_PROBE_WALK_ROOT apparatus pinned the boundary frames: fat/degenerate old-apparatus exit views splash terrain over interior pixels, the interior depth-clear preserves color, and cells absent from the walk's flood never repaint. Retail has ONE visibility structure and cannot produce this. ClipFrameAssembler.ReassembleOutsideViewFromWalk now materializes the walk's own outside_view (pixel screen points -> standard NDC -> the existing ClipPlaneSet machinery) into the assembly's outside-view block after Collect, ahead of the single PrepareClipFrame publication (moved below the walk block). The Landscape event carries the walk's active view count on the record's existing OutsideViewCount field (trace mapping compares kind only - zero oracle-fixture churn) and the driver fans exactly that many terrain slices; activeTerrainSliceCount is deleted end to end. Outdoor roots keep the assembler's single full-screen slice, asserted ==1. Hermetic 6,762/0 (4 new materializer tests pin the y-flip and plane-sign conventions), Walk lane 209/1, InstalledDat walk conformance 40/1. Seals/cell slices/look-in seeding stay on the old per-cell views for the rest of FW4 (identical dat polygons; only the visible set can differ). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8f8b0b9c57
commit
37febd1fe6
11 changed files with 468 additions and 44 deletions
|
|
@ -395,7 +395,6 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
private IWalkBuildingFrameContext? _ctx;
|
||||
private Matrix4x4 _viewProjection;
|
||||
private Vector3 _cameraWorldPosition;
|
||||
private int _activeTerrainSliceCount;
|
||||
private bool _skyDrawnThisFrame;
|
||||
private WalkDrawStage? _currentDcStage;
|
||||
private bool _readyToReplay;
|
||||
|
|
@ -429,15 +428,14 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
IGpuFrame frame,
|
||||
IGpuPassEncoder encoder,
|
||||
Matrix4x4 viewProjection,
|
||||
Vector3 cameraWorldPosition,
|
||||
int activeTerrainSliceCount = 1)
|
||||
Vector3 cameraWorldPosition)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(frame);
|
||||
ArgumentNullException.ThrowIfNull(encoder);
|
||||
|
||||
Collect(
|
||||
walk, cameraCellId, cameraCell, landscape, ctx,
|
||||
viewProjection, cameraWorldPosition, activeTerrainSliceCount);
|
||||
viewProjection, cameraWorldPosition);
|
||||
Replay(frame, encoder);
|
||||
}
|
||||
|
||||
|
|
@ -454,14 +452,13 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
WalkLandscape landscape,
|
||||
IRetailFrameWalkContext ctx,
|
||||
Matrix4x4 viewProjection,
|
||||
Vector3 cameraWorldPosition,
|
||||
int activeTerrainSliceCount)
|
||||
Vector3 cameraWorldPosition)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(walk);
|
||||
ArgumentNullException.ThrowIfNull(landscape);
|
||||
ArgumentNullException.ThrowIfNull(ctx);
|
||||
|
||||
BeginFrame(ctx, viewProjection, cameraWorldPosition, activeTerrainSliceCount);
|
||||
BeginFrame(ctx, viewProjection, cameraWorldPosition);
|
||||
walk.WalkFrame(cameraCellId, cameraCell, landscape, ctx, this);
|
||||
EndFrame();
|
||||
}
|
||||
|
|
@ -478,16 +475,9 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
internal void BeginFrame(
|
||||
IWalkBuildingFrameContext ctx,
|
||||
Matrix4x4 viewProjection,
|
||||
Vector3 cameraWorldPosition,
|
||||
int activeTerrainSliceCount)
|
||||
Vector3 cameraWorldPosition)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(ctx);
|
||||
if (activeTerrainSliceCount < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(activeTerrainSliceCount), activeTerrainSliceCount,
|
||||
"The active terrain slice count cannot be negative.");
|
||||
}
|
||||
if (_ctx is not null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
|
|
@ -499,7 +489,6 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
_ctx = ctx;
|
||||
_viewProjection = viewProjection;
|
||||
_cameraWorldPosition = cameraWorldPosition;
|
||||
_activeTerrainSliceCount = activeTerrainSliceCount;
|
||||
_skyDrawnThisFrame = false;
|
||||
_currentDcStage = null;
|
||||
_readyToReplay = false;
|
||||
|
|
@ -616,7 +605,7 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
VisitedCells.Add(walkEvent.CellId);
|
||||
break;
|
||||
case WalkEventKind.Landscape:
|
||||
HandleLandscapeTurn();
|
||||
HandleLandscapeTurn(walkEvent.OutsideViewCount);
|
||||
break;
|
||||
case WalkEventKind.DrawCells:
|
||||
foreach (uint id in walkEvent.Cells)
|
||||
|
|
@ -710,9 +699,18 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
// Turn handlers
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
private void HandleLandscapeTurn()
|
||||
private void HandleLandscapeTurn(int activeViewCount)
|
||||
{
|
||||
RequireOpenFrame();
|
||||
if (activeViewCount < 1)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"A Landscape turn fired with {activeViewCount} active views — "
|
||||
+ "RetailFrameWalk only draws the landscape through an installed view set "
|
||||
+ "(the outdoor root's full-screen default view, or an interior root's "
|
||||
+ "surviving exit views, both at least 1). A zero/negative count is a "
|
||||
+ "walk/driver desync (Campaign FW fail-loud rule).");
|
||||
}
|
||||
if (_skyDrawnThisFrame)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
|
|
@ -727,7 +725,13 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
MarkIfGrown();
|
||||
_events.Add(WalkFrameEvent.Sky());
|
||||
_skyDrawnThisFrame = true;
|
||||
for (int slice = 0; slice < _activeTerrainSliceCount; slice++)
|
||||
// FW4 slice 1: the fan count is the WALK'S OWN active view count
|
||||
// (carried on the Landscape event) — retail LScape::draw runs once
|
||||
// per view the walk installed. The old clip apparatus's slice count
|
||||
// no longer participates; the renderer re-derives the actual slice
|
||||
// clip data from the same walk views before replay, so index i here
|
||||
// and OutsideViewSlices[i] there are the same view by construction.
|
||||
for (int slice = 0; slice < activeViewCount; slice++)
|
||||
_events.Add(WalkFrameEvent.TerrainSlice(slice));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue