diff --git a/public/js/exhibit.js b/public/js/exhibit.js index 1e5e451..75b301e 100644 --- a/public/js/exhibit.js +++ b/public/js/exhibit.js @@ -13,6 +13,16 @@ import { ExhibitNet, installErrorReporter } from './net.js'; import { renderMarkdown } from './md.js'; const $ = (s) => document.querySelector(s); + +/* The fused pose is a camera-in-world transform in OpenCV convention + * (+X right, +Y DOWN, +Z FORWARD along the view axis). A Three.js camera uses + * OpenGL convention (+X right, +Y UP, looks down LOCAL -Z). The two differ by a + * 180° rotation about the camera's local X axis. Without this the world renders + * upside-down and back-to-front (camera appears inverted) even though the pose + * position and scene orientation are correct. Applied after copying the fused + * quaternion each frame. */ +const CV_TO_GL = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI); + let info = { mode: 'dev' }; let scene3, camera3, renderer, video, canvas2d, ctx2d; let detector, poseEst, fuser; @@ -207,7 +217,8 @@ function loop(t) { const fused = fuser.fuse(estimates); if (fused) { camera3.position.copy(fused.position); - camera3.quaternion.copy(fused.quaternion); + // convert OpenCV camera frame -> Three.js (OpenGL) camera frame + camera3.quaternion.copy(fused.quaternion).multiply(CV_TO_GL); } } }