checkpoint(render): preserve pre-overhaul investigation state
This commit is contained in:
parent
e880860291
commit
b3b7d922f1
45 changed files with 3168 additions and 619 deletions
|
|
@ -8,13 +8,12 @@ namespace AcDream.App.Rendering;
|
|||
/// writes — the port of <c>D3DPolyRender::DrawPortalPolyInternal</c>
|
||||
/// (Ghidra 0x0059bc90, pc:424490).
|
||||
///
|
||||
/// <para><b>Wired by T1 (BR-3, `579c8b0`):</b> seal on interior roots, punch
|
||||
/// on outdoor / look-in roots, via <c>RetailPViewPassExecutor.DrawPortalDepthWrite</c>
|
||||
/// (the <c>DrawExitPortalMasks</c> slice callback) — safe alongside the
|
||||
/// dynamics-drawn-LAST frame order (the first BR-2 attempt punched after
|
||||
/// dynamics and erased the player; reverted 88be519). #117 (2026-06-11)
|
||||
/// added the two-pass stencil depth gate on the punch side — see
|
||||
/// <see cref="DrawDepthFan"/>.</para>
|
||||
/// <para>Campaign FW's ordered frame walk restores the positional discipline
|
||||
/// on which this primitive depends: farther landscape/static content is
|
||||
/// submitted before a building punch, the punch precedes that building's
|
||||
/// look-in cells, and nearer content repaints afterward. Consequently both
|
||||
/// sides now use retail's one-pass depth operation directly; the former
|
||||
/// stencil mark/bias approximation from #117 is intentionally gone.</para>
|
||||
///
|
||||
/// <para>Retail projects a portal polygon, software-clips it against the
|
||||
/// installed portal view (<c>polyClipFinish</c>), and draws the survivor as a
|
||||
|
|
@ -78,49 +77,6 @@ public sealed partial class PortalDepthMaskRenderer : IDisposable
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// #117 (2026-06-11): the mark-pass depth bias, in NDC, toward the
|
||||
/// viewer. Retail's punch is DEPTHTEST_ALWAYS and is safe only because
|
||||
/// retail's outdoor pass is painter's-ordered far→near (anything nearer
|
||||
/// redraws AFTER the punch and re-covers it). Our z-buffered MDI frame
|
||||
/// has no such order, so an unconditional far-Z punch erased the depth
|
||||
/// of NEARER occluders (terrain hills, closer buildings) at aperture
|
||||
/// pixels — doors/interiors painted through them (the T5 #117 report).
|
||||
/// The z-buffer-correct equivalent: punch ONLY where the aperture
|
||||
/// polygon itself wins a depth test at its true depth (two-pass
|
||||
/// stencil below). The bias keeps the #108 case covered — terrain
|
||||
/// hugging the door plane (centimeters in front of the aperture) must
|
||||
/// still be punched; a hill or another house meters nearer must not.
|
||||
/// </summary>
|
||||
private const float PunchMarkDepthBias = 0.0005f;
|
||||
|
||||
/// <summary>
|
||||
/// #129 (2026-06-12): NDC depth is non-linear — a constant NDC bias b
|
||||
/// spans ≈ b·d²/near meters of eye depth at eye distance d. With
|
||||
/// znear = 0.1, the 0.0005 constant alone spanned 0.125 m at 5 m but
|
||||
/// ~190 m at a landblock away: every hill/house in front of a distant
|
||||
/// aperture passed the mark and got far-Z punched — door-shaped leaks
|
||||
/// through occluders. Fix: cap the bias's EYE-SPACE span at
|
||||
/// <see cref="PunchMarkBiasEyeCapMeters"/>. Below the ~10 m crossover
|
||||
/// (sqrt(cap·near/0.0005)) the constant-NDC term is smaller and wins —
|
||||
/// bit-identical to the T5-validated close-range behavior (#108 grass
|
||||
/// coverage untouched); beyond it the punch can never reach an occluder
|
||||
/// more than the cap in front of the aperture plane.
|
||||
/// </summary>
|
||||
public const float PunchMarkBiasEyeCapMeters = 0.5f;
|
||||
|
||||
/// <summary>Retail <c>Render::znear</c> = 0.1 (decomp :342173, re-landed
|
||||
/// d4b5c71). The cap conversion below assumes the production camera near
|
||||
/// plane; the small f/(f−n) factor (~1.00002 at far 5000) is ignored.</summary>
|
||||
public const float CameraNearPlaneMeters = 0.1f;
|
||||
|
||||
/// <summary>CPU mirror of the vertex-shader mark-bias expression (keep in
|
||||
/// sync with <c>VertSrc</c>): the NDC bias applied at eye depth
|
||||
/// <paramref name="eyeDepthMeters"/>.</summary>
|
||||
public static float MarkBiasNdc(float eyeDepthMeters) =>
|
||||
MathF.Min(PunchMarkDepthBias,
|
||||
PunchMarkBiasEyeCapMeters * CameraNearPlaneMeters
|
||||
/ MathF.Max(eyeDepthMeters * eyeDepthMeters, 1e-6f));
|
||||
|
||||
/// <summary>
|
||||
/// Draw one portal polygon as an invisible depth write, clipped to the
|
||||
/// slice's clip-space half-planes. <paramref name="forceFarZ"/> selects
|
||||
|
|
@ -130,13 +86,9 @@ public sealed partial class PortalDepthMaskRenderer : IDisposable
|
|||
/// depth ALWAYS + true projected depth. It runs immediately after the
|
||||
/// gated full depth clear, so there is no nearer content to stomp.</para>
|
||||
///
|
||||
/// <para><b>Punch</b> (outdoor root / look-in): two passes (#117).
|
||||
/// Pass A marks stencil where the aperture fan passes a LEQUAL depth
|
||||
/// test at its (biased) true depth — i.e. where the aperture is
|
||||
/// actually visible against everything drawn so far. Pass B writes the
|
||||
/// far-Z punch with depth ALWAYS but stencil-gated to the marked
|
||||
/// pixels, and zeroes the stencil as it goes (self-cleaning). This is
|
||||
/// the z-buffered equivalent of retail's painter's-order safety.</para>
|
||||
/// <para><b>Punch</b> (outdoor root / look-in): one pass, retail-verbatim
|
||||
/// — depth ALWAYS + far-Z. The ordered frame walk, not a visibility test
|
||||
/// at the aperture plane, supplies retail's painter-order safety.</para>
|
||||
/// </summary>
|
||||
public void DrawDepthFan(
|
||||
ReadOnlySpan<Vector3> worldVerts,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue