126 lines
3.3 KiB
JavaScript
126 lines
3.3 KiB
JavaScript
import Vector3 from "./Vector3.js";
|
|
|
|
export default class Matrix4 {
|
|
|
|
static lookAt( eye, target, up ) {
|
|
|
|
const zAxis = Vector3.normalize( Vector3.subtract( eye, target ) );
|
|
|
|
const xAxis = Vector3.normalize( Vector3.cross( up, zAxis ) );
|
|
|
|
const yAxis = Vector3.cross( zAxis, xAxis );
|
|
|
|
return new Float32Array([
|
|
xAxis.x, yAxis.x, zAxis.x, 0,
|
|
xAxis.y, yAxis.y, zAxis.y, 0,
|
|
xAxis.z, yAxis.z, zAxis.z, 0,
|
|
-Vector3.dot( xAxis, eye ), -Vector3.dot( yAxis, eye ), -Vector3.dot( zAxis, eye ), 1,
|
|
]);
|
|
}
|
|
|
|
static getColumn( matrix, index ) {
|
|
const i = index * 4;
|
|
|
|
return new Vector3(
|
|
matrix[ i + 0 ],
|
|
matrix[ i + 1 ],
|
|
matrix[ i + 2 ]
|
|
);
|
|
}
|
|
|
|
static createProjectionMatrix( camera, canvas ) {
|
|
return Matrix4.perspective(
|
|
camera.fovRadians,
|
|
canvas.width / canvas.height,
|
|
camera.near,
|
|
camera.far
|
|
);
|
|
}
|
|
|
|
static invert( m ) {
|
|
const out = new Float32Array(16);
|
|
|
|
const m00 = m[0], m01 = m[1], m02 = m[2], m03 = m[3];
|
|
const m10 = m[4], m11 = m[5], m12 = m[6], m13 = m[7];
|
|
const m20 = m[8], m21 = m[9], m22 = m[10], m23 = m[11];
|
|
const m30 = m[12], m31 = m[13], m32 = m[14], m33 = m[15];
|
|
|
|
const a0 = m00 * m11 - m01 * m10;
|
|
const a1 = m00 * m12 - m02 * m10;
|
|
const a2 = m00 * m13 - m03 * m10;
|
|
const a3 = m01 * m12 - m02 * m11;
|
|
const a4 = m01 * m13 - m03 * m11;
|
|
const a5 = m02 * m13 - m03 * m12;
|
|
|
|
const b0 = m20 * m31 - m21 * m30;
|
|
const b1 = m20 * m32 - m22 * m30;
|
|
const b2 = m20 * m33 - m23 * m30;
|
|
const b3 = m21 * m32 - m22 * m31;
|
|
const b4 = m21 * m33 - m23 * m31;
|
|
const b5 = m22 * m33 - m23 * m32;
|
|
|
|
const det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
|
|
|
|
if (det === 0) return null;
|
|
|
|
const invDet = 1 / det;
|
|
|
|
out[0] = ( m11 * b5 - m12 * b4 + m13 * b3) * invDet;
|
|
out[1] = (-m01 * b5 + m02 * b4 - m03 * b3) * invDet;
|
|
out[2] = ( m31 * a5 - m32 * a4 + m33 * a3) * invDet;
|
|
out[3] = (-m21 * a5 + m22 * a4 - m23 * a3) * invDet;
|
|
|
|
out[4] = (-m10 * b5 + m12 * b2 - m13 * b1) * invDet;
|
|
out[5] = ( m00 * b5 - m02 * b2 + m03 * b1) * invDet;
|
|
out[6] = (-m30 * a5 + m32 * a2 - m33 * a1) * invDet;
|
|
out[7] = ( m20 * a5 - m22 * a2 + m23 * a1) * invDet;
|
|
|
|
out[8] = ( m10 * b4 - m11 * b2 + m13 * b0) * invDet;
|
|
out[9] = (-m00 * b4 + m01 * b2 - m03 * b0) * invDet;
|
|
out[10] = ( m30 * a4 - m31 * a2 + m33 * a0) * invDet;
|
|
out[11] = (-m20 * a4 + m21 * a2 - m23 * a0) * invDet;
|
|
|
|
out[12] = (-m10 * b3 + m11 * b1 - m12 * b0) * invDet;
|
|
out[13] = ( m00 * b3 - m01 * b1 + m02 * b0) * invDet;
|
|
out[14] = (-m30 * a3 + m31 * a1 - m32 * a0) * invDet;
|
|
out[15] = ( m20 * a3 - m21 * a1 + m22 * a0) * invDet;
|
|
|
|
return out;
|
|
}
|
|
|
|
static perspective( fovRadians, aspect, near, far ) {
|
|
|
|
const f = 1.0 / Math.tan( fovRadians / 2 );
|
|
|
|
const nf = 1 / ( near - far );
|
|
|
|
return new Float32Array([
|
|
f / aspect, 0, 0, 0,
|
|
0, f, 0, 0,
|
|
0, 0, (far + near) * nf, -1,
|
|
0, 0, (2 * far * near) * nf, 0,
|
|
]);
|
|
}
|
|
|
|
static multiply( a, b ) {
|
|
const out = new Float32Array(16);
|
|
|
|
for ( let col = 0; col < 4; col++ ) {
|
|
for ( let row = 0; row < 4; row++ ) {
|
|
let sum = 0;
|
|
|
|
for ( let k = 0; k < 4; k++ ) {
|
|
// a is column-major: element at col k, row row => a[k*4 + row]
|
|
// b is column-major: element at col col, row k => b[col*4 + k]
|
|
sum += a[k * 4 + row] * b[col * 4 + k];
|
|
}
|
|
|
|
out[col * 4 + row] = sum;
|
|
}
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
}
|