refactor: extract matrix, moveMapping, easing, cubeProjection utils from SmartCube
This commit is contained in:
133
src/utils/matrix.js
Normal file
133
src/utils/matrix.js
Normal file
@@ -0,0 +1,133 @@
|
||||
// 4x4 matrix operations for 3D transformations (column-major, CSS/WebGL convention)
|
||||
|
||||
export const identityMatrix = () => [
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
];
|
||||
|
||||
export const rotateXMatrix = (deg) => {
|
||||
const rad = (deg * Math.PI) / 180;
|
||||
const c = Math.cos(rad);
|
||||
const s = Math.sin(rad);
|
||||
return [
|
||||
1, 0, 0, 0,
|
||||
0, c, s, 0,
|
||||
0, -s, c, 0,
|
||||
0, 0, 0, 1
|
||||
];
|
||||
};
|
||||
|
||||
export const rotateYMatrix = (deg) => {
|
||||
const rad = (deg * Math.PI) / 180;
|
||||
const c = Math.cos(rad);
|
||||
const s = Math.sin(rad);
|
||||
return [
|
||||
c, 0, -s, 0,
|
||||
0, 1, 0, 0,
|
||||
s, 0, c, 0,
|
||||
0, 0, 0, 1
|
||||
];
|
||||
};
|
||||
|
||||
export const rotateZMatrix = (deg) => {
|
||||
const rad = (deg * Math.PI) / 180;
|
||||
const c = Math.cos(rad);
|
||||
const s = Math.sin(rad);
|
||||
return [
|
||||
c, s, 0, 0,
|
||||
-s, c, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
];
|
||||
};
|
||||
|
||||
export const multiplyMatrices = (a, b) => {
|
||||
const result = new Array(16).fill(0);
|
||||
for (let r = 0; r < 4; r++) {
|
||||
for (let c = 0; c < 4; c++) {
|
||||
for (let k = 0; k < 4; k++) {
|
||||
result[c * 4 + r] += a[k * 4 + r] * b[c * 4 + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// --- Quaternion helpers for distortion-free rotation interpolation (SLERP) ---
|
||||
|
||||
export const matToQuat = (m) => {
|
||||
const trace = m[0] + m[5] + m[10];
|
||||
let w, x, y, z;
|
||||
if (trace > 0) {
|
||||
const s = 0.5 / Math.sqrt(trace + 1);
|
||||
w = 0.25 / s;
|
||||
x = (m[6] - m[9]) * s;
|
||||
y = (m[8] - m[2]) * s;
|
||||
z = (m[1] - m[4]) * s;
|
||||
} else if (m[0] > m[5] && m[0] > m[10]) {
|
||||
const s = 2 * Math.sqrt(1 + m[0] - m[5] - m[10]);
|
||||
w = (m[6] - m[9]) / s;
|
||||
x = 0.25 * s;
|
||||
y = (m[4] + m[1]) / s;
|
||||
z = (m[8] + m[2]) / s;
|
||||
} else if (m[5] > m[10]) {
|
||||
const s = 2 * Math.sqrt(1 + m[5] - m[0] - m[10]);
|
||||
w = (m[8] - m[2]) / s;
|
||||
x = (m[4] + m[1]) / s;
|
||||
y = 0.25 * s;
|
||||
z = (m[6] + m[9]) / s;
|
||||
} else {
|
||||
const s = 2 * Math.sqrt(1 + m[10] - m[0] - m[5]);
|
||||
w = (m[1] - m[4]) / s;
|
||||
x = (m[8] + m[2]) / s;
|
||||
y = (m[6] + m[9]) / s;
|
||||
z = 0.25 * s;
|
||||
}
|
||||
return { w, x, y, z };
|
||||
};
|
||||
|
||||
export const slerp = (q1, q2, t) => {
|
||||
let dot = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
|
||||
let q2n = q2;
|
||||
if (dot < 0) {
|
||||
q2n = { w: -q2.w, x: -q2.x, y: -q2.y, z: -q2.z };
|
||||
dot = -dot;
|
||||
}
|
||||
if (dot > 0.9995) {
|
||||
const len = Math.sqrt(
|
||||
(q1.w + t * (q2n.w - q1.w)) ** 2 + (q1.x + t * (q2n.x - q1.x)) ** 2 +
|
||||
(q1.y + t * (q2n.y - q1.y)) ** 2 + (q1.z + t * (q2n.z - q1.z)) ** 2
|
||||
);
|
||||
return {
|
||||
w: (q1.w + t * (q2n.w - q1.w)) / len,
|
||||
x: (q1.x + t * (q2n.x - q1.x)) / len,
|
||||
y: (q1.y + t * (q2n.y - q1.y)) / len,
|
||||
z: (q1.z + t * (q2n.z - q1.z)) / len,
|
||||
};
|
||||
}
|
||||
const theta = Math.acos(dot);
|
||||
const sinTheta = Math.sin(theta);
|
||||
const a = Math.sin((1 - t) * theta) / sinTheta;
|
||||
const b = Math.sin(t * theta) / sinTheta;
|
||||
return {
|
||||
w: a * q1.w + b * q2n.w,
|
||||
x: a * q1.x + b * q2n.x,
|
||||
y: a * q1.y + b * q2n.y,
|
||||
z: a * q1.z + b * q2n.z,
|
||||
};
|
||||
};
|
||||
|
||||
export const quatToMat = (q) => {
|
||||
const { w, x, y, z } = q;
|
||||
const xx = x * x, yy = y * y, zz = z * z;
|
||||
const xy = x * y, xz = x * z, yz = y * z;
|
||||
const wx = w * x, wy = w * y, wz = w * z;
|
||||
return [
|
||||
1 - 2 * (yy + zz), 2 * (xy + wz), 2 * (xz - wy), 0,
|
||||
2 * (xy - wz), 1 - 2 * (xx + zz), 2 * (yz + wx), 0,
|
||||
2 * (xz + wy), 2 * (yz - wx), 1 - 2 * (xx + yy), 0,
|
||||
0, 0, 0, 1,
|
||||
];
|
||||
};
|
||||
Reference in New Issue
Block a user