using System; using AcDream.App.Rendering; using Xunit; namespace AcDream.App.Tests.Rendering; /// /// #129 — doors/doorways leak through terrain and houses from over a landblock /// away. The punch's mark pass (#117, AD-18) biased the aperture fan toward /// the viewer by a CONSTANT 0.0005 NDC. NDC depth is non-linear: a constant /// NDC bias b spans ≈ b·d²·(f−n)/(f·n) meters of eye depth at eye distance d /// — 0.125 m at 5 m but ~190 m at a landblock (znear 0.1), so distant /// occluders in front of an aperture passed the mark and were far-Z punched: /// the door-shaped leak. The fix caps the bias's eye-space span /// (PortalDepthMaskRenderer.MarkBiasNdc): identical to the validated constant /// below the ~10 m crossover, never more than the cap beyond it. /// public class Issue129PunchBiasTests { private const float Near = PortalDepthMaskRenderer.CameraNearPlaneMeters; // 0.1 (retail znear) private const float Far = 5000f; /// Eye-depth span (meters) covered by an NDC depth bias b at eye /// distance d: ndc(d) = f(d−n)/((f−n)d) ⇒ d(ndc) inverse ⇒ /// span = b·d²·(f−n)/(f·n) (exact for small b via the derivative). private static float EyeSpanMeters(float biasNdc, float d) => biasNdc * d * d * (Far - Near) / (Far * Near); [Fact] public void OldConstantBias_SpansMetersAtALandblock_TheLeak() { // The refuted form (documentation of WHY the constant was wrong): // 0.0005 NDC at ~one landblock spans far more eye depth than any // occluder separation — everything in front got punched. Assert.True(EyeSpanMeters(0.0005f, 192f) > 100f); // ...while at close range it was a sane sliver: Assert.InRange(EyeSpanMeters(0.0005f, 5f), 0.05f, 0.30f); } [Fact] public void CappedBias_MatchesValidatedConstant_AtCloseRange() { // Below the crossover the T5-validated constant must win unchanged — // this preserves the #108 grass coverage bit-for-bit. foreach (float d in new[] { 0.5f, 1f, 3f, 5f, 8f, 9.9f }) Assert.Equal(0.0005f, PortalDepthMaskRenderer.MarkBiasNdc(d), 6); } [Fact] public void CappedBias_EyeSpanNeverExceedsCap_AtAnyDistance() { for (float d = 1f; d <= 400f; d += 1f) { float span = EyeSpanMeters(PortalDepthMaskRenderer.MarkBiasNdc(d), d); Assert.True(span <= PortalDepthMaskRenderer.PunchMarkBiasEyeCapMeters * 1.02f, FormattableString.Invariant($"bias spans {span:F2} m of eye depth at d={d} m")); } } [Fact] public void CappedBias_At200m_CannotReachOccluders() { // The reported #129 distance: occluder separations are tens of // meters; the punch reach must stay under the 0.5 m cap. float span = EyeSpanMeters(PortalDepthMaskRenderer.MarkBiasNdc(200f), 200f); Assert.True(span <= 0.51f, FormattableString.Invariant($"span {span:F3} m at 200 m")); } }