docs(#180): camera-sweep strobe handoff - evidence, retail anchors, autonomous visual-loop recipe, companion prompt
This commit is contained in:
parent
6aabe0b5ac
commit
7272235a22
1 changed files with 156 additions and 0 deletions
156
docs/research/2026-07-06-180-camera-sweep-strobe-handoff.md
Normal file
156
docs/research/2026-07-06-180-camera-sweep-strobe-handoff.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# Pickup handoff — #180 camera-sweep eye strobe (the #176 "stripes") — port retail's stateful sought-position
|
||||
|
||||
**Paste the companion prompt (bottom of this file / the session log) into a fresh
|
||||
session.** Read this file, then `claude-memory/project_physics_collision_digest.md`
|
||||
(top banner) + `claude-memory/project_render_pipeline_digest.md` (top banner), then
|
||||
**ISSUES #180** (and #176's gate-2 note).
|
||||
|
||||
## TL;DR — what #180 is
|
||||
|
||||
The user's #176 residual — "geometrical patterns, triangles, that get weird
|
||||
stripes… especially when I push the camera to the wall or the openings; if I zoom
|
||||
out and the camera does not touch the walls I get no pattern" — is **NOT a render
|
||||
defect. The camera-collision sweep is BISTABLE while the compressed chase boom
|
||||
moves along a wall**, and the per-frame view hard-cuts tear-interleave on screen:
|
||||
|
||||
> `[flap-sweep]` (launch-176-cameye.log, frames ~38607–38861): consecutive sweeps
|
||||
> whose INPUT moved **~1.4 mm** (the player's glide) flipped the OUTPUT **0.27 m
|
||||
> along the boom** — `pulledIn` 0.27 ↔ 0.53, eye (78.500,−38.633,−3.845) ↔
|
||||
> (78.669,−38.815,−3.938) — re-flipping every ~5–10 frames. All 368,357 sweeps
|
||||
> returned `ok=True` (this is NOT the fallback path — the sweep itself has two
|
||||
> first-contact solutions at an r±ε graze on the corridor's double-faced slabs,
|
||||
> the #137 threshold family, camera edition). At ~1700 fps with no vsync, each
|
||||
> monitor refresh interleaves scanline slices of BOTH views → the fine
|
||||
> stripe/hatch patterns (worst near seams where the 0.27 m parallax is largest),
|
||||
> flickering with movement. Parked camera = static (all prior "camera stable"
|
||||
> evidence was parked-camera; the strobe needs motion + a compressed boom).
|
||||
|
||||
This very plausibly also produced the ORIGINAL #176 seam flashes (one of the two
|
||||
alternating eyes sees the purple under-room parallax, the other doesn't).
|
||||
|
||||
## Eliminated for the stripes (DO-NOT-RETRY — all isolation-killed)
|
||||
|
||||
| Ruled OUT | How |
|
||||
|---|---|
|
||||
| Texture / grout-line interaction | `ACDREAM_LIGHT_DEBUG=3` (raw vLit field, texture ignored) still shows the pattern |
|
||||
| The per-cell shell clip trim (gl_ClipDistance) | `ACDREAM_CLIP_DEBUG=1` (shells drawn WHOLE, slots forced 0) — user: "Not gone, still there" |
|
||||
| Coplanar dat geometry | 2 cm-epsilon sweep: corridor floor (z=−6) clean; the only stack is the z=−12 under-hall quad×4 — SAME-mesh, bit-identical depth ⇒ stable winner, cannot moiré |
|
||||
| Shell double-instance / floor-coincident entity / portal seals | `[seam-*]` probe: n=1 per cell at the lifted z; portal entities at z=−12.05; zero depth fans (sealed dungeon) |
|
||||
| Light-set churn under movement | `[seam-blk]`: the floor's applied set held the SAME 8 identities through a 148k-frame session incl. ~12k distinct positions |
|
||||
| The light pool tracking the camera | FIXED `d8984e87` (resident collection, player anchor) — verified: flood churned 8→41 across a full turn, set constant. Do NOT re-open; re-gate VISUALLY only after #180 |
|
||||
| SweepEye itself misporting update_viewer | Read side-by-side: flags 0x5c, AdjustPosition seating, fallbacks all match 0x00453ce0. The bistability is in the transition's contact solution, not the port shape |
|
||||
|
||||
## The retail anchor (the fix direction — read BEFORE coding)
|
||||
|
||||
Retail's camera target is **STATEFUL**; ours re-demands the full boom every frame:
|
||||
|
||||
- `SmartBox` per-frame (pseudo-C line ~91842, addr 0x00452d75):
|
||||
`CameraManager::UpdateCamera(this->camera_manager, &ret, &this->viewer)` — the
|
||||
argument is the **CURRENT swept viewer**, and the RETURN is assigned to
|
||||
`this->viewer_sought_position` (0x00452d84). So the next frame's sweep target
|
||||
derives from the collided position — the target CONVERGES onto the wall
|
||||
contact and re-extends gradually; the knife-edge full-length ray is not
|
||||
re-rolled per frame. That is why retail's camera glides along walls instead of
|
||||
strobing.
|
||||
- `CameraManager::UpdateCamera` = **0x00456660** (pseudo-C line ~95505). Only the
|
||||
head was read this session (offset-movement integration, pivot query); the
|
||||
sought-position derivation in the tail is UNREAD — **read it fully, write the
|
||||
pseudocode doc (workflow step 3), then port**.
|
||||
- `SmartBox::update_viewer` = **0x00453ce0** (line ~92761) — already faithfully
|
||||
ported by `PhysicsCameraCollisionProbe.SweepEye`; leave it alone.
|
||||
- **No damping band-aid on the swept result without the UpdateCamera reading**
|
||||
(the no-workaround rule; the user has already reverted redesigns that replaced
|
||||
retail mechanisms).
|
||||
|
||||
Port site: `src/AcDream.App/Rendering/RetailChaseCamera.cs` (the desired-eye /
|
||||
boom derivation) — it must consume the previous swept viewer per retail.
|
||||
|
||||
## Also open from this arc
|
||||
|
||||
- **Site-A weenie light-registration LEAK**: `[seam-ent]` showed one portal cell's
|
||||
I100 light ×2 → ×4 within a session — re-CreateObject re-registers the light
|
||||
under a fresh `entity.Id` (GameWindow ~3679: `Id = _liveEntityIdCounter++`)
|
||||
without tearing down the previous registration. The wash intensifies over
|
||||
time. Fix with #180's gate or fold into A7 (noted in ISSUES #176).
|
||||
- **#176 re-gate** happens only after #180 lands: camera pressed into
|
||||
walls/openings while moving → no patterns; corridor seam turn → steady purple
|
||||
wedge (the faceted SHAPE is cdb-proven retail — only instability is a defect).
|
||||
- After BOTH pass: strip the throwaway probes in one cleanup commit —
|
||||
`[seam-*]` (ACDREAM_PROBE_SEAMDRAW), `ACDREAM_LIGHT_DEBUG` modes,
|
||||
`ACDREAM_CLIP_DEBUG`. Keep `[flap-sweep]` (it rides ACDREAM_PROBE_FLAP).
|
||||
|
||||
## Apparatus (reuse, don't rebuild)
|
||||
|
||||
- `ACDREAM_PROBE_FLAP=1` → `[flap-sweep]` per-sweep line: `desiredBack/eyeBack/
|
||||
pulledIn/in=/out=` — THE #180 instrument (plus [flap]/[flap-cam]).
|
||||
- `ACDREAM_PROBE_PVINPUT=1` → per-frame `[pv-input] eye=` at 6 dp.
|
||||
- **The autonomous visual loop** (no user needed, works where RenderDoc can't —
|
||||
RenderDoc doesn't support GL_ARB_bindless_texture and the modern gate throws):
|
||||
1. Launch via `dotnet run` (background) with probes; wait ~12 s.
|
||||
2. Input: `keybd_event` **with real scan codes + KEYEVENTF_EXTENDEDKEY**
|
||||
(GLFW decodes scancodes; vk-only silently does nothing). Arrows: Left
|
||||
0x25/0x4B, Right 0x27/0x4D, Down 0x28/0x50. `SetForegroundWindow` first,
|
||||
verify with `GetForegroundWindow`. Hold-key = down, Sleep, up.
|
||||
3. Capture: `GetWindowRect` + `Graphics.CopyFromScreen` → PNG in the
|
||||
scratchpad → **the Read tool renders it** (take 3 captures ~150 ms apart —
|
||||
frame-pair diffs expose per-frame strobes).
|
||||
4. Repro recipe: back the character into a wall (hold Down ~2.5 s) — the boom
|
||||
compresses; the strobe fires DURING/just after motion near the wall.
|
||||
5. Close gracefully via `CloseMainWindow()` (ACE session clears in ~5 s).
|
||||
- Launch logs on disk (worktree root): `launch-176-cameye.log` (THE strobe
|
||||
capture), `launch-176-user-gate.log` (148k-frame user session incl. the light
|
||||
leak), `launch-176-seamdraw.log`, `launch-176-fix-verify.log`.
|
||||
- `ACDREAM_LIGHT_DEBUG=1/2/3` + `ACDREAM_CLIP_DEBUG=1` — shader/clip isolation
|
||||
toggles (throwaway; strip at cleanup).
|
||||
|
||||
## State
|
||||
|
||||
- `main` = worktree branch `claude/vigorous-joliot-f0c3ad` = **`6aabe0b5`**
|
||||
(lighting fix `d8984e87` + isolation apparatus `6aabe0b5`). Suites green
|
||||
(Core 2599+2skip / App 726+2skip / UI 425 / Net 385).
|
||||
- Register: AP-85 rewritten (resident+player-anchored pool; residual = single
|
||||
128 pool vs retail 7-dyn/40-static). The a7 pseudocode doc carries a
|
||||
correction banner (`visible_cell_table` = RESIDENT registry — the
|
||||
identifier-name-≠-semantics lesson, memory
|
||||
`feedback_bn_decomp_field_names` class 4).
|
||||
- A client may be running — the user manages its lifecycle; ASK before
|
||||
rebuilding if the App DLL is locked (MSB3027 = lock, not code).
|
||||
- The test char spawns in the Facility Hub corridor (cell `0x8A020164`).
|
||||
|
||||
## Companion prompt (paste into the fresh session)
|
||||
|
||||
```
|
||||
Fix #180 — the camera-collision sweep strobes the eye 0.27m per few frames when
|
||||
the compressed chase boom moves along walls; at ~1700fps the tear-interleaved
|
||||
views ARE the #176 "stripes/triangles" the gates keep failing on. The mechanism
|
||||
is probe-pinned; every render suspect is isolation-killed. Do NOT re-investigate
|
||||
the render, the light pool (fixed d8984e87, data-verified), or SweepEye's port
|
||||
(faithful, exonerated).
|
||||
|
||||
READ FIRST, in order:
|
||||
1. docs/research/2026-07-06-180-camera-sweep-strobe-handoff.md (evidence,
|
||||
DO-NOT-RETRY table, retail anchors, the autonomous visual-loop recipe)
|
||||
2. claude-memory/project_physics_collision_digest.md (top banner)
|
||||
3. docs/ISSUES.md #180 (+ #176's gate-2 note)
|
||||
|
||||
THE FIX = port retail's STATEFUL camera target: SmartBox (0x00452d75) feeds the
|
||||
CURRENT swept viewer into CameraManager::UpdateCamera (0x00456660) and assigns
|
||||
the RETURN to viewer_sought_position (0x00452d84) — the target converges onto
|
||||
the wall contact instead of re-rolling the full knife-edge boom ray per frame
|
||||
like RetailChaseCamera does. Workflow: read UpdateCamera's tail (the sought
|
||||
derivation — UNREAD so far, pseudo-C line ~95505), write the pseudocode doc,
|
||||
port into RetailChaseCamera. NO damping band-aids on the swept result.
|
||||
|
||||
Verify autonomously with the handoff's visual loop (keybd_event scan-codes +
|
||||
GDI window capture + [flap-sweep]): back into a wall, confirm consecutive-frame
|
||||
eye deltas stay continuous and no stripe patterns in captures. Then the user
|
||||
gate covers #180 AND the #176 re-gate (steady purple wedge at the seam — the
|
||||
wedge SHAPE is retail, cdb-proven). After both pass: fix the site-A light-
|
||||
registration leak (one portal light stacked ×4/session — re-CreateObject
|
||||
re-registers under fresh entity ids) and strip the throwaway probes
|
||||
([seam-*], ACDREAM_LIGHT_DEBUG, ACDREAM_CLIP_DEBUG) in a cleanup commit.
|
||||
|
||||
State: main @ 6aabe0b5, suites green (Core 2599+2skip). Test char spawns in the
|
||||
Facility Hub corridor 0x8A020164. A client may be running — the user manages
|
||||
its lifecycle; ASK before rebuilding if the App DLL is locked.
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue