feat(render) Campaign FW3.3: ShellDrawLiftZ is RETIRED - cells draw at the dat origin

Retail draws cell geometry at the dat EnvCell origin verbatim; the
0.02 m lift was our z-fight stand-in (register row AP-32, deleted in
this commit). With the walk owning retail draw ORDER under
WorldDepthContract Less (first-drawn-wins: DrawBlock terrain-then-
objects per cell, DrawCells shells-then-contents), the coplanar
tie-breaks the lift compensated for are now resolved the way retail
resolves them.

Deleted at every site: the PortalVisibilityBuilder const + the
drawLiftZ Build parameter and its lifted exit-portal projection branch
(gate and drawn geometry now share ONE space); the seal/punch fan
lifts (DrawPortalDepthWrite + the walk's DrawWalkPunchFan); the
LandblockBuildFactory drawn-cell-transform lift (render and physics
share the one verbatim transform).

The #130 proof flipped exactly as its own doc predicted:
UnliftedGate_LeavesTheStripAtTheDrawnTopEdge is deleted (its premise -
gate space != drawn space - no longer exists), and the renamed
ExitDoorTopEdge_GateCoversTheDrawnApertureWithinPixelTolerance sweep
(147 eye/gaze combos at the Holtburg corner door) passes with both in
the same unlifted space (worst plane gap <= 1.2 px, scissor <= 0.15 px
- unchanged tolerances). Ten more replay-test call sites swept to the
new Build signature.

Suites: full Release build 0 warnings; hermetic 6,750/0; the 21
affected InstalledDat replay tests green; Walk conformance 40/1
untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-30 16:08:52 +02:00
parent 1955a0d5f1
commit 05240d2cab
12 changed files with 55 additions and 196 deletions

View file

@ -342,31 +342,26 @@ public static class PortalVisibilityBuilder
Console.WriteLine($"[pv-ERROR] chain tail(24):{tail}");
}
/// <summary>The +Z world lift applied to DRAWN cell shells (z-fighting vs
/// terrain; applied in GameWindow's cell registration). The visibility
/// graph stays in PHYSICS (unlifted) space — feeding the lift into portal
/// planes broke horizontal-portal side tests (#119-residual, f35cb8b).
/// Draw-space consumers of portal polygons (the OutsideView color gate
/// here, the seal/punch depth fans in GameWindow) must apply this lift so
/// they meet the drawn shell's aperture edge — the unlifted gate left a
/// 2 cm background strip under the drawn lintel (#130).</summary>
public const float ShellDrawLiftZ = 0.02f;
// Campaign FW3.3 (2026-08-30): ShellDrawLiftZ (the 0.02 m drawn-shell
// lift, register row AP-32) is RETIRED. Retail draws cell geometry at
// the dat EnvCell origin verbatim; the coplanar tie-breaks the lift
// stood in for are now owned by the walk's retail draw ORDER under
// WorldDepthContract's Less (first-drawn-wins — RenderDeviceD3D::
// DrawBlock terrain-then-objects per cell, PView::DrawCells shells-then-
// contents). With the lift gone, the visibility gate and the drawn
// geometry share ONE space, so the #130 strip mechanism (gate space ≠
// drawn space) no longer exists.
/// <param name="lookup">Resolve a full cell id to its LoadedCell, or null if not loaded.</param>
/// <param name="buildingMembership">Optional: true if a cell id is in the camera building's cell
/// set. When provided, a neighbour OUTSIDE the set routes to CrossBuildingViews instead of
/// continuing the in-building BFS. Pass null to treat all reachable cells as in-building.</param>
/// <param name="drawLiftZ">World +Z applied ONLY to the exit-portal projection feeding
/// <see cref="PortalVisibilityFrame.OutsideView"/> (a draw-space region; see
/// <see cref="ShellDrawLiftZ"/>). Flood admission, side tests, and CellViews are unaffected.
/// Production passes <see cref="ShellDrawLiftZ"/>; tests replaying visibility semantics pass 0.</param>
public static PortalVisibilityFrame Build(
LoadedCell cameraCell,
Vector3 cameraPos,
Func<uint, LoadedCell?> lookup,
Matrix4x4 viewProj,
Func<uint, bool>? buildingMembership = null,
float drawLiftZ = 0f,
PortalVisibilityFrame? reuseFrame = null)
{
var frame = reuseFrame ?? new PortalVisibilityFrame();
@ -544,38 +539,13 @@ public static class PortalVisibilityBuilder
if (portal.OtherCellId == 0xFFFF)
{
// Exit portal -> outdoors visible through this (clipped) opening.
// OutsideView gates DRAWN color (terrain/sky/scissor), and the
// shell that rasterizes this aperture draws +drawLiftZ above
// the physics transform — project the region in the SAME
// lifted space or terrain stops a lift-height short of the
// drawn lintel (#130 strip). Flood semantics keep the
// unlifted clippedRegion path above.
int outsideCount;
if (drawLiftZ == 0f)
{
AddRegion(frame.OutsideView, clippedRegion);
outsideCount = clippedRegion.Count;
}
else
{
using PortalVisibilityFrame.ClipRegionScratchLease outsideRegionLease =
frame.RentClipRegionScratch();
List<ViewPolygon> outsideRegion = outsideRegionLease.Region;
ClipPortalAgainstView(
frame,
poly,
cell.WorldTransform * Matrix4x4.CreateTranslation(0f, 0f, drawLiftZ),
viewProj,
currentView.Polygons,
processedCount,
endCount - processedCount,
outsideRegion,
out _);
AddRegion(frame.OutsideView, outsideRegion);
outsideCount = outsideRegion.Count;
}
trace?.Add($"portal cell=0x{cell.CellId:X8} p{i}->EXIT addOutside={outsideCount} clipVerts={clipVerts}");
// Exit portal -> outdoors visible through this (clipped)
// opening. FW3.3: shells draw at the dat origin (the
// ShellDrawLiftZ retirement), so the gate and the drawn
// aperture share one space — the unlifted clippedRegion
// IS the draw-space region.
AddRegion(frame.OutsideView, clippedRegion);
trace?.Add($"portal cell=0x{cell.CellId:X8} p{i}->EXIT addOutside={clippedRegion.Count} clipVerts={clipVerts}");
continue;
}