573 lines
12 KiB
JavaScript
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);
|
|
} |