Revert "fix(camera): rest-snap render position — kills the indoor doorway standing-still flicker"

This reverts commit cd974b29bc.
This commit is contained in:
Erik 2026-06-08 15:08:25 +02:00
parent cd974b29bc
commit 9b1857ac52
2 changed files with 1 additions and 91 deletions

View file

@ -224,73 +224,6 @@ public class PlayerMovementControllerTests
Assert.Equal(result.Position.Z, result.RenderPosition.Z, precision: 4);
}
// ── Indoor doorway flap: render-position rest-snap (2026-06-08) ───────────
//
// Live pin (flap-churn.log, user at the cottage doorway): the physics body is
// byte-stable at rest (rawPlayer = 1 distinct value), but the render position
// (Lerp of the two physics-tick snapshots) jitters ~µm and the camera EYE
// jitters ~1.3 mm — a ~1000x amplification by the grazing-doorframe camera-
// collision sweep, which trips the portal clip → the standing-still flicker.
// The dither is structural: at rest the tick snapshots (_prevPhysicsPos /
// _currPhysicsPos) can lag the settled authoritative Position by microns (door-
// frame edge-settle in the per-frame resolve), so Lerp(prev, curr, alpha) with a
// per-frame-VARYING alpha sweeps a tiny segment instead of holding still. Fix:
// at rest (velocity below epsilon) render AT the authoritative body position —
// byte-identical and alpha-independent. Mirrors retail (a resting object renders
// bit-stable) and the boom convergence snap (RetailChaseCamera.ApplyConvergenceSnap,
// d2212cf), one layer earlier so the camera's pivot input is byte-stable too.
//
// The flat-terrain controller tests above CANNOT reproduce the doorframe-specific
// prev!=curr-at-rest condition (flat terrain collapses prev==curr), so these test
// the pure rest-snap function directly; the end-to-end acceptance is the live
// doorway visual gate.
[Fact]
public void ComputeRenderPosition_AtRestWithStaleEndpoints_SnapsToAuthoritativePosition_NoAlphaDither()
{
// prev lags curr by 30 µm (the live doorframe edge-settle lag); body = the settled
// authoritative position; velocity = 0 (at rest). Two different leftover-accumulator
// alphas must BOTH return the authoritative position, byte-identical (no dither).
var prev = new Vector3(155.525116f, 14.225600f, 94f);
var curr = new Vector3(155.525146f, 14.225600f, 94f);
var body = new Vector3(155.525146f, 14.225600f, 94f);
var lowAlpha = PlayerMovementController.ComputeRenderPosition(prev, curr, body, Vector3.Zero, alpha: 0.15f);
var highAlpha = PlayerMovementController.ComputeRenderPosition(prev, curr, body, Vector3.Zero, alpha: 0.93f);
Assert.Equal(body, lowAlpha); // byte-identical to the authoritative position
Assert.Equal(lowAlpha, highAlpha); // alpha-independent at rest (no dither)
}
[Fact]
public void ComputeRenderPosition_Moving_InterpolatesBetweenTickSnapshots()
{
// Guard the no-over-fire half: while moving (velocity well above the rest epsilon)
// the render position must still interpolate smoothly between the tick snapshots.
var prev = new Vector3(96.0f, 96f, 50f);
var curr = new Vector3(96.3f, 96f, 50f);
var moving = new Vector3(3.12f, 0f, 0f); // walk speed
var half = PlayerMovementController.ComputeRenderPosition(prev, curr, curr, moving, alpha: 0.5f);
Assert.Equal(96.15f, half.X, precision: 3); // midpoint — interpolation preserved
}
[Fact]
public void Update_AtRest_BodyVelocityBelowRenderRestSnapThreshold()
{
// Precondition for the render-position rest-snap: a settled grounded body's velocity must
// be below RestVelocityEpsilonSq, else ComputeRenderPosition's gate never fires at rest and
// the doorway flicker persists. kill_velocity on grounded contact drives it to zero.
var engine = MakeFlatEngine();
var controller = new PlayerMovementController(engine);
controller.SetPosition(new Vector3(96f, 96f, 50f), 0x0001);
for (int i = 0; i < 60; i++) controller.Update(1f / 60f, new MovementInput());
Assert.True(
controller.BodyVelocity.LengthSquared() < PlayerMovementController.RestVelocityEpsilonSq,
$"resting body velocity {controller.BodyVelocity.Length()} m/s must be below the rest-snap threshold");
}
[Fact]
public void Update_RunForward_MoveFasterThanWalk()
{