From 1705875feb0e3eff61ea590bd652520b7523f733 Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Mon, 15 Feb 2021 01:54:53 +0100 Subject: [PATCH] fix: matrix multiplication --- src/matrix2.ts | 28 +++++++++++++++++++++++---- src/matrix3.ts | 20 +++++++++++--------- src/matrix4.ts | 48 ++++++++++++++++------------------------------- src/projection.ts | 42 +++++++++++------------------------------ src/util.ts | 33 +++++++++++++++++++++++++++++--- 5 files changed, 92 insertions(+), 79 deletions(-) diff --git a/src/matrix2.ts b/src/matrix2.ts index 3dcc27f..8f4c9d0 100644 --- a/src/matrix2.ts +++ b/src/matrix2.ts @@ -79,12 +79,32 @@ export class Matrix2 { return this.x.isFinite() && this.y.isFinite(); } + row(n: 0 | 1): Vector2 { + return new Vector2(this[0][n], this[1][n]); + } + + col(n: 0 | 1): Vector2 { + return this[n]; + } + + add(other: Matrix2): Matrix2 { + return new Matrix2( + this[0].add(other[0]), + this[1].add(other[1]), + ); + } + + sub(other: Matrix2): Matrix2 { + return new Matrix2( + this[0].sub(other[0]), + this[1].sub(other[1]), + ); + } + mul(other: Matrix2): Matrix2 { return Matrix2.fromCols( - this.x.dot(other.x), - this.y.dot(other.x), - this.x.dot(other.y), - this.y.dot(other.y), + this.row(0).dot(other[0]), this.row(1).dot(other[0]), + this.row(0).dot(other[1]), this.row(1).dot(other[1]), ); } diff --git a/src/matrix3.ts b/src/matrix3.ts index 2777688..d9860a0 100644 --- a/src/matrix3.ts +++ b/src/matrix3.ts @@ -128,17 +128,19 @@ export class Matrix3 { return this.x.isFinite() && this.y.isFinite() && this.z.isFinite(); } + row(n: 0 | 1 | 2): Vector3 { + return new Vector3(this[0][n], this[1][n], this[2][n]); + } + + col(n: 0 | 1 | 2): Vector3 { + return this[n]; + } + mul(other: Matrix3): Matrix3 { return Matrix3.fromCols( - this.x.dot(other.x), - this.y.dot(other.x), - this.z.dot(other.x), - this.x.dot(other.y), - this.y.dot(other.y), - this.z.dot(other.y), - this.x.dot(other.z), - this.y.dot(other.z), - this.z.dot(other.z), + this.row(0).dot(other[0]), this.row(1).dot(other[0]), this.row(2).dot(other[0]), + this.row(0).dot(other[1]), this.row(1).dot(other[1]), this.row(2).dot(other[1]), + this.row(0).dot(other[2]), this.row(1).dot(other[2]), this.row(2).dot(other[2]), ); } diff --git a/src/matrix4.ts b/src/matrix4.ts index 3c3df36..751dc7e 100644 --- a/src/matrix4.ts +++ b/src/matrix4.ts @@ -169,22 +169,10 @@ export class Matrix4 { const u = s.cross(f); return Matrix4.fromCols( - s.x, - u.x, - -f.x, - 0, - s.y, - u.y, - -f.y, - 0, - s.z, - u.z, - -f.z, - 0, - -eye.dot(s), - -eye.dot(u), - eye.dot(f), - 1, + s.x, u.x, -f.x, 0, + s.y, u.y, -f.y, 0, + s.z, u.z, -f.z, 0, + -eye.dot(s), -eye.dot(u), eye.dot(f), 1, ); } @@ -240,24 +228,20 @@ export class Matrix4 { this.w.isFinite(); } + row(n: 0 | 1 | 2 | 3): Vector4 { + return new Vector4(this[0][n], this[1][n], this[2][n], this[3][n]); + } + + col(n: 0 | 1 | 2 | 3): Vector4 { + return this[n]; + } + mul(other: Matrix4): Matrix4 { return Matrix4.fromCols( - this.x.dot(other.x), - this.y.dot(other.x), - this.z.dot(other.x), - this.w.dot(other.x), - this.x.dot(other.y), - this.y.dot(other.y), - this.z.dot(other.y), - this.w.dot(other.y), - this.x.dot(other.z), - this.y.dot(other.z), - this.z.dot(other.z), - this.w.dot(other.z), - this.x.dot(other.w), - this.y.dot(other.w), - this.z.dot(other.w), - this.w.dot(other.w), + this.row(0).dot(other[0]), this.row(1).dot(other[0]), this.row(2).dot(other[0]), this.row(3).dot(other[0]), + this.row(0).dot(other[1]), this.row(1).dot(other[1]), this.row(2).dot(other[1]), this.row(3).dot(other[1]), + this.row(0).dot(other[2]), this.row(1).dot(other[2]), this.row(2).dot(other[2]), this.row(3).dot(other[2]), + this.row(0).dot(other[3]), this.row(1).dot(other[3]), this.row(2).dot(other[3]), this.row(3).dot(other[3]), ); } diff --git a/src/projection.ts b/src/projection.ts index 04a22c5..7782647 100644 --- a/src/projection.ts +++ b/src/projection.ts @@ -43,49 +43,31 @@ export class Perspective { ); } - const c0r0 = (2 * this.near) / - (this.right - this.left); + const c0r0 = (2 * this.near) / (this.right - this.left); const c0r1 = 0; const c0r2 = 0; const c0r3 = 0; const c1r0 = 0; - const c1r1 = (2 * this.near) / - (this.top - this.bottom); + const c1r1 = (2 * this.near) / (this.top - this.bottom); const c1r2 = 0; const c1r3 = 0; - const c2r0 = (this.right + this.left) / - (this.right - this.left); - const c2r1 = (this.top + this.bottom) / - (this.top - this.bottom); - const c2r2 = -(this.far + this.near) / - (this.far - this.near); + const c2r0 = (this.right + this.left) / (this.right - this.left); + const c2r1 = (this.top + this.bottom) / (this.top - this.bottom); + const c2r2 = -(this.far + this.near) / (this.far - this.near); const c2r3 = -1; const c3r0 = 0; const c3r1 = 0; - const c3r2 = -(2 * this.far * this.near) / - (this.far - this.near); + const c3r2 = -(2 * this.far * this.near) / (this.far - this.near); const c3r3 = 0; return Matrix4.fromCols( - c0r0, - c0r1, - c0r2, - c0r3, - c1r0, - c1r1, - c1r2, - c1r3, - c2r0, - c2r1, - c2r2, - c2r3, - c3r0, - c3r1, - c3r2, - c3r3, + c0r0, c0r1, c0r2, c0r3, + c1r0, c1r1, c1r2, c1r3, + c2r0, c2r1, c2r2, c2r3, + c3r0, c3r1, c3r2, c3r3, ); } } @@ -102,9 +84,7 @@ export class PerspectiveFov { near: number, far: number, ) { - if (fovy instanceof Deg) { - fovy = fovy.toRad(); - } + fovy = fovy.toRad(); this.fovy = fovy; this.aspect = aspect; diff --git a/src/util.ts b/src/util.ts index bc71bb6..f017bac 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,7 +1,9 @@ +export const epsilon = 3.4028235 * 10 ** 38; +// export const epsilon = Number.MAX_VALUE; + export function absDiffEq( x: number, y: number, - epsilon = Number.MIN_VALUE, ): boolean { return (x > y ? x - y : x - y) <= epsilon; } @@ -9,7 +11,32 @@ export function absDiffEq( export function absDiffNe( x: number, y: number, - epsilon = Number.MIN_VALUE, ): boolean { - return !absDiffNe(x, y, epsilon); + return !absDiffNe(x, y); +} + +export function relativeDiff(x: number, y: number): number { + return Math.abs((x - y) / Math.min(x, y)); +} + +export function epsilonDiff(x: number, y: number): number { + return relativeDiff(x, y) / epsilon; +} + +export function f32ToI32(f32: number): number { + return new Int32Array(new Float32Array([f32]).buffer)[0]; +} + +export function ulpsDist(x: number, y: number): number { + if (x === y) return 0; + + if (isNaN(x) || isNaN(y)) return epsilon; + if (!isFinite(x) || !isFinite(y)) return epsilon; + + const ix = f32ToI32(x); + const iy = f32ToI32(y); + + if ((ix < 0) !== (iy < 0)) return epsilon; + + return ix > iy ? ix - iy : iy - ix; }