UNPKG

rabbit-ear

Version:
194 lines (190 loc) 8.31 kB
/* Rabbit Ear 0.9.4 alpha 2024-04-20 (c) Kraft, GNU GPLv3 License */ import { EPSILON } from './constant.js'; import { resize, normalize, normalize3, subtract3, cross3 } from './vector.js'; import { makeMatrix2Reflect } from './matrix2.js'; const identity4x4 = Object.freeze([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); const isIdentity4x4 = m => identity4x4 .map((n, i) => Math.abs(n - m[i]) < EPSILON) .reduce((a, b) => a && b, true); const multiplyMatrix4Vector3 = (m, vector) => [ m[0] * vector[0] + m[4] * vector[1] + m[8] * vector[2] + m[12], m[1] * vector[0] + m[5] * vector[1] + m[9] * vector[2] + m[13], m[2] * vector[0] + m[6] * vector[1] + m[10] * vector[2] + m[14], ]; const multiplyMatrix4Line3 = (m, vector, origin) => ({ vector: [ m[0] * vector[0] + m[4] * vector[1] + m[8] * vector[2], m[1] * vector[0] + m[5] * vector[1] + m[9] * vector[2], m[2] * vector[0] + m[6] * vector[1] + m[10] * vector[2], ], origin: [ m[0] * origin[0] + m[4] * origin[1] + m[8] * origin[2] + m[12], m[1] * origin[0] + m[5] * origin[1] + m[9] * origin[2] + m[13], m[2] * origin[0] + m[6] * origin[1] + m[10] * origin[2] + m[14], ], }); const multiplyMatrices4 = (m1, m2) => [ m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3], m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3], m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3], m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3], m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7], m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7], m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7], m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7], m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11], m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11], m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11], m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11], m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15], m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15], m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15], m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15], ]; const determinant4 = (m) => { const A2323 = m[10] * m[15] - m[11] * m[14]; const A1323 = m[9] * m[15] - m[11] * m[13]; const A1223 = m[9] * m[14] - m[10] * m[13]; const A0323 = m[8] * m[15] - m[11] * m[12]; const A0223 = m[8] * m[14] - m[10] * m[12]; const A0123 = m[8] * m[13] - m[9] * m[12]; return ( m[0] * (m[5] * A2323 - m[6] * A1323 + m[7] * A1223) - m[1] * (m[4] * A2323 - m[6] * A0323 + m[7] * A0223) + m[2] * (m[4] * A1323 - m[5] * A0323 + m[7] * A0123) - m[3] * (m[4] * A1223 - m[5] * A0223 + m[6] * A0123) ); }; const invertMatrix4 = (m) => { const det = determinant4(m); if (Math.abs(det) < 1e-12 || Number.isNaN(det) || !Number.isFinite(m[12]) || !Number.isFinite(m[13]) || !Number.isFinite(m[14])) { return undefined; } const A2323 = m[10] * m[15] - m[11] * m[14]; const A1323 = m[9] * m[15] - m[11] * m[13]; const A1223 = m[9] * m[14] - m[10] * m[13]; const A0323 = m[8] * m[15] - m[11] * m[12]; const A0223 = m[8] * m[14] - m[10] * m[12]; const A0123 = m[8] * m[13] - m[9] * m[12]; const A2313 = m[6] * m[15] - m[7] * m[14]; const A1313 = m[5] * m[15] - m[7] * m[13]; const A1213 = m[5] * m[14] - m[6] * m[13]; const A2312 = m[6] * m[11] - m[7] * m[10]; const A1312 = m[5] * m[11] - m[7] * m[9]; const A1212 = m[5] * m[10] - m[6] * m[9]; const A0313 = m[4] * m[15] - m[7] * m[12]; const A0213 = m[4] * m[14] - m[6] * m[12]; const A0312 = m[4] * m[11] - m[7] * m[8]; const A0212 = m[4] * m[10] - m[6] * m[8]; const A0113 = m[4] * m[13] - m[5] * m[12]; const A0112 = m[4] * m[9] - m[5] * m[8]; const inv = [ +(m[5] * A2323 - m[6] * A1323 + m[7] * A1223), -(m[1] * A2323 - m[2] * A1323 + m[3] * A1223), +(m[1] * A2313 - m[2] * A1313 + m[3] * A1213), -(m[1] * A2312 - m[2] * A1312 + m[3] * A1212), -(m[4] * A2323 - m[6] * A0323 + m[7] * A0223), +(m[0] * A2323 - m[2] * A0323 + m[3] * A0223), -(m[0] * A2313 - m[2] * A0313 + m[3] * A0213), +(m[0] * A2312 - m[2] * A0312 + m[3] * A0212), +(m[4] * A1323 - m[5] * A0323 + m[7] * A0123), -(m[0] * A1323 - m[1] * A0323 + m[3] * A0123), +(m[0] * A1313 - m[1] * A0313 + m[3] * A0113), -(m[0] * A1312 - m[1] * A0312 + m[3] * A0112), -(m[4] * A1223 - m[5] * A0223 + m[6] * A0123), +(m[0] * A1223 - m[1] * A0223 + m[2] * A0123), -(m[0] * A1213 - m[1] * A0213 + m[2] * A0113), +(m[0] * A1212 - m[1] * A0212 + m[2] * A0112), ]; const invDet = 1.0 / det; return inv.map(n => n * invDet); }; const identity4x3 = Object.freeze([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]); const makeMatrix4Translate = (x = 0, y = 0, z = 0) => [...identity4x3, x, y, z, 1]; const singleAxisRotate4 = (angle, origin, i0, i1, sgn) => { const cos = Math.cos(angle); const sin = Math.sin(angle); const rotate = [...identity4x4]; rotate[i0 * 4 + i0] = cos; rotate[i0 * 4 + i1] = (sgn ? +1 : -1) * sin; rotate[i1 * 4 + i0] = (sgn ? -1 : +1) * sin; rotate[i1 * 4 + i1] = cos; const origin3 = [0, 1, 2].map(i => origin[i] || 0); const trans = [...identity4x4]; const trans_inv = [...identity4x4]; [12, 13, 14].forEach((i, j) => { trans[i] = -origin3[j]; trans_inv[i] = origin3[j]; }); return multiplyMatrices4(trans_inv, multiplyMatrices4(rotate, trans)); }; const makeMatrix4RotateX = (angle, origin = [0, 0, 0]) => ( singleAxisRotate4(angle, origin, 1, 2, true)); const makeMatrix4RotateY = (angle, origin = [0, 0, 0]) => ( singleAxisRotate4(angle, origin, 0, 2, false)); const makeMatrix4RotateZ = (angle, origin = [0, 0, 0]) => ( singleAxisRotate4(angle, origin, 0, 1, true)); const makeMatrix4Rotate = (angle, vector = [0, 0, 1], origin = [0, 0, 0]) => { const pos = [0, 1, 2].map(i => origin[i] || 0); const [x, y, z] = resize(3, normalize(vector)); const c = Math.cos(angle); const s = Math.sin(angle); const t = 1 - c; const trans = makeMatrix4Translate(-pos[0], -pos[1], -pos[2]); const trans_inv = makeMatrix4Translate(pos[0], pos[1], pos[2]); return multiplyMatrices4(trans_inv, multiplyMatrices4([ t * x * x + c, t * y * x + z * s, t * z * x - y * s, 0, t * x * y - z * s, t * y * y + c, t * z * y + x * s, 0, t * x * z + y * s, t * y * z - x * s, t * z * z + c, 0, 0, 0, 0, 1], trans)); }; const makeMatrix4Scale = (scale = [1, 1, 1], origin = [0, 0, 0]) => [ scale[0], 0, 0, 0, 0, scale[1], 0, 0, 0, 0, scale[2], 0, scale[0] * -origin[0] + origin[0], scale[1] * -origin[1] + origin[1], scale[2] * -origin[2] + origin[2], 1, ]; const makeMatrix4UniformScale = (scale = 1, origin = [0, 0, 0]) => ( makeMatrix4Scale([scale, scale, scale], origin) ); const makeMatrix4ReflectZ = (vector, origin = [0, 0]) => { const m = makeMatrix2Reflect(vector, origin); return [m[0], m[1], 0, 0, m[2], m[3], 0, 0, 0, 0, 1, 0, m[4], m[5], 0, 1]; }; const makePerspectiveMatrix4 = (FOV, aspect, near, far) => { const f = Math.tan(Math.PI * 0.5 - 0.5 * FOV); const rangeInv = 1.0 / (near - far); const x = aspect < 1 ? f : f / aspect; const y = aspect < 1 ? f * aspect : f; return [ x, 0, 0, 0, 0, y, 0, 0, 0, 0, (near + far) * rangeInv, -1, 0, 0, near * far * rangeInv * 2, 0, ]; }; const makeOrthographicMatrix4 = (top, right, bottom, left, near, far) => [ 2 / (right - left), 0, 0, 0, 0, 2 / (top - bottom), 0, 0, 0, 0, 2 / (near - far), 0, (left + right) / (left - right), (bottom + top) / (bottom - top), (near + far) / (near - far), 1, ]; const makeLookAtMatrix4 = (position, target, up) => { const zAxis = normalize3(subtract3(position, target)); const xAxis = normalize3(cross3(up, zAxis)); const yAxis = normalize3(cross3(zAxis, xAxis)); return [ xAxis[0], xAxis[1], xAxis[2], 0, yAxis[0], yAxis[1], yAxis[2], 0, zAxis[0], zAxis[1], zAxis[2], 0, position[0], position[1], position[2], 1, ]; }; export { determinant4, identity4x4, invertMatrix4, isIdentity4x4, makeLookAtMatrix4, makeMatrix4ReflectZ, makeMatrix4Rotate, makeMatrix4RotateX, makeMatrix4RotateY, makeMatrix4RotateZ, makeMatrix4Scale, makeMatrix4Translate, makeMatrix4UniformScale, makeOrthographicMatrix4, makePerspectiveMatrix4, multiplyMatrices4, multiplyMatrix4Line3, multiplyMatrix4Vector3 };