diff --git a/public/js/exhibit.js b/public/js/exhibit.js index a91d552..a8c3db5 100644 --- a/public/js/exhibit.js +++ b/public/js/exhibit.js @@ -69,17 +69,15 @@ function centredCorners(m, w, h) { } // Build the marker->camera matrix (POS-IT), converting js-aruco axes to three.js. -// POS-IT frame is right-handed (X right, Y up, Z toward viewer). To bring the -// full RIGID transform into three.js we must CONJUGATE by F = diag(1,-1,-1): -// M_three = F * M_pose * F -// Premultiplying by F alone flips the translation but leaves the rotation's -// pitch inverted -> "camera up/down moves the ghost the wrong way". The second -// (right) multiply by F fixes the rotation handedness while keeping translation -// correct (F*M*F's translation column is F*t, i.e. flipped exactly once). +// js-aruco POS-IT gives the marker pose in a camera frame with X right, Y up, +// Z toward viewer. Three.js's camera looks down -Z with Y up, so we convert by +// premultiplying F = diag(1,-1,-1) (flip Y and Z). This is the SAME conversion +// the working ar-head.js uses, and it is correct for pitch AND roll: tilting the +// phone up moves an anchored ghost down-screen, and rolling the phone rotates the +// ghost the same way. (An earlier F*M*F "fix" inverted both — don't reintroduce it.) const flipYZ = new THREE.Matrix4().makeScale(1, -1, -1); -// Convert one POS-IT (R,t) solution into a three.js marker->camera matrix via -// the F*M*F conjugation (see note above). +// Convert one POS-IT (R,t) solution into a three.js marker->camera matrix. function poseToMatrix(R, t) { const M = new THREE.Matrix4().set( R[0][0], R[0][1], R[0][2], t[0], @@ -87,8 +85,7 @@ function poseToMatrix(R, t) { R[2][0], R[2][1], R[2][2], t[2], 0, 0, 0, 1 ); - M.premultiply(flipYZ); // F * M - M.multiply(flipYZ); // F * M * F + M.premultiply(flipYZ); // F * M (flip Y & Z: POS-IT frame -> three.js frame) return M; }