UNPKG

@gltf-transform/core

Version:

glTF 2.0 SDK for JavaScript and TypeScript, on Web and Node.js.

175 lines (149 loc) 4.86 kB
import { determinant, getRotation } from 'gl-matrix/mat4'; import { length } from 'gl-matrix/vec3'; import type { mat4, vec3, vec4 } from '../constants.js'; import type { GLTF } from '../types/gltf.js'; /** @hidden */ export class MathUtils { public static identity(v: number): number { return v; } public static eq(a: number[], b: number[], tolerance = 10e-6): boolean { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (Math.abs(a[i] - b[i]) > tolerance) return false; } return true; } public static clamp(value: number, min: number, max: number): number { if (value < min) return min; if (value > max) return max; return value; } // TODO(perf): Compare performance if we replace the switch with individual functions. public static decodeNormalizedInt(i: number, componentType: GLTF.AccessorComponentType): number { // Hardcode enums from accessor.ts to avoid a circular dependency. switch (componentType) { case 5126: // FLOAT return i; case 5123: // UNSIGNED_SHORT return i / 65535.0; case 5121: // UNSIGNED_BYTE return i / 255.0; case 5122: // SHORT return Math.max(i / 32767.0, -1.0); case 5120: // BYTE return Math.max(i / 127.0, -1.0); default: throw new Error('Invalid component type.'); } } // TODO(perf): Compare performance if we replace the switch with individual functions. public static encodeNormalizedInt(f: number, componentType: GLTF.AccessorComponentType): number { // Hardcode enums from accessor.ts to avoid a circular dependency. switch (componentType) { case 5126: // FLOAT return f; case 5123: // UNSIGNED_SHORT return Math.round(MathUtils.clamp(f, 0, 1) * 65535.0); case 5121: // UNSIGNED_BYTE return Math.round(MathUtils.clamp(f, 0, 1) * 255.0); case 5122: // SHORT return Math.round(MathUtils.clamp(f, -1, 1) * 32767.0); case 5120: // BYTE return Math.round(MathUtils.clamp(f, -1, 1) * 127.0); default: throw new Error('Invalid component type.'); } } /** * Decompose a mat4 to TRS properties. * * Equivalent to the Matrix4 decompose() method in three.js, and intentionally not using the * gl-matrix version. See: https://github.com/toji/gl-matrix/issues/408 * * @param srcMat Matrix element, to be decomposed to TRS properties. * @param dstTranslation Translation element, to be overwritten. * @param dstRotation Rotation element, to be overwritten. * @param dstScale Scale element, to be overwritten. */ public static decompose(srcMat: mat4, dstTranslation: vec3, dstRotation: vec4, dstScale: vec3): void { let sx = length([srcMat[0], srcMat[1], srcMat[2]]); const sy = length([srcMat[4], srcMat[5], srcMat[6]]); const sz = length([srcMat[8], srcMat[9], srcMat[10]]); // if determine is negative, we need to invert one scale const det = determinant(srcMat); if (det < 0) sx = -sx; dstTranslation[0] = srcMat[12]; dstTranslation[1] = srcMat[13]; dstTranslation[2] = srcMat[14]; // scale the rotation part const _m1 = srcMat.slice(); const invSX = 1 / sx; const invSY = 1 / sy; const invSZ = 1 / sz; _m1[0] *= invSX; _m1[1] *= invSX; _m1[2] *= invSX; _m1[4] *= invSY; _m1[5] *= invSY; _m1[6] *= invSY; _m1[8] *= invSZ; _m1[9] *= invSZ; _m1[10] *= invSZ; getRotation(dstRotation, _m1 as mat4); dstScale[0] = sx; dstScale[1] = sy; dstScale[2] = sz; } /** * Compose TRS properties to a mat4. * * Equivalent to the Matrix4 compose() method in three.js, and intentionally not using the * gl-matrix version. See: https://github.com/toji/gl-matrix/issues/408 * * @param srcTranslation Translation element of matrix. * @param srcRotation Rotation element of matrix. * @param srcScale Scale element of matrix. * @param dstMat Matrix element, to be modified and returned. * @returns dstMat, overwritten to mat4 equivalent of given TRS properties. */ public static compose(srcTranslation: vec3, srcRotation: vec4, srcScale: vec3, dstMat: mat4): mat4 { const te = dstMat; const x = srcRotation[0], y = srcRotation[1], z = srcRotation[2], w = srcRotation[3]; const x2 = x + x, y2 = y + y, z2 = z + z; const xx = x * x2, xy = x * y2, xz = x * z2; const yy = y * y2, yz = y * z2, zz = z * z2; const wx = w * x2, wy = w * y2, wz = w * z2; const sx = srcScale[0], sy = srcScale[1], sz = srcScale[2]; te[0] = (1 - (yy + zz)) * sx; te[1] = (xy + wz) * sx; te[2] = (xz - wy) * sx; te[3] = 0; te[4] = (xy - wz) * sy; te[5] = (1 - (xx + zz)) * sy; te[6] = (yz + wx) * sy; te[7] = 0; te[8] = (xz + wy) * sz; te[9] = (yz - wx) * sz; te[10] = (1 - (xx + yy)) * sz; te[11] = 0; te[12] = srcTranslation[0]; te[13] = srcTranslation[1]; te[14] = srcTranslation[2]; te[15] = 1; return te; } }