refactor(render): make the walk sole production visibility owner
This commit is contained in:
parent
2a3ec09a98
commit
98d2d43fdc
1 changed files with 63 additions and 64 deletions
|
|
@ -165,70 +165,9 @@ public sealed class RetailPViewRenderer
|
|||
RecycleLookInFrames();
|
||||
ResetBuildingGroups();
|
||||
|
||||
var pvFrame = PortalVisibilityBuilder.Build(
|
||||
ctx.RootCell,
|
||||
ctx.ViewerEyePos,
|
||||
ctx.Cells.Find,
|
||||
ctx.ViewProjection,
|
||||
buildingMembership: null,
|
||||
reuseFrame: _mainPortalFrameScratch);
|
||||
|
||||
// R-A2: outdoor root — flood each nearby building SEPARATELY from its own entrance and merge
|
||||
// the small (~2-cell) per-building views into the frame. Retail reaches building interiors via
|
||||
// the terrain BSP -> DrawPortal -> ConstructView(CBldPortal) (decomp:326881/433895/433827); the
|
||||
// land root itself has no portals (it floods nothing into buildings). Per-building seeding is
|
||||
// robust to the eye's ~36 µm rest jitter where the pre-R-A2 single reverse-portal flood
|
||||
// oscillated as the chase eye grazed a doorway (the indoor flap).
|
||||
if (ctx.RootCell.IsOutdoorNode && ctx.NearbyBuildingCells is not null)
|
||||
MergeNearbyBuildingFloods(ctx, pvFrame);
|
||||
|
||||
// #124: interior-root building look-ins. Retail runs the look-in INSIDE
|
||||
// the landscape stage for ANY root — LScape::draw is the FIRST call of
|
||||
// DrawCells' outside-view branch (pc:432719), strictly BEFORE the depth
|
||||
// clear (pc:432732) and the exit-portal seals (pc:432785); a far
|
||||
// building seen through our doorway floods clipped to the INSTALLED
|
||||
// outside view (GetClip vs current view, ConstructView(CBldPortal)
|
||||
// 0x005a59a0). These frames therefore draw in DrawBuildingLookIns
|
||||
// (inside the landscape stage), NEVER merged into the main frame — a
|
||||
// merged cell would draw post-clear and z-fail against the root's seal
|
||||
// (its geometry is beyond the door plane). The eye-side seed test
|
||||
// self-excludes the root's own building (the eye is on its interior
|
||||
// side). Outdoor roots keep the MergeNearbyBuildingFloods path above
|
||||
// (no depth clear under outdoor roots — the merged form is equivalent
|
||||
// there).
|
||||
if (!ctx.RootCell.IsOutdoorNode
|
||||
&& ctx.NearbyBuildingCells is not null
|
||||
&& pvFrame.OutsideView.Polygons.Count > 0)
|
||||
BuildInteriorRootLookIns(ctx, pvFrame);
|
||||
|
||||
var clipAssembly = passes.AssembleClipFrame(
|
||||
pvFrame,
|
||||
_clipAssemblyScratch);
|
||||
passes.AppendLookInClipFrames(_lookInFrames, clipAssembly);
|
||||
// FW4 slice 1: PrepareClipFrame (the one clip-region publication)
|
||||
// moved BELOW the walk block — an interior-rooted walk frame
|
||||
// re-derives the outside-view slices from the walk's own views
|
||||
// first, so the appended slots join the same single publication.
|
||||
|
||||
// R1: draw EVERY visible cell (retail cell_draw_list), not only the cells the
|
||||
// assembler handed a clip-slot. This feeds the Prepare filter + entity partition,
|
||||
// so every visible cell's shell has a prepared batch and seals — killing the grey
|
||||
// (the old clipAssembly.CellIdToSlot.Keys filter silently dropped slot-less cells).
|
||||
// Per-slice trim still applies in DrawEnvCellShells (Task 4 makes it self-contained).
|
||||
_drawableCellsScratch.Clear();
|
||||
_drawableCellsScratch.UnionWith(pvFrame.OrderedVisibleCells);
|
||||
var drawableCells = _drawableCellsScratch;
|
||||
passes.UseIndoorMembershipOnlyRouting();
|
||||
|
||||
// Campaign FW3.2b-2: the production rooting. A concrete executor is
|
||||
// required — the walk submits through WbDrawDispatcher.SubmitOrderedStream
|
||||
// and needs a real GPU frame/encoder (RequireWalkSubmission), which no
|
||||
// test IRetailPViewPassExecutor fake can supply. Whenever a concrete
|
||||
// executor IS present, the retained render scene must ALSO be
|
||||
// wired with all three walk registries — a scene product without the
|
||||
// walk data (or vice versa) is a production miswiring, not a
|
||||
// legacy/diagnostic shape, so it fails loud rather than silently
|
||||
// falling back to the retired static routes (plan §FW3 item 6).
|
||||
// Campaign FW4 production cutover: decide the walk route before any
|
||||
// old PView construction. A concrete production executor must have all
|
||||
// walk registries; otherwise the frame is miswired and fails loud.
|
||||
RetailPViewPassExecutor? walkExecutor = passes as RetailPViewPassExecutor;
|
||||
bool walkRegistriesReady =
|
||||
_walkBuildings is not null
|
||||
|
|
@ -252,6 +191,61 @@ public sealed class RetailPViewRenderer
|
|||
&& _renderSceneShadow is not null
|
||||
&& walkRegistriesReady;
|
||||
|
||||
PortalVisibilityFrame pvFrame;
|
||||
if (walkActive)
|
||||
{
|
||||
// Compatibility carrier only. Production visibility is populated
|
||||
// exclusively by RetailFrameWalk below; this frame supplies the
|
||||
// clip assembler's outdoor full-screen seed until that remaining
|
||||
// shell is deleted later in FW4.
|
||||
pvFrame = _mainPortalFrameScratch;
|
||||
pvFrame.ResetForBuild();
|
||||
if (ctx.RootCell.IsOutdoorNode)
|
||||
{
|
||||
pvFrame.OutsideView.SetFullScreen();
|
||||
pvFrame.OrderedVisibleCells.Add(ctx.RootCell.CellId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Standalone/fake executor compatibility. Production never calls
|
||||
// PortalVisibilityBuilder after the FW4 cutover above.
|
||||
pvFrame = PortalVisibilityBuilder.Build(
|
||||
ctx.RootCell,
|
||||
ctx.ViewerEyePos,
|
||||
ctx.Cells.Find,
|
||||
ctx.ViewProjection,
|
||||
buildingMembership: null,
|
||||
reuseFrame: _mainPortalFrameScratch);
|
||||
|
||||
if (ctx.RootCell.IsOutdoorNode && ctx.NearbyBuildingCells is not null)
|
||||
MergeNearbyBuildingFloods(ctx, pvFrame);
|
||||
if (!ctx.RootCell.IsOutdoorNode
|
||||
&& ctx.NearbyBuildingCells is not null
|
||||
&& pvFrame.OutsideView.Polygons.Count > 0)
|
||||
BuildInteriorRootLookIns(ctx, pvFrame);
|
||||
}
|
||||
|
||||
var clipAssembly = passes.AssembleClipFrame(
|
||||
pvFrame,
|
||||
_clipAssemblyScratch);
|
||||
if (!walkActive)
|
||||
passes.AppendLookInClipFrames(_lookInFrames, clipAssembly);
|
||||
// FW4 slice 1: PrepareClipFrame (the one clip-region publication)
|
||||
// moved BELOW the walk block — an interior-rooted walk frame
|
||||
// re-derives the outside-view slices from the walk's own views
|
||||
// first, so the appended slots join the same single publication.
|
||||
|
||||
// R1: draw EVERY visible cell (retail cell_draw_list), not only the cells the
|
||||
// assembler handed a clip-slot. This feeds the Prepare filter + entity partition,
|
||||
// so every visible cell's shell has a prepared batch and seals — killing the grey
|
||||
// (the old clipAssembly.CellIdToSlot.Keys filter silently dropped slot-less cells).
|
||||
// Per-slice trim still applies in DrawEnvCellShells (Task 4 makes it self-contained).
|
||||
_drawableCellsScratch.Clear();
|
||||
_drawableCellsScratch.UnionWith(pvFrame.OrderedVisibleCells);
|
||||
var drawableCells = _drawableCellsScratch;
|
||||
passes.UseIndoorMembershipOnlyRouting();
|
||||
|
||||
// Campaign FW3.4a: THE ONE WALK. Builds walkContext/walkLandscape/
|
||||
// walkCameraCell exactly as the pre-FW3.4a pre-walk collection pass
|
||||
// did, then drives WalkFrameDriver.Collect — a SINGLE RetailFrameWalk
|
||||
|
|
@ -382,6 +376,11 @@ public sealed class RetailPViewRenderer
|
|||
viewportHeight);
|
||||
}
|
||||
|
||||
// The walk's visited set replaces PortalVisibilityFrame's old
|
||||
// OrderedVisibleCells side-channel for every production consumer.
|
||||
_drawableCellsScratch.Clear();
|
||||
_drawableCellsScratch.UnionWith(walkDriver.VisitedCells);
|
||||
|
||||
// Phase I cathedral instrumentation (synthesis §Phase I.3): the
|
||||
// continuous rooting line SEPARATES the true root flood
|
||||
// (InteriorFloodCells) from the visited union (root + look-ins —
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue