From acf1e58f7af67771d76511c11b8a32ac2f8387de Mon Sep 17 00:00:00 2001 From: jessikitty Date: Mon, 3 Aug 2026 23:31:51 +1000 Subject: [PATCH] Fix residual roll inversion: CV->GL camera conversion is 180 about local Y, not X --- public/js/exhibit.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/public/js/exhibit.js b/public/js/exhibit.js index 75b301e..54a9164 100644 --- a/public/js/exhibit.js +++ b/public/js/exhibit.js @@ -16,12 +16,13 @@ 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); + * OpenGL convention (+X right, +Y UP, looks down LOCAL -Z). The correct change of + * basis between them is a 180° rotation about the camera's local Y axis: it flips + * the forward axis (+Z_cv view -> three.js -Z) AND the up axis (+Y_cv down -> + * three.js +Y up) together, leaving roll correct. (A 180° about X fixes the view + * axis too but leaves roll inverted — ghosts render upside-down when the phone is + * upright.) Applied after copying the fused quaternion each frame. */ +const CV_TO_GL = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI); let info = { mode: 'dev' }; let scene3, camera3, renderer, video, canvas2d, ctx2d;