UNPKG

gpu-curtains

Version:

gpu-curtains is a 3D WebGPU rendering engine. It can be used as a standalone 3D engine, but also includes extra classes focused on mapping 3d objects to DOM elements; It allows users to synchronize values such as position, sizing, or scale between them.

325 lines (324 loc) 9.54 kB
import { Mat4 } from "./Mat4.mjs"; import { Vec2 } from "./Vec2.mjs"; //#region src/math/Mat3.ts /** * Basic 3x3 matrix class used for matrix calculations. * * Note that like three.js, the constructor and {@link set} method take arguments in row-major order, while internally they are stored in the {@link elements} array in column-major order. * * @see https://github.com/mrdoob/three.js/blob/dev/src/math/Matrix3.js * @see http://glmatrix.net/docs/mat3.js.html */ var Mat3 = class Mat3 { /** * Mat3 constructor * @param elements - initial array to use, default to identity matrix */ constructor(elements = new Float32Array([ 1, 0, 0, 0, 1, 0, 0, 0, 1 ])) { this.type = "Mat3"; this.elements = elements; } /** * Sets the matrix from 9 numbers * * @param n11 - number * @param n12 - number * @param n13 - number * @param n21 - number * @param n22 - number * @param n23 - number * @param n31 - number * @param n32 - number * @param n33 - number * @returns - this {@link Mat3} after being set */ set(n11, n12, n13, n21, n22, n23, n31, n32, n33) { const te = this.elements; te[0] = n11; te[1] = n21; te[2] = n31; te[3] = n12; te[4] = n22; te[5] = n32; te[6] = n13; te[7] = n23; te[8] = n33; return this; } /** * Sets the {@link Mat3} to an identity matrix * @returns - this {@link Mat3} after being set */ identity() { this.set(1, 0, 0, 0, 1, 0, 0, 0, 1); return this; } /** * Sets the {@link Mat3} values from an array * @param array - array to use * @param offset - optional offset in the array to use * @returns - this {@link Mat3} after being set */ setFromArray(array = new Float32Array([ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]), offset = 0) { for (let i = 0; i < this.elements.length; i++) this.elements[i] = array[i + offset]; return this; } /** * Copy another {@link Mat3} * @param matrix - matrix to copy * @returns - this {@link Mat3} after being set */ copy(matrix = new Mat3()) { const array = matrix.elements; this.elements[0] = array[0]; this.elements[1] = array[1]; this.elements[2] = array[2]; this.elements[3] = array[3]; this.elements[4] = array[4]; this.elements[5] = array[5]; this.elements[6] = array[6]; this.elements[7] = array[7]; this.elements[8] = array[8]; return this; } /** * Clone a {@link Mat3} * @returns - cloned {@link Mat3} */ clone() { return new Mat3().copy(this); } /** * Set a {@link Mat3} from a {@link Mat4}. * @param matrix - {@link Mat4} to use. * @returns - this {@link Mat3} after being set. */ setFromMat4(matrix = new Mat4()) { const me = matrix.elements; this.set(me[0], me[4], me[8], me[1], me[5], me[9], me[2], me[6], me[10]); return this; } /** * Multiply this {@link Mat3} with another {@link Mat3} * @param matrix - {@link Mat3} to multiply with * @returns - this {@link Mat3} after multiplication */ multiply(matrix = new Mat3()) { return this.multiplyMatrices(this, matrix); } /** * Multiply another {@link Mat3} with this {@link Mat3} * @param matrix - {@link Mat3} to multiply with * @returns - this {@link Mat3} after multiplication */ premultiply(matrix = new Mat3()) { return this.multiplyMatrices(matrix, this); } /** * Multiply two {@link Mat3} * @param a - first {@link Mat3} * @param b - second {@link Mat3} * @returns - {@link Mat3} resulting from the multiplication */ multiplyMatrices(a = new Mat3(), b = new Mat3()) { const ae = a.elements; const be = b.elements; const te = this.elements; const a11 = ae[0], a12 = ae[3], a13 = ae[6]; const a21 = ae[1], a22 = ae[4], a23 = ae[7]; const a31 = ae[2], a32 = ae[5], a33 = ae[8]; const b11 = be[0], b12 = be[3], b13 = be[6]; const b21 = be[1], b22 = be[4], b23 = be[7]; const b31 = be[2], b32 = be[5], b33 = be[8]; te[0] = a11 * b11 + a12 * b21 + a13 * b31; te[3] = a11 * b12 + a12 * b22 + a13 * b32; te[6] = a11 * b13 + a12 * b23 + a13 * b33; te[1] = a21 * b11 + a22 * b21 + a23 * b31; te[4] = a21 * b12 + a22 * b22 + a23 * b32; te[7] = a21 * b13 + a22 * b23 + a23 * b33; te[2] = a31 * b11 + a32 * b21 + a33 * b31; te[5] = a31 * b12 + a32 * b22 + a33 * b32; te[8] = a31 * b13 + a32 * b23 + a33 * b33; return this; } /** * Invert this {@link Mat3}. * @returns - this {@link Mat3} after being inverted */ invert() { const te = this.elements, n11 = te[0], n21 = te[1], n31 = te[2], n12 = te[3], n22 = te[4], n32 = te[5], n13 = te[6], n23 = te[7], n33 = te[8], t11 = n33 * n22 - n32 * n23, t12 = n32 * n13 - n33 * n12, t13 = n23 * n12 - n22 * n13, det = n11 * t11 + n21 * t12 + n31 * t13; if (det === 0) return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0); const detInv = 1 / det; te[0] = t11 * detInv; te[1] = (n31 * n23 - n33 * n21) * detInv; te[2] = (n32 * n21 - n31 * n22) * detInv; te[3] = t12 * detInv; te[4] = (n33 * n11 - n31 * n13) * detInv; te[5] = (n31 * n12 - n32 * n11) * detInv; te[6] = t13 * detInv; te[7] = (n21 * n13 - n23 * n11) * detInv; te[8] = (n22 * n11 - n21 * n12) * detInv; return this; } /** * Transpose this {@link Mat3}. * @returns - this {@link Mat3} after being transposed */ transpose() { let tmp; const m = this.elements; tmp = m[1]; m[1] = m[3]; m[3] = tmp; tmp = m[2]; m[2] = m[6]; m[6] = tmp; tmp = m[5]; m[5] = m[7]; m[7] = tmp; return this; } /** * Compute a normal {@link Mat3} matrix from a {@link Mat4} transformation matrix. * @param matrix - {@link Mat4} transformation matrix * @returns - this {@link Mat3} after being inverted and transposed */ getNormalMatrix(matrix = new Mat4()) { return this.setFromMat4(matrix).invert().transpose(); } /** * Set a transformation matrix from translation, scale and center 2D coordinates and a rotation. Useful to compute UV transformation matrices. * @param tx - translation along X axis. * @param ty - translation along Y axis. * @param sx - Scale along X axis. * @param sy - Scale along Y axis. * @param rotation - Rotation in radians. * @param cx - Center of the transformation along X axis. * @param cy - Center of the transformation along Y axis. */ setUVTransform(tx = 0, ty = 0, sx = 1, sy = 1, rotation = 0, cx = 0, cy = 0) { const c = Math.cos(rotation); const s = Math.sin(rotation); this.set(sx * c, sx * s, -sx * (c * cx + s * cy) + cx + tx, -sy * s, sy * c, -sy * (-s * cx + c * cy) + cy + ty, 0, 0, 1); return this; } /** * Rotate this {@link Mat3} by a given angle around X axis, counterclockwise. * @param theta - Angle to rotate along X axis. * @returns - this {@link Mat3} after rotation. */ rotateByAngleX(theta = 0) { const c = Math.cos(theta); const s = Math.sin(theta); this.set(1, 0, 0, 0, c, s, 0, -s, c); return this; } /** * Rotate this {@link Mat3} by a given angle around Y axis, counterclockwise. * @param theta - Angle to rotate along Y axis. * @returns - this {@link Mat3} after rotation. */ rotateByAngleY(theta = 0) { const c = Math.cos(theta); const s = Math.sin(theta); this.set(c, 0, s, 0, 1, 0, -s, 0, c); return this; } /** * Rotate this {@link Mat3} by a given angle around Z axis, counterclockwise. * @param theta - Angle to rotate along Z axis. * @returns - this {@link Mat3} after rotation. */ rotateByAngleZ(theta = 0) { const c = Math.cos(theta); const s = Math.sin(theta); this.set(c, -s, 0, s, c, 0, 0, 0, 1); return this; } /** * {@link premultiply} this {@link Mat3} by a translate matrix (i.e. translateMatrix = new Mat3().translate(vector)). * @param vector - translation {@link Vec2} to use. * @returns - this {@link Mat3} after the premultiply translate operation. */ premultiplyTranslate(vector = new Vec2()) { const a11 = 1, a22 = 1, a33 = 1; const a13 = vector.x, a23 = vector.y; const be = this.elements; const te = this.elements; const b11 = be[0], b12 = be[3], b13 = be[6]; const b21 = be[1], b22 = be[4], b23 = be[7]; const b31 = be[2], b32 = be[5], b33 = be[8]; te[0] = a11 * b11 + a13 * b31; te[3] = a11 * b12 + a13 * b32; te[6] = a11 * b13 + a13 * b33; te[1] = a22 * b21 + a23 * b31; te[4] = a22 * b22 + a23 * b32; te[7] = a22 * b23 + a23 * b33; te[2] = a33 * b31; te[5] = a33 * b32; te[8] = a33 * b33; return this; } /** * {@link premultiply} this {@link Mat3} by a scale matrix (i.e. translateMatrix = new Mat3().scale(vector)). * @param vector - scale {@link Vec2} to use. * @returns - this {@link Mat3} after the premultiply scale operation. */ premultiplyScale(vector = new Vec2()) { const a11 = vector.x, a22 = vector.y, a33 = 1; const be = this.elements; const te = this.elements; const b11 = be[0], b12 = be[3], b13 = be[6]; const b21 = be[1], b22 = be[4], b23 = be[7]; const b31 = be[2], b32 = be[5], b33 = be[8]; te[0] = a11 * b11; te[3] = a11 * b12; te[6] = a11 * b13; te[1] = a22 * b21; te[4] = a22 * b22; te[7] = a22 * b23; te[2] = a33 * b31; te[5] = a33 * b32; te[8] = a33 * b33; return this; } /** * Translate a {@link Mat3}. * @param vector - translation {@link Vec2} to use. * @returns - translated {@link Mat3}. */ translate(vector = new Vec2()) { const tx = vector.x, ty = vector.y; const be = this.elements; const te = this.elements; const b11 = be[0], b12 = be[3], b13 = be[6]; const b21 = be[1], b22 = be[4], b23 = be[7]; const b31 = be[2], b32 = be[5], b33 = be[8]; te[6] = b11 * tx + b12 * ty + b13; te[7] = b21 * tx + b22 * ty + b23; te[8] = b31 * tx + b32 * ty + b33; return this; } }; //#endregion export { Mat3 };