v3: README — board-solve tracking core, dual engines, in-place migration
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# Newbury Exhibit v3
|
||||
|
||||
Fan-made shared multi-viewer AR experience for a physical LEGO® Hidden Side™ town
|
||||
display (tribute project — not affiliated with the LEGO Group). Multiple phones
|
||||
detect printed "Newbury Crests" (ArUco markers) and see the same server-driven
|
||||
ghosts anchored to real-world positions, each from their own viewpoint.
|
||||
|
||||
**v3 = v2 with the tracking core replaced.** Everything else — playlist engine,
|
||||
residents/tracks, character editor, admin suite, dev error overlay, password-
|
||||
protected final mode, deployment — carries over unchanged.
|
||||
|
||||
## What changed in v3
|
||||
|
||||
The per-marker POS-IT → confidence-weighted fusion pipeline is replaced by a
|
||||
**joint multi-marker board solve** (`public/js/ar/solve-cv.js`, OpenCV.js):
|
||||
|
||||
- Every detected crest corner becomes a 3D world point (from `data/scene.json`
|
||||
anchors, same `anchorWorldMatrix` convention as v2) and **one `solvePnP` call**
|
||||
recovers the camera pose. No per-marker fusion, no slerp base, no area buckets.
|
||||
- Stability scales with marker spread. Synthetic validation at 0.5px corner noise:
|
||||
~0.06 cm position / 0.03° rotation error on the full 5-crest board
|
||||
(single-marker POS-IT on the same test: ~2.6 cm / 0.9°).
|
||||
- The **wall crest makes the point set non-coplanar**, which removes the POS-IT
|
||||
planar ambiguity (the flip problem) outright whenever it's visible.
|
||||
- Single visible crest still works: SQPNP/IPPE cold start, then iterative refine
|
||||
warm-started from the previous frame (temporal continuity resolves flips).
|
||||
- A reprojection-error gate (mean px, shown in the dev HUD) rejects poisoned
|
||||
frames before they reach the 1€ filter.
|
||||
|
||||
OpenCV.js (~13 MB WASM) is fetched at Docker build time (pinned
|
||||
`@techstark/opencv-js@4.12.0-release.1`) and lazy-loaded on the client after
|
||||
Start. If it fails to load, the app falls back to the v2 engine automatically.
|
||||
|
||||
## Dual engines (on-table A/B)
|
||||
|
||||
The complete v2 pipeline (`detect.js` → `pose.js` → `fuse.js`) ships alongside
|
||||
the new one until the board solve is confirmed on the real table.
|
||||
|
||||
Dev HUD overlay tap zones (thirds):
|
||||
|
||||
| zone | opencv engine | posit engine |
|
||||
|--------|----------------------------|-----------------------------|
|
||||
| top | switch engine | switch engine |
|
||||
| middle | axis mode (`std`/`ymirror`)| rotation mode (`fr`/…) |
|
||||
| bottom | — | camera correction (`none`/…)|
|
||||
|
||||
Engine choice persists in `localStorage` (`nbx.engine`). Optional per-device
|
||||
horizontal FOV override: `localStorage nbx.hfovDeg` (default 60, both engines).
|
||||
|
||||
`axis ymirror` exists as on-device insurance: if the world appears mirrored /
|
||||
camera under the table in opencv mode, tap the middle third once.
|
||||
|
||||
## First-time load (in place of v2)
|
||||
|
||||
```
|
||||
git clone https://gitea.hideawaygaming.com.au/jessikitty/newbury-exhibit-v3.git ~/newbury-exhibit-v3
|
||||
cd ~/newbury-exhibit-v3 && bash load-v3.sh
|
||||
```
|
||||
|
||||
`load-v3.sh` imports the unchanged v2 base files into this repo (one commit,
|
||||
pushed — set `GITEA_TOKEN=…` if the machine has no git credentials), copies
|
||||
`.env` and any locally-dropped `public/models` from the v2 checkout, stops the
|
||||
v2 container, and brings v3 up **on the same host port, container name, and
|
||||
`exhibit-live` volume** — live scene/playlist/character state carries over.
|
||||
|
||||
- Future deploys: `cd ~/newbury-exhibit-v3 && bash deploy.sh` (same as v2).
|
||||
- Rollback any time: `cd ~/newbury-exhibit && docker compose up -d --build`.
|
||||
|
||||
## Conventions (unchanged from v2)
|
||||
|
||||
- World units cm; origin front-left table corner; +X right, +Z back, +Y up.
|
||||
- Marker print sizes stay in mm (`sizeMM`); single mm→cm conversion at the
|
||||
solver boundary.
|
||||
- `data/*.json` are committed seeds; `data/live/` (volume) is runtime state.
|
||||
- `maxHammingDistance: 0` — hamming-1 detections are 100% phantoms here.
|
||||
|
||||
LEGO® and Hidden Side™ are trademarks of the LEGO Group, which does not sponsor,
|
||||
authorise or endorse this project.
|
||||
Reference in New Issue
Block a user