1055 lines
26 KiB
JavaScript
Executable File
1055 lines
26 KiB
JavaScript
Executable File
import * as vec3 from './Vec3Func.js';
|
|
|
|
const EPSILON = 0.000001;
|
|
|
|
/**
|
|
* Copy the values from one mat4 to another
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the source matrix
|
|
* @returns {mat4} out
|
|
*/
|
|
export function copy(out, a) {
|
|
out[0] = a[0];
|
|
out[1] = a[1];
|
|
out[2] = a[2];
|
|
out[3] = a[3];
|
|
out[4] = a[4];
|
|
out[5] = a[5];
|
|
out[6] = a[6];
|
|
out[7] = a[7];
|
|
out[8] = a[8];
|
|
out[9] = a[9];
|
|
out[10] = a[10];
|
|
out[11] = a[11];
|
|
out[12] = a[12];
|
|
out[13] = a[13];
|
|
out[14] = a[14];
|
|
out[15] = a[15];
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Set the components of a mat4 to the given values
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @returns {mat4} out
|
|
*/
|
|
export function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
|
|
out[0] = m00;
|
|
out[1] = m01;
|
|
out[2] = m02;
|
|
out[3] = m03;
|
|
out[4] = m10;
|
|
out[5] = m11;
|
|
out[6] = m12;
|
|
out[7] = m13;
|
|
out[8] = m20;
|
|
out[9] = m21;
|
|
out[10] = m22;
|
|
out[11] = m23;
|
|
out[12] = m30;
|
|
out[13] = m31;
|
|
out[14] = m32;
|
|
out[15] = m33;
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Set a mat4 to the identity matrix
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @returns {mat4} out
|
|
*/
|
|
export function identity(out) {
|
|
out[0] = 1;
|
|
out[1] = 0;
|
|
out[2] = 0;
|
|
out[3] = 0;
|
|
out[4] = 0;
|
|
out[5] = 1;
|
|
out[6] = 0;
|
|
out[7] = 0;
|
|
out[8] = 0;
|
|
out[9] = 0;
|
|
out[10] = 1;
|
|
out[11] = 0;
|
|
out[12] = 0;
|
|
out[13] = 0;
|
|
out[14] = 0;
|
|
out[15] = 1;
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Transpose the values of a mat4
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the source matrix
|
|
* @returns {mat4} out
|
|
*/
|
|
export function transpose(out, a) {
|
|
// If we are transposing ourselves we can skip a few steps but have to cache some values
|
|
if (out === a) {
|
|
let a01 = a[1],
|
|
a02 = a[2],
|
|
a03 = a[3];
|
|
let a12 = a[6],
|
|
a13 = a[7];
|
|
let a23 = a[11];
|
|
|
|
out[1] = a[4];
|
|
out[2] = a[8];
|
|
out[3] = a[12];
|
|
out[4] = a01;
|
|
out[6] = a[9];
|
|
out[7] = a[13];
|
|
out[8] = a02;
|
|
out[9] = a12;
|
|
out[11] = a[14];
|
|
out[12] = a03;
|
|
out[13] = a13;
|
|
out[14] = a23;
|
|
} else {
|
|
out[0] = a[0];
|
|
out[1] = a[4];
|
|
out[2] = a[8];
|
|
out[3] = a[12];
|
|
out[4] = a[1];
|
|
out[5] = a[5];
|
|
out[6] = a[9];
|
|
out[7] = a[13];
|
|
out[8] = a[2];
|
|
out[9] = a[6];
|
|
out[10] = a[10];
|
|
out[11] = a[14];
|
|
out[12] = a[3];
|
|
out[13] = a[7];
|
|
out[14] = a[11];
|
|
out[15] = a[15];
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Inverts a mat4
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the source matrix
|
|
* @returns {mat4} out
|
|
*/
|
|
export function invert(out, a) {
|
|
let a00 = a[0],
|
|
a01 = a[1],
|
|
a02 = a[2],
|
|
a03 = a[3];
|
|
let a10 = a[4],
|
|
a11 = a[5],
|
|
a12 = a[6],
|
|
a13 = a[7];
|
|
let a20 = a[8],
|
|
a21 = a[9],
|
|
a22 = a[10],
|
|
a23 = a[11];
|
|
let a30 = a[12],
|
|
a31 = a[13],
|
|
a32 = a[14],
|
|
a33 = a[15];
|
|
|
|
let b00 = a00 * a11 - a01 * a10;
|
|
let b01 = a00 * a12 - a02 * a10;
|
|
let b02 = a00 * a13 - a03 * a10;
|
|
let b03 = a01 * a12 - a02 * a11;
|
|
let b04 = a01 * a13 - a03 * a11;
|
|
let b05 = a02 * a13 - a03 * a12;
|
|
let b06 = a20 * a31 - a21 * a30;
|
|
let b07 = a20 * a32 - a22 * a30;
|
|
let b08 = a20 * a33 - a23 * a30;
|
|
let b09 = a21 * a32 - a22 * a31;
|
|
let b10 = a21 * a33 - a23 * a31;
|
|
let b11 = a22 * a33 - a23 * a32;
|
|
|
|
// Calculate the determinant
|
|
let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
|
|
|
if (!det) {
|
|
return null;
|
|
}
|
|
det = 1.0 / det;
|
|
|
|
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
|
|
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
|
|
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
|
|
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
|
|
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
|
|
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
|
|
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
|
|
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
|
|
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
|
|
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
|
|
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
|
|
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
|
|
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
|
|
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
|
|
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
|
|
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
|
|
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Calculates the determinant of a mat4
|
|
*
|
|
* @param {mat4} a the source matrix
|
|
* @returns {Number} determinant of a
|
|
*/
|
|
export function determinant(a) {
|
|
let a00 = a[0],
|
|
a01 = a[1],
|
|
a02 = a[2],
|
|
a03 = a[3];
|
|
let a10 = a[4],
|
|
a11 = a[5],
|
|
a12 = a[6],
|
|
a13 = a[7];
|
|
let a20 = a[8],
|
|
a21 = a[9],
|
|
a22 = a[10],
|
|
a23 = a[11];
|
|
let a30 = a[12],
|
|
a31 = a[13],
|
|
a32 = a[14],
|
|
a33 = a[15];
|
|
|
|
let b00 = a00 * a11 - a01 * a10;
|
|
let b01 = a00 * a12 - a02 * a10;
|
|
let b02 = a00 * a13 - a03 * a10;
|
|
let b03 = a01 * a12 - a02 * a11;
|
|
let b04 = a01 * a13 - a03 * a11;
|
|
let b05 = a02 * a13 - a03 * a12;
|
|
let b06 = a20 * a31 - a21 * a30;
|
|
let b07 = a20 * a32 - a22 * a30;
|
|
let b08 = a20 * a33 - a23 * a30;
|
|
let b09 = a21 * a32 - a22 * a31;
|
|
let b10 = a21 * a33 - a23 * a31;
|
|
let b11 = a22 * a33 - a23 * a32;
|
|
|
|
// Calculate the determinant
|
|
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
|
}
|
|
|
|
/**
|
|
* Multiplies two mat4s
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the first operand
|
|
* @param {mat4} b the second operand
|
|
* @returns {mat4} out
|
|
*/
|
|
export function multiply(out, a, b) {
|
|
let a00 = a[0],
|
|
a01 = a[1],
|
|
a02 = a[2],
|
|
a03 = a[3];
|
|
let a10 = a[4],
|
|
a11 = a[5],
|
|
a12 = a[6],
|
|
a13 = a[7];
|
|
let a20 = a[8],
|
|
a21 = a[9],
|
|
a22 = a[10],
|
|
a23 = a[11];
|
|
let a30 = a[12],
|
|
a31 = a[13],
|
|
a32 = a[14],
|
|
a33 = a[15];
|
|
|
|
// Cache only the current line of the second matrix
|
|
let b0 = b[0],
|
|
b1 = b[1],
|
|
b2 = b[2],
|
|
b3 = b[3];
|
|
out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
|
|
out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
|
|
out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
|
|
out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
|
|
|
|
b0 = b[4];
|
|
b1 = b[5];
|
|
b2 = b[6];
|
|
b3 = b[7];
|
|
out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
|
|
out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
|
|
out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
|
|
out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
|
|
|
|
b0 = b[8];
|
|
b1 = b[9];
|
|
b2 = b[10];
|
|
b3 = b[11];
|
|
out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
|
|
out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
|
|
out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
|
|
out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
|
|
|
|
b0 = b[12];
|
|
b1 = b[13];
|
|
b2 = b[14];
|
|
b3 = b[15];
|
|
out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
|
|
out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
|
|
out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
|
|
out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Translate a mat4 by the given vector
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the matrix to translate
|
|
* @param {vec3} v vector to translate by
|
|
* @returns {mat4} out
|
|
*/
|
|
export function translate(out, a, v) {
|
|
let x = v[0],
|
|
y = v[1],
|
|
z = v[2];
|
|
let a00, a01, a02, a03;
|
|
let a10, a11, a12, a13;
|
|
let a20, a21, a22, a23;
|
|
|
|
if (a === out) {
|
|
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
|
|
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
|
|
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
|
|
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
|
|
} else {
|
|
a00 = a[0];
|
|
a01 = a[1];
|
|
a02 = a[2];
|
|
a03 = a[3];
|
|
a10 = a[4];
|
|
a11 = a[5];
|
|
a12 = a[6];
|
|
a13 = a[7];
|
|
a20 = a[8];
|
|
a21 = a[9];
|
|
a22 = a[10];
|
|
a23 = a[11];
|
|
|
|
out[0] = a00;
|
|
out[1] = a01;
|
|
out[2] = a02;
|
|
out[3] = a03;
|
|
out[4] = a10;
|
|
out[5] = a11;
|
|
out[6] = a12;
|
|
out[7] = a13;
|
|
out[8] = a20;
|
|
out[9] = a21;
|
|
out[10] = a22;
|
|
out[11] = a23;
|
|
|
|
out[12] = a00 * x + a10 * y + a20 * z + a[12];
|
|
out[13] = a01 * x + a11 * y + a21 * z + a[13];
|
|
out[14] = a02 * x + a12 * y + a22 * z + a[14];
|
|
out[15] = a03 * x + a13 * y + a23 * z + a[15];
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Scales the mat4 by the dimensions in the given vec3 not using vectorization
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the matrix to scale
|
|
* @param {vec3} v the vec3 to scale the matrix by
|
|
* @returns {mat4} out
|
|
**/
|
|
export function scale(out, a, v) {
|
|
let x = v[0],
|
|
y = v[1],
|
|
z = v[2];
|
|
|
|
out[0] = a[0] * x;
|
|
out[1] = a[1] * x;
|
|
out[2] = a[2] * x;
|
|
out[3] = a[3] * x;
|
|
out[4] = a[4] * y;
|
|
out[5] = a[5] * y;
|
|
out[6] = a[6] * y;
|
|
out[7] = a[7] * y;
|
|
out[8] = a[8] * z;
|
|
out[9] = a[9] * z;
|
|
out[10] = a[10] * z;
|
|
out[11] = a[11] * z;
|
|
out[12] = a[12];
|
|
out[13] = a[13];
|
|
out[14] = a[14];
|
|
out[15] = a[15];
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Rotates a mat4 by the given angle around the given axis
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the matrix to rotate
|
|
* @param {Number} rad the angle to rotate the matrix by
|
|
* @param {vec3} axis the axis to rotate around
|
|
* @returns {mat4} out
|
|
*/
|
|
export function rotate(out, a, rad, axis) {
|
|
let x = axis[0],
|
|
y = axis[1],
|
|
z = axis[2];
|
|
let len = Math.hypot(x, y, z);
|
|
let s, c, t;
|
|
let a00, a01, a02, a03;
|
|
let a10, a11, a12, a13;
|
|
let a20, a21, a22, a23;
|
|
let b00, b01, b02;
|
|
let b10, b11, b12;
|
|
let b20, b21, b22;
|
|
|
|
if (Math.abs(len) < EPSILON) {
|
|
return null;
|
|
}
|
|
|
|
len = 1 / len;
|
|
x *= len;
|
|
y *= len;
|
|
z *= len;
|
|
|
|
s = Math.sin(rad);
|
|
c = Math.cos(rad);
|
|
t = 1 - c;
|
|
|
|
a00 = a[0];
|
|
a01 = a[1];
|
|
a02 = a[2];
|
|
a03 = a[3];
|
|
a10 = a[4];
|
|
a11 = a[5];
|
|
a12 = a[6];
|
|
a13 = a[7];
|
|
a20 = a[8];
|
|
a21 = a[9];
|
|
a22 = a[10];
|
|
a23 = a[11];
|
|
|
|
// Construct the elements of the rotation matrix
|
|
b00 = x * x * t + c;
|
|
b01 = y * x * t + z * s;
|
|
b02 = z * x * t - y * s;
|
|
b10 = x * y * t - z * s;
|
|
b11 = y * y * t + c;
|
|
b12 = z * y * t + x * s;
|
|
b20 = x * z * t + y * s;
|
|
b21 = y * z * t - x * s;
|
|
b22 = z * z * t + c;
|
|
|
|
// Perform rotation-specific matrix multiplication
|
|
out[0] = a00 * b00 + a10 * b01 + a20 * b02;
|
|
out[1] = a01 * b00 + a11 * b01 + a21 * b02;
|
|
out[2] = a02 * b00 + a12 * b01 + a22 * b02;
|
|
out[3] = a03 * b00 + a13 * b01 + a23 * b02;
|
|
out[4] = a00 * b10 + a10 * b11 + a20 * b12;
|
|
out[5] = a01 * b10 + a11 * b11 + a21 * b12;
|
|
out[6] = a02 * b10 + a12 * b11 + a22 * b12;
|
|
out[7] = a03 * b10 + a13 * b11 + a23 * b12;
|
|
out[8] = a00 * b20 + a10 * b21 + a20 * b22;
|
|
out[9] = a01 * b20 + a11 * b21 + a21 * b22;
|
|
out[10] = a02 * b20 + a12 * b21 + a22 * b22;
|
|
out[11] = a03 * b20 + a13 * b21 + a23 * b22;
|
|
|
|
if (a !== out) {
|
|
// If the source and destination differ, copy the unchanged last row
|
|
out[12] = a[12];
|
|
out[13] = a[13];
|
|
out[14] = a[14];
|
|
out[15] = a[15];
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Returns the translation vector component of a transformation
|
|
* matrix. If a matrix is built with fromRotationTranslation,
|
|
* the returned vector will be the same as the translation vector
|
|
* originally supplied.
|
|
* @param {vec3} out Vector to receive translation component
|
|
* @param {mat4} mat Matrix to be decomposed (input)
|
|
* @return {vec3} out
|
|
*/
|
|
export function getTranslation(out, mat) {
|
|
out[0] = mat[12];
|
|
out[1] = mat[13];
|
|
out[2] = mat[14];
|
|
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Returns the scaling factor component of a transformation
|
|
* matrix. If a matrix is built with fromRotationTranslationScale
|
|
* with a normalized Quaternion paramter, the returned vector will be
|
|
* the same as the scaling vector
|
|
* originally supplied.
|
|
* @param {vec3} out Vector to receive scaling factor component
|
|
* @param {mat4} mat Matrix to be decomposed (input)
|
|
* @return {vec3} out
|
|
*/
|
|
export function getScaling(out, mat) {
|
|
let m11 = mat[0];
|
|
let m12 = mat[1];
|
|
let m13 = mat[2];
|
|
let m21 = mat[4];
|
|
let m22 = mat[5];
|
|
let m23 = mat[6];
|
|
let m31 = mat[8];
|
|
let m32 = mat[9];
|
|
let m33 = mat[10];
|
|
|
|
out[0] = Math.hypot(m11, m12, m13);
|
|
out[1] = Math.hypot(m21, m22, m23);
|
|
out[2] = Math.hypot(m31, m32, m33);
|
|
|
|
return out;
|
|
}
|
|
|
|
export function getMaxScaleOnAxis(mat) {
|
|
let m11 = mat[0];
|
|
let m12 = mat[1];
|
|
let m13 = mat[2];
|
|
let m21 = mat[4];
|
|
let m22 = mat[5];
|
|
let m23 = mat[6];
|
|
let m31 = mat[8];
|
|
let m32 = mat[9];
|
|
let m33 = mat[10];
|
|
|
|
const x = m11 * m11 + m12 * m12 + m13 * m13;
|
|
const y = m21 * m21 + m22 * m22 + m23 * m23;
|
|
const z = m31 * m31 + m32 * m32 + m33 * m33;
|
|
|
|
return Math.sqrt(Math.max(x, y, z));
|
|
}
|
|
|
|
/**
|
|
* Returns a quaternion representing the rotational component
|
|
* of a transformation matrix. If a matrix is built with
|
|
* fromRotationTranslation, the returned quaternion will be the
|
|
* same as the quaternion originally supplied.
|
|
* @param {quat} out Quaternion to receive the rotation component
|
|
* @param {mat4} mat Matrix to be decomposed (input)
|
|
* @return {quat} out
|
|
*/
|
|
export const getRotation = (function () {
|
|
const temp = [1, 1, 1];
|
|
|
|
return function (out, mat) {
|
|
let scaling = temp;
|
|
getScaling(scaling, mat);
|
|
|
|
let is1 = 1 / scaling[0];
|
|
let is2 = 1 / scaling[1];
|
|
let is3 = 1 / scaling[2];
|
|
|
|
let sm11 = mat[0] * is1;
|
|
let sm12 = mat[1] * is2;
|
|
let sm13 = mat[2] * is3;
|
|
let sm21 = mat[4] * is1;
|
|
let sm22 = mat[5] * is2;
|
|
let sm23 = mat[6] * is3;
|
|
let sm31 = mat[8] * is1;
|
|
let sm32 = mat[9] * is2;
|
|
let sm33 = mat[10] * is3;
|
|
|
|
let trace = sm11 + sm22 + sm33;
|
|
let S = 0;
|
|
|
|
if (trace > 0) {
|
|
S = Math.sqrt(trace + 1.0) * 2;
|
|
out[3] = 0.25 * S;
|
|
out[0] = (sm23 - sm32) / S;
|
|
out[1] = (sm31 - sm13) / S;
|
|
out[2] = (sm12 - sm21) / S;
|
|
} else if (sm11 > sm22 && sm11 > sm33) {
|
|
S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
|
|
out[3] = (sm23 - sm32) / S;
|
|
out[0] = 0.25 * S;
|
|
out[1] = (sm12 + sm21) / S;
|
|
out[2] = (sm31 + sm13) / S;
|
|
} else if (sm22 > sm33) {
|
|
S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
|
|
out[3] = (sm31 - sm13) / S;
|
|
out[0] = (sm12 + sm21) / S;
|
|
out[1] = 0.25 * S;
|
|
out[2] = (sm23 + sm32) / S;
|
|
} else {
|
|
S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
|
|
out[3] = (sm12 - sm21) / S;
|
|
out[0] = (sm31 + sm13) / S;
|
|
out[1] = (sm23 + sm32) / S;
|
|
out[2] = 0.25 * S;
|
|
}
|
|
|
|
return out;
|
|
};
|
|
})();
|
|
|
|
/**
|
|
* From glTF-Transform
|
|
* https://github.com/donmccurdy/glTF-Transform/blob/main/packages/core/src/utils/math-utils.ts
|
|
*
|
|
* Decompose a mat4 to TRS properties.
|
|
*
|
|
* Equivalent to the Matrix4 decompose() method in three.js, and intentionally not using the
|
|
* gl-matrix version. See: https://github.com/toji/gl-matrix/issues/408
|
|
*
|
|
* @param {mat4} srcMat Matrix element, to be decomposed to TRS properties.
|
|
* @param {quat4} dstRotation Rotation element, to be overwritten.
|
|
* @param {vec3} dstTranslation Translation element, to be overwritten.
|
|
* @param {vec3} dstScale Scale element, to be overwritten
|
|
*/
|
|
export function decompose(srcMat, dstRotation, dstTranslation, dstScale) {
|
|
let sx = vec3.length([srcMat[0], srcMat[1], srcMat[2]]);
|
|
const sy = vec3.length([srcMat[4], srcMat[5], srcMat[6]]);
|
|
const sz = vec3.length([srcMat[8], srcMat[9], srcMat[10]]);
|
|
|
|
// if determine is negative, we need to invert one scale
|
|
const det = determinant(srcMat);
|
|
if (det < 0) sx = -sx;
|
|
|
|
dstTranslation[0] = srcMat[12];
|
|
dstTranslation[1] = srcMat[13];
|
|
dstTranslation[2] = srcMat[14];
|
|
|
|
// scale the rotation part
|
|
const _m1 = srcMat.slice();
|
|
|
|
const invSX = 1 / sx;
|
|
const invSY = 1 / sy;
|
|
const invSZ = 1 / sz;
|
|
|
|
_m1[0] *= invSX;
|
|
_m1[1] *= invSX;
|
|
_m1[2] *= invSX;
|
|
|
|
_m1[4] *= invSY;
|
|
_m1[5] *= invSY;
|
|
_m1[6] *= invSY;
|
|
|
|
_m1[8] *= invSZ;
|
|
_m1[9] *= invSZ;
|
|
_m1[10] *= invSZ;
|
|
|
|
getRotation(dstRotation, _m1);
|
|
|
|
dstScale[0] = sx;
|
|
dstScale[1] = sy;
|
|
dstScale[2] = sz;
|
|
}
|
|
|
|
/**
|
|
* From glTF-Transform
|
|
* https://github.com/donmccurdy/glTF-Transform/blob/main/packages/core/src/utils/math-utils.ts
|
|
*
|
|
* Compose TRS properties to a mat4.
|
|
*
|
|
* Equivalent to the Matrix4 compose() method in three.js, and intentionally not using the
|
|
* gl-matrix version. See: https://github.com/toji/gl-matrix/issues/408
|
|
*
|
|
* @param {mat4} dstMat Matrix element, to be modified and returned.
|
|
* @param {quat4} srcRotation Rotation element of matrix.
|
|
* @param {vec3} srcTranslation Translation element of matrix.
|
|
* @param {vec3} srcScale Scale element of matrix.
|
|
* @returns {mat4} dstMat, overwritten to mat4 equivalent of given TRS properties.
|
|
*/
|
|
export function compose(dstMat, srcRotation, srcTranslation, srcScale) {
|
|
const te = dstMat;
|
|
|
|
const x = srcRotation[0],
|
|
y = srcRotation[1],
|
|
z = srcRotation[2],
|
|
w = srcRotation[3];
|
|
const x2 = x + x,
|
|
y2 = y + y,
|
|
z2 = z + z;
|
|
const xx = x * x2,
|
|
xy = x * y2,
|
|
xz = x * z2;
|
|
const yy = y * y2,
|
|
yz = y * z2,
|
|
zz = z * z2;
|
|
const wx = w * x2,
|
|
wy = w * y2,
|
|
wz = w * z2;
|
|
|
|
const sx = srcScale[0],
|
|
sy = srcScale[1],
|
|
sz = srcScale[2];
|
|
|
|
te[0] = (1 - (yy + zz)) * sx;
|
|
te[1] = (xy + wz) * sx;
|
|
te[2] = (xz - wy) * sx;
|
|
te[3] = 0;
|
|
|
|
te[4] = (xy - wz) * sy;
|
|
te[5] = (1 - (xx + zz)) * sy;
|
|
te[6] = (yz + wx) * sy;
|
|
te[7] = 0;
|
|
|
|
te[8] = (xz + wy) * sz;
|
|
te[9] = (yz - wx) * sz;
|
|
te[10] = (1 - (xx + yy)) * sz;
|
|
te[11] = 0;
|
|
|
|
te[12] = srcTranslation[0];
|
|
te[13] = srcTranslation[1];
|
|
te[14] = srcTranslation[2];
|
|
te[15] = 1;
|
|
|
|
return te;
|
|
}
|
|
|
|
/**
|
|
* Creates a matrix from a quaternion rotation, vector translation and vector scale
|
|
* This is equivalent to (but much faster than):
|
|
*
|
|
* mat4.identity(dest);
|
|
* mat4.translate(dest, vec);
|
|
* let quatMat = mat4.create();
|
|
* quat4.toMat4(quat, quatMat);
|
|
* mat4.multiply(dest, quatMat);
|
|
* mat4.scale(dest, scale)
|
|
*
|
|
* @param {mat4} out mat4 receiving operation result
|
|
* @param {quat4} q Rotation quaternion
|
|
* @param {vec3} v Translation vector
|
|
* @param {vec3} s Scaling vector
|
|
* @returns {mat4} out
|
|
*/
|
|
export function fromRotationTranslationScale(out, q, v, s) {
|
|
// Quaternion math
|
|
let x = q[0],
|
|
y = q[1],
|
|
z = q[2],
|
|
w = q[3];
|
|
let x2 = x + x;
|
|
let y2 = y + y;
|
|
let z2 = z + z;
|
|
|
|
let xx = x * x2;
|
|
let xy = x * y2;
|
|
let xz = x * z2;
|
|
let yy = y * y2;
|
|
let yz = y * z2;
|
|
let zz = z * z2;
|
|
let wx = w * x2;
|
|
let wy = w * y2;
|
|
let wz = w * z2;
|
|
let sx = s[0];
|
|
let sy = s[1];
|
|
let sz = s[2];
|
|
|
|
out[0] = (1 - (yy + zz)) * sx;
|
|
out[1] = (xy + wz) * sx;
|
|
out[2] = (xz - wy) * sx;
|
|
out[3] = 0;
|
|
out[4] = (xy - wz) * sy;
|
|
out[5] = (1 - (xx + zz)) * sy;
|
|
out[6] = (yz + wx) * sy;
|
|
out[7] = 0;
|
|
out[8] = (xz + wy) * sz;
|
|
out[9] = (yz - wx) * sz;
|
|
out[10] = (1 - (xx + yy)) * sz;
|
|
out[11] = 0;
|
|
out[12] = v[0];
|
|
out[13] = v[1];
|
|
out[14] = v[2];
|
|
out[15] = 1;
|
|
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Calculates a 4x4 matrix from the given quaternion
|
|
*
|
|
* @param {mat4} out mat4 receiving operation result
|
|
* @param {quat} q Quaternion to create matrix from
|
|
*
|
|
* @returns {mat4} out
|
|
*/
|
|
export function fromQuat(out, q) {
|
|
let x = q[0],
|
|
y = q[1],
|
|
z = q[2],
|
|
w = q[3];
|
|
let x2 = x + x;
|
|
let y2 = y + y;
|
|
let z2 = z + z;
|
|
|
|
let xx = x * x2;
|
|
let yx = y * x2;
|
|
let yy = y * y2;
|
|
let zx = z * x2;
|
|
let zy = z * y2;
|
|
let zz = z * z2;
|
|
let wx = w * x2;
|
|
let wy = w * y2;
|
|
let wz = w * z2;
|
|
|
|
out[0] = 1 - yy - zz;
|
|
out[1] = yx + wz;
|
|
out[2] = zx - wy;
|
|
out[3] = 0;
|
|
|
|
out[4] = yx - wz;
|
|
out[5] = 1 - xx - zz;
|
|
out[6] = zy + wx;
|
|
out[7] = 0;
|
|
|
|
out[8] = zx + wy;
|
|
out[9] = zy - wx;
|
|
out[10] = 1 - xx - yy;
|
|
out[11] = 0;
|
|
|
|
out[12] = 0;
|
|
out[13] = 0;
|
|
out[14] = 0;
|
|
out[15] = 1;
|
|
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Generates a perspective projection matrix with the given bounds
|
|
*
|
|
* @param {mat4} out mat4 frustum matrix will be written into
|
|
* @param {number} fovy Vertical field of view in radians
|
|
* @param {number} aspect Aspect ratio. typically viewport width/height
|
|
* @param {number} near Near bound of the frustum
|
|
* @param {number} far Far bound of the frustum
|
|
* @returns {mat4} out
|
|
*/
|
|
export function perspective(out, fovy, aspect, near, far) {
|
|
let f = 1.0 / Math.tan(fovy / 2);
|
|
let nf = 1 / (near - far);
|
|
out[0] = f / aspect;
|
|
out[1] = 0;
|
|
out[2] = 0;
|
|
out[3] = 0;
|
|
out[4] = 0;
|
|
out[5] = f;
|
|
out[6] = 0;
|
|
out[7] = 0;
|
|
out[8] = 0;
|
|
out[9] = 0;
|
|
out[10] = (far + near) * nf;
|
|
out[11] = -1;
|
|
out[12] = 0;
|
|
out[13] = 0;
|
|
out[14] = 2 * far * near * nf;
|
|
out[15] = 0;
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Generates a orthogonal projection matrix with the given bounds
|
|
*
|
|
* @param {mat4} out mat4 frustum matrix will be written into
|
|
* @param {number} left Left bound of the frustum
|
|
* @param {number} right Right bound of the frustum
|
|
* @param {number} bottom Bottom bound of the frustum
|
|
* @param {number} top Top bound of the frustum
|
|
* @param {number} near Near bound of the frustum
|
|
* @param {number} far Far bound of the frustum
|
|
* @returns {mat4} out
|
|
*/
|
|
export function ortho(out, left, right, bottom, top, near, far) {
|
|
let lr = 1 / (left - right);
|
|
let bt = 1 / (bottom - top);
|
|
let nf = 1 / (near - far);
|
|
out[0] = -2 * lr;
|
|
out[1] = 0;
|
|
out[2] = 0;
|
|
out[3] = 0;
|
|
out[4] = 0;
|
|
out[5] = -2 * bt;
|
|
out[6] = 0;
|
|
out[7] = 0;
|
|
out[8] = 0;
|
|
out[9] = 0;
|
|
out[10] = 2 * nf;
|
|
out[11] = 0;
|
|
out[12] = (left + right) * lr;
|
|
out[13] = (top + bottom) * bt;
|
|
out[14] = (far + near) * nf;
|
|
out[15] = 1;
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Generates a matrix that makes something look at something else.
|
|
*
|
|
* @param {mat4} out mat4 frustum matrix will be written into
|
|
* @param {vec3} eye Position of the viewer
|
|
* @param {vec3} target Point the viewer is looking at
|
|
* @param {vec3} up vec3 pointing up
|
|
* @returns {mat4} out
|
|
*/
|
|
export function targetTo(out, eye, target, up) {
|
|
let eyex = eye[0],
|
|
eyey = eye[1],
|
|
eyez = eye[2],
|
|
upx = up[0],
|
|
upy = up[1],
|
|
upz = up[2];
|
|
|
|
let z0 = eyex - target[0],
|
|
z1 = eyey - target[1],
|
|
z2 = eyez - target[2];
|
|
|
|
let len = z0 * z0 + z1 * z1 + z2 * z2;
|
|
if (len === 0) {
|
|
// eye and target are in the same position
|
|
z2 = 1;
|
|
} else {
|
|
len = 1 / Math.sqrt(len);
|
|
z0 *= len;
|
|
z1 *= len;
|
|
z2 *= len;
|
|
}
|
|
|
|
let x0 = upy * z2 - upz * z1,
|
|
x1 = upz * z0 - upx * z2,
|
|
x2 = upx * z1 - upy * z0;
|
|
|
|
len = x0 * x0 + x1 * x1 + x2 * x2;
|
|
if (len === 0) {
|
|
// up and z are parallel
|
|
if (upz) {
|
|
upx += 1e-6;
|
|
} else if (upy) {
|
|
upz += 1e-6;
|
|
} else {
|
|
upy += 1e-6;
|
|
}
|
|
(x0 = upy * z2 - upz * z1), (x1 = upz * z0 - upx * z2), (x2 = upx * z1 - upy * z0);
|
|
|
|
len = x0 * x0 + x1 * x1 + x2 * x2;
|
|
}
|
|
|
|
len = 1 / Math.sqrt(len);
|
|
x0 *= len;
|
|
x1 *= len;
|
|
x2 *= len;
|
|
|
|
out[0] = x0;
|
|
out[1] = x1;
|
|
out[2] = x2;
|
|
out[3] = 0;
|
|
out[4] = z1 * x2 - z2 * x1;
|
|
out[5] = z2 * x0 - z0 * x2;
|
|
out[6] = z0 * x1 - z1 * x0;
|
|
out[7] = 0;
|
|
out[8] = z0;
|
|
out[9] = z1;
|
|
out[10] = z2;
|
|
out[11] = 0;
|
|
out[12] = eyex;
|
|
out[13] = eyey;
|
|
out[14] = eyez;
|
|
out[15] = 1;
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Adds two mat4's
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the first operand
|
|
* @param {mat4} b the second operand
|
|
* @returns {mat4} out
|
|
*/
|
|
export function add(out, a, b) {
|
|
out[0] = a[0] + b[0];
|
|
out[1] = a[1] + b[1];
|
|
out[2] = a[2] + b[2];
|
|
out[3] = a[3] + b[3];
|
|
out[4] = a[4] + b[4];
|
|
out[5] = a[5] + b[5];
|
|
out[6] = a[6] + b[6];
|
|
out[7] = a[7] + b[7];
|
|
out[8] = a[8] + b[8];
|
|
out[9] = a[9] + b[9];
|
|
out[10] = a[10] + b[10];
|
|
out[11] = a[11] + b[11];
|
|
out[12] = a[12] + b[12];
|
|
out[13] = a[13] + b[13];
|
|
out[14] = a[14] + b[14];
|
|
out[15] = a[15] + b[15];
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Subtracts matrix b from matrix a
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the first operand
|
|
* @param {mat4} b the second operand
|
|
* @returns {mat4} out
|
|
*/
|
|
export function subtract(out, a, b) {
|
|
out[0] = a[0] - b[0];
|
|
out[1] = a[1] - b[1];
|
|
out[2] = a[2] - b[2];
|
|
out[3] = a[3] - b[3];
|
|
out[4] = a[4] - b[4];
|
|
out[5] = a[5] - b[5];
|
|
out[6] = a[6] - b[6];
|
|
out[7] = a[7] - b[7];
|
|
out[8] = a[8] - b[8];
|
|
out[9] = a[9] - b[9];
|
|
out[10] = a[10] - b[10];
|
|
out[11] = a[11] - b[11];
|
|
out[12] = a[12] - b[12];
|
|
out[13] = a[13] - b[13];
|
|
out[14] = a[14] - b[14];
|
|
out[15] = a[15] - b[15];
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Multiply each element of the matrix by a scalar.
|
|
*
|
|
* @param {mat4} out the receiving matrix
|
|
* @param {mat4} a the matrix to scale
|
|
* @param {Number} b amount to scale the matrix's elements by
|
|
* @returns {mat4} out
|
|
*/
|
|
export function multiplyScalar(out, a, b) {
|
|
out[0] = a[0] * b;
|
|
out[1] = a[1] * b;
|
|
out[2] = a[2] * b;
|
|
out[3] = a[3] * b;
|
|
out[4] = a[4] * b;
|
|
out[5] = a[5] * b;
|
|
out[6] = a[6] * b;
|
|
out[7] = a[7] * b;
|
|
out[8] = a[8] * b;
|
|
out[9] = a[9] * b;
|
|
out[10] = a[10] * b;
|
|
out[11] = a[11] * b;
|
|
out[12] = a[12] * b;
|
|
out[13] = a[13] * b;
|
|
out[14] = a[14] * b;
|
|
out[15] = a[15] * b;
|
|
return out;
|
|
}
|