/** A class representing a 4x4 float matrix */
Lore.Matrix4f = class Matrix4f {
// Do NOT go double precision on GPUs!!!
// See:
// http://stackoverflow.com/questions/2079906/float-vs-double-on-graphics-hardware
/**
* Creates an instance of Matrix4f.
* @param {Float32Array} [entries=new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])]
*/
constructor(entries = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
this.entries = entries;
}
/**
*
*
* @param {Number} m00 A matrix entry.
* @param {Number} m10 A matrix entry.
* @param {Number} m20 A matrix entry.
* @param {Number} m30 A matrix entry.
* @param {Number} m01 A matrix entry.
* @param {Number} m11 A matrix entry.
* @param {Number} m21 A matrix entry.
* @param {Number} m31 A matrix entry.
* @param {Number} m02 A matrix entry.
* @param {Number} m12 A matrix entry.
* @param {Number} m22 A matrix entry.
* @param {Number} m32 A matrix entry.
* @param {Number} m03 A matrix entry.
* @param {Number} m13 A matrix entry.
* @param {Number} m23 A matrix entry.
* @param {Number} m33 A matrix entry.
* @returns {Matrix4f} Returns itself.
*/
set(m00, m10, m20, m30, m01, m11, m21, m31, m02, m12, m22, m32, m03, m13, m23, m33) {
this.entries.set([m00, m10, m20, m30,
m01, m11, m21, m31,
m02, m12, m22, m32,
m03, m13, m23, m33
]);
return this;
}
/**
* Multiplies this matrix with another matrix (a * b).
*
* @param {any} b Another matrix.
* @returns {Matrix4f} Returns itself.
*/
multiplyA(b) {
// First, store the values in local variables.
// See:
// http://blog.tojicode.com/2010/06/stupidly-fast-webgl-matricies.html
let a00 = this.entries[0],
a01 = this.entries[4],
a02 = this.entries[8],
a03 = this.entries[12];
let a10 = this.entries[1],
a11 = this.entries[5],
a12 = this.entries[9],
a13 = this.entries[13];
let a20 = this.entries[2],
a21 = this.entries[6],
a22 = this.entries[10],
a23 = this.entries[14];
let a30 = this.entries[3],
a31 = this.entries[7],
a32 = this.entries[11],
a33 = this.entries[15];
let b00 = b.entries[0],
b01 = b.entries[4],
b02 = b.entries[8],
b03 = b.entries[12];
let b10 = b.entries[1],
b11 = b.entries[5],
b12 = b.entries[9],
b13 = b.entries[13];
let b20 = b.entries[2],
b21 = b.entries[6],
b22 = b.entries[10],
b23 = b.entries[14];
let b30 = b.entries[3],
b31 = b.entries[7],
b32 = b.entries[11],
b33 = b.entries[15];
this.entries[0] = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30;
this.entries[1] = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30;
this.entries[2] = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30;
this.entries[3] = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31;
this.entries[4] = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30;
this.entries[5] = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31;
this.entries[6] = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31;
this.entries[7] = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31;
this.entries[8] = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32;
this.entries[9] = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32;
this.entries[10] = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32;
this.entries[11] = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32;
this.entries[12] = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33;
this.entries[13] = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33;
this.entries[14] = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33;
this.entries[15] = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33;
return this;
}
/**
* Multiplies another matrix with this matrix (a * b).
*
* @param {any} a Another matrix.
* @returns {Matrix4f} Returns itself.
*/
multiplyB(a) {
// First, store the values in local variables.
// See:
// http://blog.tojicode.com/2010/06/stupidly-fast-webgl-matricies.html
let a00 = a.entries[0],
a01 = a.entries[4],
a02 = a.entries[8],
a03 = a.entries[12];
let a10 = a.entries[1],
a11 = a.entries[5],
a12 = a.entries[9],
a13 = a.entries[13];
let a20 = a.entries[2],
a21 = a.entries[6],
a22 = a.entries[10],
a23 = a.entries[14];
let a30 = a.entries[3],
a31 = a.entries[7],
a32 = a.entries[11],
a33 = a.entries[15];
let b00 = this.entries[0],
b01 = this.entries[4],
b02 = this.entries[8],
b03 = this.entries[12];
let b10 = this.entries[1],
b11 = this.entries[5],
b12 = this.entries[9],
b13 = this.entries[13];
let b20 = this.entries[2],
b21 = this.entries[6],
b22 = this.entries[10],
b23 = this.entries[14];
let b30 = this.entries[3],
b31 = this.entries[7],
b32 = this.entries[11],
b33 = this.entries[15];
this.entries[0] = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30;
this.entries[1] = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30;
this.entries[2] = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30;
this.entries[3] = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31;
this.entries[4] = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30;
this.entries[5] = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31;
this.entries[6] = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31;
this.entries[7] = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31;
this.entries[8] = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32;
this.entries[9] = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32;
this.entries[10] = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32;
this.entries[11] = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32;
this.entries[12] = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33;
this.entries[13] = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33;
this.entries[14] = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33;
this.entries[15] = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33;
return this;
}
/**
* Set the scale component of this matrix.
*
* @param {Vector3f} v The scaling vector.
* @returns {Matrix4f} Returns itself.
*/
scale(vec) {
let x = vec.components[0];
let y = vec.components[1];
let z = vec.components[2];
this.entries[0] *= x;
this.entries[1] *= x;
this.entries[2] *= x;
this.entries[3] *= x;
this.entries[4] *= y;
this.entries[5] *= y;
this.entries[6] *= y;
this.entries[7] *= y;
this.entries[8] *= z;
this.entries[9] *= z;
this.entries[10] *= z;
this.entries[11] *= z;
return this;
}
/**
* Set the position component of this matrix.
*
* @param {any} vec The position vector.
* @returns {Matrix4f} Returns itself.
*/
setPosition(vec) {
this.entries[12] = vec.components[0];
this.entries[13] = vec.components[1];
this.entries[14] = vec.components[2];
return this;
}
/**
* Set the rotation component of this matrix.
*
* @param {Quaternion} q A quaternion representing the rotation.
* @returns {Matrix4f} Returns itself.
*/
setRotation(q) {
let x = q.components[0];
let y = q.components[1];
let z = q.components[2];
let w = q.components[3];
let x2 = x + x,
y2 = y + y,
z2 = z + z;
let xx = x * x2,
xy = x * y2,
xz = x * z2;
let yy = y * y2,
yz = y * z2,
zz = z * z2;
let wx = w * x2,
wy = w * y2,
wz = w * z2;
this.entries[0] = 1 - (yy + zz);
this.entries[1] = xy + wz;
this.entries[2] = xz - wy;
this.entries[4] = xy - wz;
this.entries[5] = 1 - (xx + zz);
this.entries[6] = yz + wx;
this.entries[8] = xz + wy;
this.entries[9] = yz - wx;
this.entries[10] = 1 - (xx + yy);
this.entries[3] = 0.0;
this.entries[7] = 0.0;
this.entries[11] = 0.0;
this.entries[12] = 0.0;
this.entries[13] = 0.0;
this.entries[14] = 0.0;
this.entries[15] = 1.0;
return this;
}
/**
* Get the determinant of the matrix.
*
* @returns {Number} The determinant of this matrix.
*/
determinant() {
let a00 = a.entries[0],
a01 = a.entries[4],
a02 = a.entries[8],
a03 = a.entries[12];
let a10 = a.entries[1],
a11 = a.entries[5],
a12 = a.entries[9],
a13 = a.entries[13];
let a20 = a.entries[2],
a21 = a.entries[6],
a22 = a.entries[10],
a23 = a.entries[14];
let a30 = a.entries[3],
a31 = a.entries[7],
a32 = a.entries[11],
a33 = a.entries[15];
return (
a30 * (
a03 * a12 * a21 - a02 * a13 * a21 -
a03 * a11 * a22 + a01 * a13 * a22 +
a02 * a11 * a23 - a01 * a12 * a23
) +
a31 * (
a00 * a12 * a23 - a00 * a13 * a22 +
a03 * a10 * a22 - a02 * a10 * a23 +
a02 * a13 * a20 - a03 * a12 * a20
) +
a32 * (
a00 * a13 * a21 - a00 * a11 * a23 -
a03 * a10 * a21 + a01 * a10 * a23 +
a03 * a11 * a20 - a01 * a13 * a20
) +
a33 * (-a02 * a11 * a20 - a00 * a12 * a21 +
a00 * a11 * a22 + a02 * a10 * a21 -
a01 * a10 * a22 + a01 * a12 * a20
)
);
}
/**
* Decomposes the matrix into its positional, rotational and scaling component.
*
* @param {Vector3f} outPosition The positional component will be written to this vector.
* @param {Quaternion} outQuaternion The rotational component will be written to this quaternion.
* @param {Vector3f} outScale The scaling component will be written to this vector.
* @returns {Matrix4f} Returns itself.
*/
decompose(outPosition, outQuaternion, outScale) {
let v = new Lore.Vector3f();
let m = new Lore.Matrix4f();
// The position is the simple one
position.set(this.entries[12], this.entries[13], this.entries[14]);
// Calculate the scale
let sx = Math.sqrt(this.entries[0] * this.entries[0] +
this.entries[1] * this.entries[1] +
this.entries[2] * this.entries[2]);
let sy = Math.sqrt(this.entries[4] * this.entries[4] +
this.entries[5] * this.entries[5] +
this.entries[6] * this.entries[6]);
let sz = Math.sqrt(this.entries[8] * this.entries[8] +
this.entries[9] * this.entries[9] +
this.entries[10] * this.entries[10]);
let det = this.determinant();
if (det < 0) {
sx = -sx;
}
// Set the scale
outScale.set(sx, sy, sz);
// Get the info for the quaternion, this involves scaling the rotation
// See:
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
let isx = 1.0 / sx;
let isy = 1.0 / sy;
let isz = 1.0 / sz;
m.entries.set(this.entries);
m.entries[0] *= isx;
m.entries[1] *= isx;
m.entries[2] *= isx;
m.entries[4] *= isy;
m.entries[5] *= isy;
m.entries[6] *= isy;
m.entries[8] *= isz;
m.entries[9] *= isz;
m.entries[10] *= isz;
outQuaternion.setFromMatrix(m);
return this;
}
/**
* Composes the matrix from the positional, rotational and scaling components.
*
* @param {Vector3f} position The positional component.
* @param {Quaternion} quaternion The rotational component.
* @param {Vector3f} scale The scaling component.
* @returns {Matrix4f} Returns itself.
*/
compose(position, quaternion, scale) {
this.setRotation(quaternion);
this.scale(scale);
this.setPosition(position);
return this;
}
/**
* Inverts this matrix.
*
* @returns {Matrix4f} Returns itself.
*/
invert() {
// Fugly implementation lifted from MESA (originally in C++)
let im = new Lore.Matrix4f();
let m = this.entries;
im.entries[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
im.entries[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
im.entries[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
im.entries[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
im.entries[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
im.entries[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
im.entries[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
im.entries[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
im.entries[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
im.entries[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
im.entries[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
im.entries[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
im.entries[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
im.entries[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
im.entries[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
im.entries[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
let det = m[0] * im.entries[0] +
m[1] * im.entries[4] +
m[2] * im.entries[8] +
m[3] * im.entries[12];
if (det == 0) {
throw 'Determinant is zero.';
}
det = 1.0 / det;
for (let i = 0; i < 16; i++) {
this.entries[i] = im.entries[i] * det;
}
return this;
}
/**
* Clones this matrix.
*
* @returns {Matrix4f} A clone of the matrix.
*/
clone() {
return new Lore.Matrix4f(new Float32Array(this.entries));
}
/**
* Checks whether or not the entries of the two matrices match.
*
* @param {Matrix4f} a A matrix.
* @returns {Boolean} A boolean indicating whether or not the entries of the two matrices match.
*/
equals(a) {
for (let i = 0; i < this.entries.length; i++) {
if (this.entries[i] !== a.entries[i]) return false;
}
return true;
}
/**
* Returns a string representation of the matrix.
*
* @returns {String} The string representation of this matrix.
*/
toString() {
let str = this.entries[0] + ', ' + this.entries[4] + ', ' + this.entries[8] + ', ' + this.entries[12] + '\n';
str += this.entries[1] + ', ' + this.entries[5] + ', ' + this.entries[9] + ', ' + this.entries[13] + '\n';
str += this.entries[2] + ', ' + this.entries[6] + ', ' + this.entries[10] + ', ' + this.entries[14] + '\n';
str += this.entries[3] + ', ' + this.entries[7] + ', ' + this.entries[11] + ', ' + this.entries[15] + '\n';
return str;
}
/**
* Multiply the two matrices (a * b).
*
* @static
* @param {any} a A matrix to be multiplied.
* @param {any} b A matrix to be multiplied.
* @returns {Matrix4f} A matrix.
*/
static multiply(a, b) {
// First, store the values in local variables.
// See:
// http://blog.tojicode.com/2010/06/stupidly-fast-webgl-matricies.html
let a00 = a.entries[0],
a01 = a.entries[4],
a02 = a.entries[8],
a03 = a.entries[12];
let a10 = a.entries[1],
a11 = a.entries[5],
a12 = a.entries[9],
a13 = a.entries[13];
let a20 = a.entries[2],
a21 = a.entries[6],
a22 = a.entries[10],
a23 = a.entries[14];
let a30 = a.entries[3],
a31 = a.entries[7],
a32 = a.entries[11],
a33 = a.entries[15];
let b00 = b.entries[0],
b01 = b.entries[4],
b02 = b.entries[8],
b03 = b.entries[12];
let b10 = b.entries[1],
b11 = b.entries[5],
b12 = b.entries[9],
b13 = b.entries[13];
let b20 = b.entries[2],
b21 = b.entries[6],
b22 = b.entries[10],
b23 = b.entries[14];
let b30 = b.entries[3],
b31 = b.entries[7],
b32 = b.entries[11],
b33 = b.entries[15];
return new Lore.Matrix4f(new Float32Array([
a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30,
a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30,
a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30,
a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30,
a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31,
a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31,
a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31,
a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31,
a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32,
a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32,
a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32,
a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32,
a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33,
a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33,
a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33,
a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33
]));
}
/**
* Initialize a matrix from a quaternion.
*
* @static
* @param {Quaternion} q A quaternion.
* @returns {Matrix4f} A matrix.
*/
static fromQuaternion(q) {
// First, store the values in local variables.
// See:
// http://blog.tojicode.com/2010/06/stupidly-fast-webgl-matricies.html
// https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix
let x = q.components[0],
y = q.components[1],
z = q.components[2],
w = q.components[3];
let x2 = x + x,
y2 = y + y,
z2 = z + z;
let xx = x * x2,
xy = x * y2,
xz = x * z2;
let yy = y * y2,
yz = y * z2,
zz = z * z2;
let wx = w * x2,
wy = w * y2,
wz = w * z2;
return new Lore.Matrix4f(new Float32Array([
1 - (yy + zz), xy + wz, xz - wy, 0,
xy - wz, 1 - (xx + zz), yz + wx, 0,
xz + wy, yz - wx, 1 - (xx + yy), 0,
0, 0, 0, 1
]));
}
/**
* Create a lookat matrix for a camera.
*
* @static
* @param {Vector3f} cameraPosition The position of the camera.
* @param {Vector3f} target The lookat (target) of the camera.
* @param {Vector3f} up The up vector of the camera node.
* @returns {Matrix4f} A matrix.
*/
static lookAt(cameraPosition, target, up) {
// See here in order to return a quaternion directly:
// http://www.euclideanspace.com/maths/algebra/vectors/lookat/
let z = Lore.Vector3f.subtract(cameraPosition, target).normalize();
if (z.lengthSq() === 0.0) {
z.components[2] = 1.0
}
let x = Lore.Vector3f.cross(up, z).normalize();
if (x.lengthSq() === 0.0) {
z.components[2] += 0.0001;
x = Lore.Vector3f.cross(up, z).normalize();
}
let y = Lore.Vector3f.cross(z, x);
return new Lore.Matrix4f(new Float32Array([
x.components[0], x.components[1], x.components[2], 0,
y.components[0], y.components[1], y.components[2], 0,
z.components[0], z.components[1], z.components[2], 0,
0, 0, 0, 1
]));
}
/**
* Composes a matrix from the positional, rotational and scaling components.
*
* @param {Vector3f} position The positional component.
* @param {Quaternion} quaternion The rotational component.
* @param {Vector3f} scale The scaling component.
* @returns {Matrix4f} A matrix.
*/
static compose(position, quaternion, scale) {
let m = new Lore.Matrix4f();
m.setRotation(quaternion);
m.scale(scale);
m.setPosition(position);
return m;
}
/**
* Inverts a matrix.
*
* @static
* @param {Matrix4f} matrix A matrix to be inverted.
* @returns The inverted matrix.
*/
static invert(matrix) {
// Fugly implementation lifted from MESA (originally in C++)
let im = new Lore.Matrix4f();
let m = matrix.entries;
im.entries[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
im.entries[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
im.entries[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
im.entries[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
im.entries[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
im.entries[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
im.entries[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
im.entries[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
im.entries[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
im.entries[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
im.entries[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
im.entries[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
im.entries[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
im.entries[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
im.entries[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
im.entries[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
let det = m[0] * im.entries[0] +
m[1] * im.entries[4] +
m[2] * im.entries[8] +
m[3] * im.entries[12];
if (det == 0) {
throw 'Determinant is zero.';
}
det = 1.0 / det;
for (let i = 0; i < 16; i++) {
im.entries[i] = im.entries[i] * det;
}
return im;
}
}