fix #180: port retail's stateful camera sought-position - the sweep target converges onto the wall contact

The camera-collision sweep strobed the eye 0.27m every ~5-10 frames while
the compressed chase boom moved along corridor walls (pulledIn 0.27<->0.53
on ~1.4mm input drift): RetailChaseCamera re-demanded the FULL-length ideal
boom from scratch each frame, so the pivot->eye ray re-rolled the same
knife-edge r+-eps graze on the double-faced slabs every frame, and its two
first-contact solutions tear-interleaved at ~1700fps into the #176
"stripes/triangles".

Retail never re-rolls that ray. CameraManager::UpdateCamera (0x00456660)
interpolates FROM THE CURRENT SWEPT VIEWER toward the desired pose
(interpolate_origin/rotation, stiffness 0.45 x dt x 10, clamped) and the
result becomes viewer_sought_position (SmartBox::PlayerPhysicsUpdatedCallback
0x00452d60); update_viewer (0x00453ce0) sweeps pivot->SOUGHT. Pressed against
a wall the sweep ray extends one interpolation step past the contact
(sub-mm at high fps), so a bistable graze can move the eye by at most that
step - the strobe is structurally impossible. A 0.4mm/2e-4 dead-band parks
the sought exactly on the viewer when converged (0x00456fcd-0x00457035).

- RetailChaseCamera: _dampedEye -> _soughtEye + _publishedEye (retail's two
  Positions); lerp base = the published (swept) viewer; sweep targets the
  sought; total-fallback (ViewerCellId==0) resets the sought like
  set_viewer(player_pos, 1). The old "collision must NOT feed back into the
  damped state" comment had the coupling backwards - what stays clean is the
  transient desired pose, not the sought.
- SweepEye untouched (faithful update_viewer port, exonerated by the #180
  investigation).
- Tests: the old pin asserting instant full re-extension after a clamp
  (the divergence itself) replaced with four retail pins: gradual
  re-extension, sweep-target-converges-onto-contact, total-fallback
  re-extends from the player, wall-press glide stability.
- Pseudocode doc: docs/research/2026-07-06-camera-sought-position-pseudocode.md
  (UpdateCamera tail incl. the sought derivation + set_viewer reset semantics
  + Frame interpolate/close_rotation).
- Register: AD-37 (forward-vector nlerp vs quaternion slerp), AD-38
  (init-at-full-extension vs retail re-extend-from-player) - both
  pre-existing, identified during the decomp reading.

Suites green (Core 2599+2skip / App 729+2skip / UI 425 / Net 385).
Pending: autonomous visual verify + user gate (#180 + the #176 re-gate).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-06 16:49:01 +02:00
parent 7272235a22
commit 48aaab811c
5 changed files with 571 additions and 56 deletions

View file

@ -48,7 +48,13 @@ Copy this block when adding a new issue:
## #180 — Camera-collision sweep bistable at a compressed boom → per-frame eye strobe (the #176 "stripes")
**Status:** OPEN — mechanism PINNED numerically; fix = port retail's stateful sought-position
**Status:** 🟡 FIX SHIPPED 2026-07-06 (stateful sought-position ported per
`CameraManager::UpdateCamera` 0x00456660 — the interpolation base is the
CURRENT swept viewer and the sweep targets the converging sought, never the
full-length boom; pseudocode
`docs/research/2026-07-06-camera-sought-position-pseudocode.md`; register
AD-37/AD-38 filed for the two pre-existing adaptations found in the reading).
Awaiting autonomous visual verify + the user gate (with the #176 re-gate).
**Severity:** HIGH (the visible flicker/stripe artifact the #176 gate keeps failing on; corridor camera constantly rides walls)
**Filed:** 2026-07-06
**Component:** camera / physics (NOT render — every render suspect eliminated by isolation)