UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

344 lines (341 loc) 10.2 kB
import { Vec3 } from './vec3.js'; /** * @import { Mat4 } from './mat4.js' * @import { Quat } from './quat.js' */ /** * A 3x3 matrix. * * @category Math */ class Mat3 { /** * Create a new Mat3 instance. It is initialized to the identity matrix. */ constructor(){ /** * Matrix elements in the form of a flat array. * * @type {Float32Array} */ this.data = new Float32Array(9); // Create an identity matrix. Note that a new Float32Array has all elements set // to zero by default, so we only need to set the relevant elements to one. this.data[0] = this.data[4] = this.data[8] = 1; } /** * Creates a duplicate of the specified matrix. * * @returns {this} A duplicate matrix. * @example * const src = new pc.Mat3().translate(10, 20, 30); * const dst = src.clone(); * console.log("The two matrices are " + (src.equals(dst) ? "equal" : "different")); */ clone() { /** @type {this} */ const cstr = this.constructor; return new cstr().copy(this); } /** * Copies the contents of a source 3x3 matrix to a destination 3x3 matrix. * * @param {Mat3} rhs - A 3x3 matrix to be copied. * @returns {Mat3} Self for chaining. * @example * const src = new pc.Mat3().translate(10, 20, 30); * const dst = new pc.Mat3(); * dst.copy(src); * console.log("The two matrices are " + (src.equals(dst) ? "equal" : "different")); */ copy(rhs) { const src = rhs.data; const dst = this.data; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; dst[4] = src[4]; dst[5] = src[5]; dst[6] = src[6]; dst[7] = src[7]; dst[8] = src[8]; return this; } /** * Copies the contents of a source array[9] to a destination 3x3 matrix. * * @param {number[]} src - An array[9] to be copied. * @returns {Mat3} Self for chaining. * @example * const dst = new pc.Mat3(); * dst.set([0, 1, 2, 3, 4, 5, 6, 7, 8]); */ set(src) { const dst = this.data; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; dst[4] = src[4]; dst[5] = src[5]; dst[6] = src[6]; dst[7] = src[7]; dst[8] = src[8]; return this; } /** * Extracts the x-axis from the specified matrix. * * @param {Vec3} [x] - The vector to receive the x axis of the matrix. * @returns {Vec3} The x-axis of the specified matrix. */ getX(x = new Vec3()) { return x.set(this.data[0], this.data[1], this.data[2]); } /** * Extracts the y-axis from the specified matrix. * * @param {Vec3} [y] - The vector to receive the y axis of the matrix. * @returns {Vec3} The y-axis of the specified matrix. */ getY(y = new Vec3()) { return y.set(this.data[3], this.data[4], this.data[5]); } /** * Extracts the z-axis from the specified matrix. * * @param {Vec3} [z] - The vector to receive the z axis of the matrix. * @returns {Vec3} The z-axis of the specified matrix. */ getZ(z = new Vec3()) { return z.set(this.data[6], this.data[7], this.data[8]); } /** * Reports whether two matrices are equal. * * @param {Mat3} rhs - The other matrix. * @returns {boolean} True if the matrices are equal and false otherwise. * @example * const a = new pc.Mat3().translate(10, 20, 30); * const b = new pc.Mat3(); * console.log("The two matrices are " + (a.equals(b) ? "equal" : "different")); */ equals(rhs) { const l = this.data; const r = rhs.data; return l[0] === r[0] && l[1] === r[1] && l[2] === r[2] && l[3] === r[3] && l[4] === r[4] && l[5] === r[5] && l[6] === r[6] && l[7] === r[7] && l[8] === r[8]; } /** * Reports whether the specified matrix is the identity matrix. * * @returns {boolean} True if the matrix is identity and false otherwise. * @example * const m = new pc.Mat3(); * console.log("The matrix is " + (m.isIdentity() ? "identity" : "not identity")); */ isIdentity() { const m = this.data; return m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 0 && m[4] === 1 && m[5] === 0 && m[6] === 0 && m[7] === 0 && m[8] === 1; } /** * Sets the matrix to the identity matrix. * * @returns {Mat3} Self for chaining. * @example * m.setIdentity(); * console.log("The matrix is " + (m.isIdentity() ? "identity" : "not identity")); */ setIdentity() { const m = this.data; m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 1; m[5] = 0; m[6] = 0; m[7] = 0; m[8] = 1; return this; } /** * Converts the matrix to string form. * * @returns {string} The matrix in string form. * @example * const m = new pc.Mat3(); * // Outputs [1, 0, 0, 0, 1, 0, 0, 0, 1] * console.log(m.toString()); */ toString() { return `[${this.data.join(', ')}]`; } /** * Generates the transpose of the specified 3x3 matrix. * * @param {Mat3} [src] - The matrix to transpose. If not set, the matrix is transposed in-place. * @returns {Mat3} Self for chaining. * @example * const m = new pc.Mat3(); * * // Transpose in place * m.transpose(); */ transpose(src = this) { const s = src.data; const t = this.data; if (s === t) { let tmp; tmp = s[1]; t[1] = s[3]; t[3] = tmp; tmp = s[2]; t[2] = s[6]; t[6] = tmp; tmp = s[5]; t[5] = s[7]; t[7] = tmp; } else { t[0] = s[0]; t[1] = s[3]; t[2] = s[6]; t[3] = s[1]; t[4] = s[4]; t[5] = s[7]; t[6] = s[2]; t[7] = s[5]; t[8] = s[8]; } return this; } /** * Converts the specified 4x4 matrix to a Mat3. * * @param {Mat4} m - The 4x4 matrix to convert. * @returns {Mat3} Self for chaining. */ setFromMat4(m) { const src = m.data; const dst = this.data; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6]; dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10]; return this; } /** * Sets this matrix to the given quaternion rotation. * * @param {Quat} r - A quaternion rotation. * @returns {Mat3} Self for chaining. * @example * const r = new pc.Quat(1, 2, 3, 4).normalize(); * * const m = new pc.Mat4(); * m.setFromQuat(r); */ setFromQuat(r) { const qx = r.x; const qy = r.y; const qz = r.z; const qw = r.w; const x2 = qx + qx; const y2 = qy + qy; const z2 = qz + qz; const xx = qx * x2; const xy = qx * y2; const xz = qx * z2; const yy = qy * y2; const yz = qy * z2; const zz = qz * z2; const wx = qw * x2; const wy = qw * y2; const wz = qw * z2; const m = this.data; m[0] = 1 - (yy + zz); m[1] = xy + wz; m[2] = xz - wy; m[3] = xy - wz; m[4] = 1 - (xx + zz); m[5] = yz + wx; m[6] = xz + wy; m[7] = yz - wx; m[8] = 1 - (xx + yy); return this; } /** * Set the matrix to the inverse of the specified 4x4 matrix. * * @param {Mat4} src - The 4x4 matrix to invert. * @returns {Mat3} Self for chaining. * * @ignore */ invertMat4(src) { const s = src.data; const a0 = s[0]; const a1 = s[1]; const a2 = s[2]; const a4 = s[4]; const a5 = s[5]; const a6 = s[6]; const a8 = s[8]; const a9 = s[9]; const a10 = s[10]; const b11 = a10 * a5 - a6 * a9; const b21 = -a10 * a1 + a2 * a9; const b31 = a6 * a1 - a2 * a5; const b12 = -a10 * a4 + a6 * a8; const b22 = a10 * a0 - a2 * a8; const b32 = -a6 * a0 + a2 * a4; const b13 = a9 * a4 - a5 * a8; const b23 = -a9 * a0 + a1 * a8; const b33 = a5 * a0 - a1 * a4; const det = a0 * b11 + a1 * b12 + a2 * b13; if (det === 0) { this.setIdentity(); } else { const invDet = 1 / det; const t = this.data; t[0] = b11 * invDet; t[1] = b21 * invDet; t[2] = b31 * invDet; t[3] = b12 * invDet; t[4] = b22 * invDet; t[5] = b32 * invDet; t[6] = b13 * invDet; t[7] = b23 * invDet; t[8] = b33 * invDet; } return this; } /** * Transforms a 3-dimensional vector by a 3x3 matrix. * * @param {Vec3} vec - The 3-dimensional vector to be transformed. * @param {Vec3} [res] - An optional 3-dimensional vector to receive the result of the * transformation. * @returns {Vec3} The input vector v transformed by the current instance. */ transformVector(vec, res = new Vec3()) { const m = this.data; const { x, y, z } = vec; res.x = x * m[0] + y * m[3] + z * m[6]; res.y = x * m[1] + y * m[4] + z * m[7]; res.z = x * m[2] + y * m[5] + z * m[8]; return res; } static{ /** * A constant matrix set to the identity. * * @type {Mat3} * @readonly */ this.IDENTITY = Object.freeze(new Mat3()); } static{ /** * A constant matrix with all elements set to 0. * * @type {Mat3} * @readonly */ this.ZERO = Object.freeze(new Mat3().set([ 0, 0, 0, 0, 0, 0, 0, 0, 0 ])); } } export { Mat3 };