cg1-visualisations/public/matrix-math.js

573 lines
12 KiB
JavaScript

"use strict";
/**
* overwrites a 4x4 matrix with the identity matrix
*/
function mat4Identity(mat) {
for (let i = 0; i < 16; i++) {
mat[i] = (i % 5 == 0) ? 1 : 0;
}
}
/**
* copies a mat4 from src to dst
*/
function mat4Copy(src, dst) {
for (let i = 0; i < 16; i++) {
dst[i] = src[i];
}
}
/**
* sets all the values in a mat4 to zero
*/
function mat4Empty(mat) {
for (let i = 0; i < 16; i++) {
mat[i] = 0;
}
}
/**
* mutliplies A with B and stores the result in result
*/
function mat4Multiply(result, A, B) {
// if result is one of the arguments, modify copy instead of result directly
if (result == A || result == B) {
let tempResult = [];
mat4Multiply(tempResult, A, B);
mat4Copy(tempResult, result);
return;
}
// loops over cells of the result matrix
for (let i = 0; i < 16; i++) {
let col = (i / 4) | 0;
let row = i % 4;
// initialise current cell with 0
result[i] = 0;
// loop over the row of A and column of B
// continuously adding the multiplication of the two values to the result cell
for (let j = 0; j < 4; j++) {
result[i] += A[row + j * 4] * B[j + col * 4];
}
}
}
/**
* prints a mat4 to the screen
*/
function mat4Print(m) {
let str = "";
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
str += m[j * 4 + i] + " ";
}
str += "\n";
}
console.log(str);
}
/**
* translates by the vector v
*/
function mat4Translate(out, inm, v) {
let t = [];
mat4Identity(t);
t[12] = v[0];
t[13] = v[1];
t[14] = v[2];
mat4Multiply(out, t, inm);
}
/**
* scales by the vector v
*/
function mat4Scale(out, inm, v) {
let t = [];
mat4Identity(t);
t[0] = v[0];
t[5] = v[1];
t[10] = v[2];
mat4Multiply(out, t, inm);
}
/**
* rotates around the X axis by the angle a (in radians)
*/
function mat4RotateX(out, inm, a) {
let t = [];
mat4Identity(t);
t[5] = Math.cos(a);
t[6] = Math.sin(a);
t[9] = -Math.sin(a);
t[10] = Math.cos(a);
mat4Multiply(out, t, inm);
}
/**
* rotates around the Y axis by the angle a (in radians)
*/
function mat4RotateY(out, inm, a) {
let t = [];
mat4Identity(t);
t[0] = Math.cos(a);
t[2] = -Math.sin(a);
t[8] = Math.sin(a);
t[10] = Math.cos(a);
mat4Multiply(out, t, inm);
}
/**
* rotates around the Z axis by the angle a (in radians)
*/
function mat4RotateZ(out, inm, a) {
let t = [];
mat4Identity(t);
t[0] = Math.cos(a);
t[1] = Math.sin(a);
t[4] = -Math.sin(a);
t[5] = Math.cos(a);
mat4Multiply(out, t, inm);
}
/**
* builds a look-at matrix, overwriting out
* eye is the position of the camera
* look is the position of the target to be looked at
* up is the up vector
*/
function mat4BuildLookAt(out, eye, look, up) {
let n = [];
let u = [];
let v = [];
let t = [];
vec3Subtract(n, eye, look);
vec3CrossProduct(u, up, n);
vec3CrossProduct(v, n, u);
vec3Normalise(n, n);
vec3Normalise(u, u);
vec3Normalise(v, v);
t[0] = - vec3DotProduct(u, eye);
t[1] = - vec3DotProduct(v, eye);
t[2] = - vec3DotProduct(n, eye);
out[0] = u[0]; out[4] = u[1]; out[8] = u[2]; out[12] = t[0];
out[1] = v[0]; out[5] = v[1]; out[9] = v[2]; out[13] = t[1];
out[2] = n[0]; out[6] = n[1]; out[10] = n[2]; out[14] = t[2];
out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1;
}
function mat4BuildLookAt1(out, eye, look, up) {
out[0] = 1; out[4] = 0; out[8] = 0; out[12] = -eye[0];
out[1] = 0; out[5] = 1; out[9] = 0; out[13] = -eye[1];
out[2] = 0; out[6] = 0; out[10] = 1; out[14] = -eye[2];
out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1;
}
function mat4BuildLookAt2(out, eye, look, up) {
let n = [];
let u = [];
let v = [];
vec3Subtract(n, eye, look);
vec3CrossProduct(u, up, n);
vec3CrossProduct(v, n, u);
vec3Normalise(n, n);
vec3Normalise(u, u);
vec3Normalise(v, v);
out[0] = u[0]; out[4] = u[1]; out[8] = u[2]; out[12] = 0;
out[1] = v[0]; out[5] = v[1]; out[9] = v[2]; out[13] = 0;
out[2] = n[0]; out[6] = n[1]; out[10] = n[2]; out[14] = 0;
out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1;
}
/**
* builds a projection matrix, overwriting out
* r, l, t, b are the right, left, top and bottom of the frustum
* n and f are the distance of the near and far planes from the camera
*/
function mat4BuildProjection(out, r, l, t, b, n, f) {
mat4Identity(out);
out[0] = 2.0 / (r - l);
out[5] = 2.0 / (t - b);
out[8] = 1.0 / n * (r + l) / (r - l);
out[9] = 1.0 / n * (t + b) / (t - b);
out[10] = -1.0 / n * (f + n) / (f - n);
out[11] = -1.0 / n;
out[14] = - 2.0 * f / (f - n);
out[15] = 0.0;
}
/**
* builds a perspective projection matrix, overwriting out
* fovy is the field of view in the y direction
* aspect is the aspect ratio
* n and f are the distance of the near and far planes from the camera
*/
function mat4BuildPerspective(out, fovy, aspect, n, f) {
let t = n * Math.tan(0.5 * fovy);
let b = -t;
let r = aspect * t;
let l = -r;
mat4BuildProjection(out, r, l, t, b, n, f);
}
function mat4BuildPerspective1(out, fovy, aspect, n, f) {
mat4Identity(out);
out[10] = 1.0 + f / n;
out[11] = -1.0 / n;
out[14] = f;
out[15] = 0.0;
}
function mat4BuildPerspective2(out, fovy, aspect, n, f) {
let t = n * Math.tan(0.5 * fovy);
let b = -t;
let r = aspect * t;
let l = -r;
mat4Identity(out);
out[12] = -(r + l) / 2.0;
out[13] = -(t + b) / 2.0;
out[14] = (f + n) / 2.0;
}
function mat4BuildPerspective3(out, fovy, aspect, n, f) {
let t = n * Math.tan(0.5 * fovy);
let b = -t;
let r = aspect * t;
let l = -r;
mat4Identity(out);
out[0] = 2.0 / (r - l);
out[5] = 2.0 / (t - b);
out[10] = 2.0 / (f - n);
}
function mat4BuildPerspective4(out, fovy, aspect, n, f) {
mat4Identity(out);
out[10] = -1.0;
}
/**
* linearly interpolates between a and b, storing the result in out
*/
function mat4Interpolate(out, a, b, f) {
for (let i = 0; i < 16; i++) {
out[i] = (1 - f) * a[i] + f * b[i];
}
}
function mat4From3(out, inm) {
mat4Identity(out);
out[0] = inm[0];
out[1] = inm[1];
out[2] = inm[2];
out[4] = inm[3];
out[5] = inm[4];
out[6] = inm[5];
out[8] = inm[6];
out[9] = inm[7];
out[10] = inm[8];
}
/**
* https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
*/
function mat4Inverse(out, m) {
let inv = [];
let det;
let i;
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
inv[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];
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0) {
mat4Copy(m, out); // singular matrix, can't invert
return;
}
det = 1.0 / det;
for (i = 0; i < 16; i++)
out[i] = inv[i] * det;
return;
}
/**
* subtracts b from a, storing the result in out
*/
function vec3Subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
}
/**
* calculates the cross product of a and b, storing the result in out
*/
function vec3CrossProduct(out, a, b) {
let result = [];
result[0] = a[1] * b[2] - a[2] * b[1];
result[1] = a[2] * b[0] - a[0] * b[2];
result[2] = a[0] * b[1] - a[1] * b[0];
out[0] = result[0];
out[1] = result[1];
out[2] = result[2];
}
/**
* normalizes in storing the result in out
*/
function vec3Normalise(out, inv) {
let length = vec3Length(inv);
out[0] = inv[0] / length;
out[1] = inv[1] / length;
out[2] = inv[2] / length;
}
/**
* returns the length of the vector in
*/
function vec3Length(inv) {
return Math.sqrt(inv[0] * inv[0] + inv[1] * inv[1] + inv[2] * inv[2]);
}
/**
* returns the dot product of the vectors a and b
*/
function vec3DotProduct(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
/**
* sets the values of out to x, y and z
*/
function vec3Set(out, x, y, z) {
out[0] = x;
out[1] = y;
out[2] = z;
}
function mat3Copy(src, dst) {
for (let i = 0; i < 9; i++) {
dst[i] = src[i];
}
}
function mat3From4(out, inm) {
out[0] = inm[0];
out[1] = inm[1];
out[2] = inm[2];
out[3] = inm[4];
out[4] = inm[5];
out[5] = inm[6];
out[6] = inm[8];
out[7] = inm[9];
out[8] = inm[10];
}
function mat3Transpose(out, inm) {
let result = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
result[i * 3 + j] = inm[j * 3 + i];
}
}
mat3Copy(result, out);
}
function mat3Minor(out, inm) {
let result = [];
// TODO: check if this is correct
result[0] = inm[4] * inm[8] - inm[5] * inm[7];
result[1] = inm[3] * inm[8] - inm[5] * inm[6];
result[2] = inm[3] * inm[7] - inm[4] * inm[6];
result[3] = inm[1] * inm[8] - inm[2] * inm[7];
result[4] = inm[0] * inm[8] - inm[2] * inm[6];
result[5] = inm[0] * inm[7] - inm[1] * inm[6];
result[6] = inm[1] * inm[5] - inm[2] * inm[4];
result[7] = inm[0] * inm[5] - inm[2] * inm[3];
result[8] = inm[0] * inm[4] - inm[1] * inm[3];
mat3Copy(result, out);
}
function mat3Cofactor(out, inm) {
mat3Minor(out, inm);
out[1] *= -1;
out[3] *= -1;
out[5] *= -1;
out[7] *= -1;
}
function mat3Adjoint(out, inm) {
mat3Cofactor(out, inm);
mat3Transpose(out, inm);
}
function mat3MultiplyScalar(out, inm, x) {
for (let i = 0; i < 9; i++) {
out[i] = inm[i] * x;
}
}
function mat3Determinant(m) {
return + m[0] * m[4] * m[8] + m[3] * m[7] * m[2] + m[6] * m[1] * m[5] - m[2] * m[4] * m[6] - m[5] * m[7] * m[0] - m[8] * m[1] * m[3];
}
function mat3Inverse(out, inm) {
let result = [];
mat3Adjoint(result, inm);
mat3MultiplyScalar(result, result, 1 / mat3Determinant(inm));
mat3Copy(result, out);
}