diff --git a/VR/client/math/matrix3.js b/VR/client/math/matrix3.js new file mode 100644 index 0000000..e40c9c1 --- /dev/null +++ b/VR/client/math/matrix3.js @@ -0,0 +1,29 @@ +export function identity3x3() { + return [ + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + ]; +} + +export function transpose3x3(rows) { + return [ + [rows[0][0], rows[1][0], rows[2][0]], + [rows[0][1], rows[1][1], rows[2][1]], + [rows[0][2], rows[1][2], rows[2][2]], + ]; +} + +export function multiply3x3(a, b) { + const out = [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + ]; + for (let i = 0; i < 3; i += 1) { + for (let j = 0; j < 3; j += 1) { + out[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j]; + } + } + return out; +} diff --git a/VR/client/math/quaternions.js b/VR/client/math/quaternions.js new file mode 100644 index 0000000..24af53b --- /dev/null +++ b/VR/client/math/quaternions.js @@ -0,0 +1,43 @@ +import * as THREE from "three"; + +import { transpose3x3 } from "./matrix3.js"; + +export function quaternionFromRowwiseDirector(matrixRows) { + const m = new THREE.Matrix4(); + m.set( + matrixRows[0][0], matrixRows[1][0], matrixRows[2][0], 0.0, + matrixRows[0][1], matrixRows[1][1], matrixRows[2][1], 0.0, + matrixRows[0][2], matrixRows[1][2], matrixRows[2][2], 0.0, + 0.0, 0.0, 0.0, 1.0 + ); + return new THREE.Quaternion().setFromRotationMatrix(m); +} + +export function columnwiseDirectorFromQuaternion(quaternion) { + // Convert quaternion to column-wise director for elastica representation. + // Maybe consider using three.js's conversion, but we just want 3x3 orientation. + const x = quaternion.x; + const y = quaternion.y; + const z = quaternion.z; + const w = quaternion.w; + const xx = x * x; + const yy = y * y; + const zz = z * z; + const xy = x * y; + const xz = x * z; + const yz = y * z; + const wx = w * x; + const wy = w * y; + const wz = w * z; + return [ + [1.0 - 2.0 * (yy + zz), 2.0 * (xy - wz), 2.0 * (xz + wy)], + [2.0 * (xy + wz), 1.0 - 2.0 * (xx + zz), 2.0 * (yz - wx)], + [2.0 * (xz - wy), 2.0 * (yz + wx), 1.0 - 2.0 * (xx + yy)], + ]; +} + +export function rowwiseDirectorFromQuaternion(quaternion) { + // Typically quaternion from controller is in world space, + // We need to convert to row-wise director for elastica representation. + return transpose3x3(columnwiseDirectorFromQuaternion(quaternion)); +}