diff --git a/public/js/exhibit.js b/public/js/exhibit.js index c1a94bf..3323f3e 100644 --- a/public/js/exhibit.js +++ b/public/js/exhibit.js @@ -4,7 +4,7 @@ * * v3 ships two runtime-switchable tracking engines (HUD overlay, tap top third): * opencv (default) — joint multi-marker board solve (solve-cv.js). All detected - * corners -> one solvePnP -> camera pose. Non-coplanar wall + * corners -> one solvePnP -> camera pose. A non-coplanar * crest removes planar ambiguity outright. * posit — the v2 per-marker POS-IT + fuseWorld path, kept intact for * on-table A/B until the new engine is confirmed. Delete later. @@ -86,6 +86,13 @@ const focalPxFor = (w, h) => (Math.max(w, h) / 2) / Math.tan(THREE.MathUtils.deg * ~20Hz tracks hand movement fine and the 1e filter smooths between updates, * while rendering stays at full frame rate. Override: localStorage 'nbx.detectHz'. */ const DETECT_HZ = parseFloat(localStorage.getItem('nbx.detectHz')) || 20; + +/* Long-edge resolution of the detection canvas. At 960 a 60mm crest filling the + * usual framing already gets ~23px per marker cell, well above ArUco's needs — + * so raising this is NOT an obvious cure for crests that fail to decode, and it + * costs CPU roughly linearly (960 -> 1280 is +78% pixels). Exposed as a knob to + * test that empirically rather than assume: localStorage 'nbx.detectLong'. */ +const DETECT_LONG = parseFloat(localStorage.getItem('nbx.detectLong')) || 960; const DETECT_INTERVAL_MS = 1000 / DETECT_HZ; let lastDetectAt = 0; let fps = 0, fpsFrames = 0, fpsAt = 0; @@ -99,7 +106,8 @@ function dbgStatus() { const ws = netRef && netRef.ws ? ['conn','open','closing','closed'][netRef.ws.readyState] : 'none'; return `ws ${ws} rx ${rxLog.join(',') || '-'}\n` + `scene ${sceneLoaded ? anchorCount + ' anchors' : 'NOT LOADED'} ghost recs ${activeGhosts.size}\n` + - `${fps} fps detect ${DETECT_HZ}Hz fov ${camera3 ? camera3.fov.toFixed(0) : '?'}\n`; + `${fps} fps detect ${DETECT_HZ}Hz@${DETECT_LONG} fov ${camera3 ? camera3.fov.toFixed(0) : '?'}` + + `${cvSolver && cvSolver.lastReject ? ' REJ:' + cvSolver.lastReject : ''}\n`; } function paintDbg() { if (dbgEl) dbgEl.textContent = dbgStatus() + dbgPose + dbgAim; } @@ -472,11 +480,11 @@ function loop(t) { if (video && video.readyState >= 2 && (t - lastDetectAt) >= DETECT_INTERVAL_MS) { lastDetectAt = t; - /* Downscale for detection speed, capping the LONG side. Fixing the WIDTH at - * 960 quietly tripled the work on a portrait stream (960x1707 = 1.6M px vs - * 960x540 = 0.5M), which is most of the cost of a frame. */ + /* Downscale for detection, capping the LONG side. Fixing the WIDTH quietly + * tripled the work on a portrait stream (960x1707 vs 960x540), which is most + * of the cost of a frame. */ const vw = video.videoWidth, vh = video.videoHeight; - const LONG = 960; + const LONG = DETECT_LONG; const W = vw >= vh ? LONG : Math.round(LONG * vw / vh); const H = vw >= vh ? Math.round(LONG * vh / vw) : LONG; if (canvas2d.width !== W || canvas2d.height !== H) { canvas2d.width = W; canvas2d.height = H; }