From 41cd51d59052cc256ac5a67c722b4947cef8e282 Mon Sep 17 00:00:00 2001 From: blobt Date: Fri, 16 Apr 2021 16:31:34 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9F=A9=E9=98=B5=E8=BD=AC=E6=8D=A2=E5=BC=80?= =?UTF-8?q?=E5=A7=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/render/math/Mat4.ts | 396 +++++++++++++++++++++++++++++++++++++++ src/render/math/Vec4.ts | 136 ++++++++++++++ src/render/math/index.ts | 3 + 3 files changed, 535 insertions(+) create mode 100755 src/render/math/Mat4.ts create mode 100755 src/render/math/Vec4.ts create mode 100755 src/render/math/index.ts diff --git a/src/render/math/Mat4.ts b/src/render/math/Mat4.ts new file mode 100755 index 00000000..08e1cf29 --- /dev/null +++ b/src/render/math/Mat4.ts @@ -0,0 +1,396 @@ +import { EPSILON } from "../common"; +import { vec3, vec4 } from "."; + +export class mat4 { + + public values = new Float32Array(16); + + public constructor(values: number[] | null = null) { + if (values) { + this.set(values); + } + else { + this.setIdentity(); + } + } + + public set(values: number[]): mat4 { + for (let i = 0; i < 16; i++) { + this.values[i] = values[i]; + } + + return this; + } + + public at(index: number): number { + return this.values[index]; + } + + /** + * 复制当前矩阵到目标矩阵 + * @param dest + * @returns + */ + public copy(dest: mat4 | null = null): mat4 { + if (!dest) dest = new mat4(); + + for (let i = 0; i < 16; i++) { + dest.values[i] = this.values[i]; + } + + return dest; + } + + /** + * 判断矩阵是否相等 + * @param matrix + * @param threshold + * @returns + */ + public equals(matrix: mat4, threshold = EPSILON): boolean { + for (let i = 0; i < 16; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) + return false; + } + + return true; + } + + /** + * 获取一行 + * @param index + * @param dest + * @returns + */ + public getRow(index: number, dest: vec4 | null = null): vec4 { + if (dest === null) { + dest = new vec4(); + } + dest.x = this.values[index * 4 + 0], + dest.y = this.values[index * 4 + 1], + dest.z = this.values[index * 4 + 2], + dest.w = this.values[index * 4 + 3] + return dest; + } + + /** + * 获取一列 + * @param index + * @param dest + * @returns + */ + public getColumn(index: number, dest: vec4 | null = null): vec4 { + if (dest === null) { + dest = new vec4(); + } + dest.x = this.values[index]; + dest.y = this.values[index + 4]; + dest.z = this.values[index + 8]; + dest.w = this.values[index + 12]; + return dest; + } + + /** + * + * @param dest + * @returns + */ + public getPosition(dest: vec3 | null = null): vec3 { + if (dest === null) { + dest = new vec3(); + } + dest.x = this.values[12]; + dest.y = this.values[13]; + dest.z = this.values[14]; + return dest; + } + + /** + * 获取x轴 + * @param dest + * @returns + */ + public getXAxis(dest: vec3 | null = null): vec3 { + if (dest === null) { + dest = new vec3(); + } + dest.x = this.values[0]; + dest.y = this.values[1]; + dest.z = this.values[2]; + return dest; + } + + /** + * 获取y轴 + * @param dest + * @returns + */ + public getYAxis(dest: vec3 | null = null): vec3 { + if (dest === null) { + dest = new vec3(); + } + dest.x = this.values[4]; + dest.y = this.values[5]; + dest.z = this.values[6]; + return dest; + } + + /** + * 获取z轴 + * @param dest + * @returns + */ + public getZAxis(dest: vec3 | null = null): vec3 { + if (dest === null) { + dest = new vec3(); + } + dest.x = this.values[8]; + dest.y = this.values[9]; + dest.z = this.values[10]; + return dest; + } + + /** + * + * @param idx + * @param dest + * @returns + */ + public getAxis(idx: number, dest: vec3 | null = null): vec3 { + if (idx === 0) { + return this.getXAxis(dest); + } else if (idx === 1) { + return this.getYAxis(dest); + } else { + return this.getZAxis(dest); + } + } + + /** + * 设置成单位矩阵 + * @returns + */ + public setIdentity(): mat4 { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 0; + this.values[4] = 0; + this.values[5] = 1; + this.values[6] = 0; + this.values[7] = 0; + this.values[8] = 0; + this.values[9] = 0; + this.values[10] = 1; + this.values[11] = 0; + this.values[12] = 0; + this.values[13] = 0; + this.values[14] = 0; + this.values[15] = 1; + + return this; + } + + /** + * 转置 + * @returns + */ + public transpose(): mat4 { + let temp01 = this.values[1], temp02 = this.values[2], + temp03 = this.values[3], temp12 = this.values[6], + temp13 = this.values[7], temp23 = this.values[11]; + + this.values[1] = this.values[4]; + this.values[2] = this.values[8]; + this.values[3] = this.values[12]; + this.values[4] = temp01; + + this.values[6] = this.values[9]; + this.values[7] = this.values[13]; + this.values[8] = temp02; + this.values[9] = temp12; + this.values[11] = this.values[14]; + this.values[12] = temp03; + this.values[13] = temp13; + this.values[14] = temp23; + + return this; + } + + /** + * 获取矩阵行列式 + * @returns + */ + public determinant(): number { + let a00 = this.values[0], a01 = this.values[1], a02 = this.values[2], a03 = this.values[3], + a10 = this.values[4], a11 = this.values[5], a12 = this.values[6], a13 = this.values[7], + a20 = this.values[8], a21 = this.values[9], a22 = this.values[10], a23 = this.values[11], + a30 = this.values[12], a31 = this.values[13], a32 = this.values[14], a33 = this.values[15]; + + let det00 = a00 * a11 - a01 * a10, + det01 = a00 * a12 - a02 * a10, + det02 = a00 * a13 - a03 * a10, + det03 = a01 * a12 - a02 * a11, + det04 = a01 * a13 - a03 * a11, + det05 = a02 * a13 - a03 * a12, + det06 = a20 * a31 - a21 * a30, + det07 = a20 * a32 - a22 * a30, + det08 = a20 * a33 - a23 * a30, + det09 = a21 * a32 - a22 * a31, + det10 = a21 * a33 - a23 * a31, + det11 = a22 * a33 - a23 * a32; + + return (det00 * det11 - det01 * det10 + det02 * det09 + det03 * det08 - det04 * det07 + det05 * det06); + } + + public det(): number { + return this.determinant(); + } + + /** + * 逆矩阵 + * @param out + * @returns + */ + public inverse(out: mat4): boolean { + this.copy(out); + let a00 = out.values[0], a01 = out.values[1], a02 = out.values[2], a03 = out.values[3], + a10 = out.values[4], a11 = out.values[5], a12 = out.values[6], a13 = out.values[7], + a20 = out.values[8], a21 = out.values[9], a22 = out.values[10], a23 = out.values[11], + a30 = out.values[12], a31 = out.values[13], a32 = out.values[14], a33 = out.values[15]; + + let det00 = a00 * a11 - a01 * a10, + det01 = a00 * a12 - a02 * a10, + det02 = a00 * a13 - a03 * a10, + det03 = a01 * a12 - a02 * a11, + det04 = a01 * a13 - a03 * a11, + det05 = a02 * a13 - a03 * a12, + det06 = a20 * a31 - a21 * a30, + det07 = a20 * a32 - a22 * a30, + det08 = a20 * a33 - a23 * a30, + det09 = a21 * a32 - a22 * a31, + det10 = a21 * a33 - a23 * a31, + det11 = a22 * a33 - a23 * a32; + + let det = (det00 * det11 - det01 * det10 + det02 * det09 + det03 * det08 - det04 * det07 + det05 * det06); + + if (!det) + return false; + + det = 1.0 / det; + + out.values[0] = (a11 * det11 - a12 * det10 + a13 * det09) * det; + out.values[1] = (-a01 * det11 + a02 * det10 - a03 * det09) * det; + out.values[2] = (a31 * det05 - a32 * det04 + a33 * det03) * det; + out.values[3] = (-a21 * det05 + a22 * det04 - a23 * det03) * det; + out.values[4] = (-a10 * det11 + a12 * det08 - a13 * det07) * det; + out.values[5] = (a00 * det11 - a02 * det08 + a03 * det07) * det; + out.values[6] = (-a30 * det05 + a32 * det02 - a33 * det01) * det; + out.values[7] = (a20 * det05 - a22 * det02 + a23 * det01) * det; + out.values[8] = (a10 * det10 - a11 * det08 + a13 * det06) * det; + out.values[9] = (-a00 * det10 + a01 * det08 - a03 * det06) * det; + out.values[10] = (a30 * det04 - a31 * det02 + a33 * det00) * det; + out.values[11] = (-a20 * det04 + a21 * det02 - a23 * det00) * det; + out.values[12] = (-a10 * det09 + a11 * det07 - a12 * det06) * det; + out.values[13] = (a00 * det09 - a01 * det07 + a02 * det06) * det; + out.values[14] = (-a30 * det03 + a31 * det01 - a32 * det00) * det; + out.values[15] = (a20 * det03 - a21 * det01 + a22 * det00) * det; + + return true; + } + + /** + * 矩阵相乘 + * @param matrix + * @returns + */ + public multiply(matrix: mat4): mat4 { + let a00 = this.values[0], a01 = this.values[1], a02 = this.values[2], a03 = this.values[3]; + let a10 = this.values[4], a11 = this.values[5], a12 = this.values[6], a13 = this.values[7]; + let a20 = this.values[8], a21 = this.values[9], a22 = this.values[10], a23 = this.values[11]; + let a30 = this.values[12], a31 = this.values[13], a32 = this.values[14], a33 = this.values[15]; + + let b0 = matrix.at(0), + b1 = matrix.at(1), + b2 = matrix.at(2), + b3 = matrix.at(3); + + this.values[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = matrix.at(4); + b1 = matrix.at(5); + b2 = matrix.at(6); + b3 = matrix.at(7); + + this.values[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = matrix.at(8); + b1 = matrix.at(9); + b2 = matrix.at(10); + b3 = matrix.at(11); + + this.values[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = matrix.at(12); + b1 = matrix.at(13); + b2 = matrix.at(14); + b3 = matrix.at(15); + + this.values[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + return this; + } + + /** + * 矩阵乘以3维度向量 + * @param vector + * @param dest + * @returns + */ + public multiplyVec3(vector: vec3, dest: vec3 | null = null): vec3 { + if (!dest) dest = new vec3(); + let x = vector.x, + y = vector.y, + z = vector.z; + + dest.x = this.values[0] * x + this.values[4] * y + this.values[8] * z + this.values[12]; + dest.y = this.values[1] * x + this.values[5] * y + this.values[9] * z + this.values[13]; + dest.z = this.values[2] * x + this.values[6] * y + this.values[10] * z + this.values[14]; + + return dest; + } + + /** + * 矩阵乘4维向量 + * @param vector + * @param dest + * @returns + */ + public multiplyVec4(vector: vec4, dest: vec4 | null = null): vec4 { + if (!dest) dest = new vec4(); + + let x = vector.x, + y = vector.y, + z = vector.z, + w = vector.w; + + dest.x = this.values[0] * x + this.values[4] * y + this.values[8] * z + this.values[12] * w; + dest.y = this.values[1] * x + this.values[5] * y + this.values[9] * z + this.values[13] * w; + dest.z = this.values[2] * x + this.values[6] * y + this.values[10] * z + this.values[14] * w; + dest.w = this.values[3] * x + this.values[7] * y + this.values[11] * z + this.values[15] * w; + + return dest; + } +} \ No newline at end of file diff --git a/src/render/math/Vec4.ts b/src/render/math/Vec4.ts new file mode 100755 index 00000000..0cef892d --- /dev/null +++ b/src/render/math/Vec4.ts @@ -0,0 +1,136 @@ +import { EPSILON } from "../common"; +import { vec3 } from "./Vec3"; + +export class vec4 { + + public values = new Float32Array(4); + + public get x(): number { + return this.values[0]; + } + + public get y(): number { + return this.values[1]; + } + + public get z(): number { + return this.values[2]; + } + + public get w(): number { + return this.values[3]; + } + + public set x(value: number) { + this.values[0] = value; + } + + public set y(value: number) { + this.values[1] = value; + } + + public set z(value: number) { + this.values[2] = value; + } + + public set w(value: number) { + this.values[3] = value; + } + + public get vec3(): vec3 { + return new vec3([this.x, this.y, this.z]); + } + + /** + * RGBA + */ + public get r(): number { + return this.values[0]; + } + + public get g(): number { + return this.values[1]; + } + + public get b(): number { + return this.values[2]; + } + + public get a(): number { + return this.values[3]; + } + + public set r(value: number) { + this.values[0] = value; + } + + public set g(value: number) { + this.values[1] = value; + } + + public set b(value: number) { + this.values[2] = value; + } + + public set a(value: number) { + this.values[3] = value; + } + + public constructor(values: number[] | null = null) { + if (values) { + this.x = values[0]; + this.y = values[1]; + this.z = values[2]; + this.w = values[3]; + } else { + this.x = this.y = this.z = this.w = 0.0; + } + } + + public at(index: number): number { + return this.values[index]; + } + + public reset(): void { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 0; + } + + public copy(dest: vec4 | null = null): vec4 { + if (!dest) dest = new vec4(); + + dest.x = this.x; + dest.y = this.y; + dest.z = this.z; + dest.w = this.w; + + return dest; + } + + public equals(vector: vec4, threshold = EPSILON): boolean { + if (Math.abs(this.x - vector.x) > threshold) + return false; + + if (Math.abs(this.y - vector.y) > threshold) + return false; + + if (Math.abs(this.z - vector.z) > threshold) + return false; + + if (Math.abs(this.w - vector.w) > threshold) + return false; + + return true; + } + + static red: vec4 = new vec4([1.0, 0.0, 0.0, 1.0]); + static green: vec4 = new vec4([0.0, 1.0, 0.0, 1.0]); + static blue: vec4 = new vec4([0.0, 0.0, 1.0, 1.0]); + static black: vec4 = new vec4([0, 0, 0, 0]); + + static v0: vec4 = new vec4(); + static v1: vec4 = new vec4(); + static v2: vec4 = new vec4(); +} \ No newline at end of file diff --git a/src/render/math/index.ts b/src/render/math/index.ts new file mode 100755 index 00000000..5e0c2a5c --- /dev/null +++ b/src/render/math/index.ts @@ -0,0 +1,3 @@ +export * from './Vec2'; +export * from './Vec3'; +export * from './Vec4'; \ No newline at end of file