UNPKG

@gltf-transform/core

Version:

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

66 lines (55 loc) 2.24 kB
import { transformMat4 } from 'gl-matrix/vec3'; import { type bbox, type mat4, PropertyType, type vec3 } from '../constants.js'; import type { Mesh, Node, Scene } from '../properties/index.js'; /** @hidden Implemented in /core for use by /extensions, publicly exported from /functions. */ export function getBounds(node: Node | Scene): bbox { const resultBounds = createBounds(); const parents = node.propertyType === PropertyType.NODE ? [node] : node.listChildren(); for (const parent of parents) { parent.traverse((node) => { const mesh = node.getMesh(); if (!mesh) return; // Compute mesh bounds and update result. const meshBounds = getMeshBounds(mesh, node.getWorldMatrix()); if (meshBounds.min.every(isFinite) && meshBounds.max.every(isFinite)) { expandBounds(meshBounds.min, resultBounds); expandBounds(meshBounds.max, resultBounds); } }); } return resultBounds; } /** Computes mesh bounds in world space. */ function getMeshBounds(mesh: Mesh, worldMatrix: mat4): bbox { const meshBounds = createBounds(); // We can't transform a local AABB into world space and still have a tight AABB in world space, // so we need to compute the world AABB vertex by vertex here. for (const prim of mesh.listPrimitives()) { const position = prim.getAttribute('POSITION'); const indices = prim.getIndices(); if (!position) continue; let localPos: vec3 = [0, 0, 0]; let worldPos: vec3 = [0, 0, 0]; for (let i = 0, il = indices ? indices.getCount() : position.getCount(); i < il; i++) { const index = indices ? indices.getScalar(i) : i; localPos = position.getElement(index, localPos) as vec3; worldPos = transformMat4(worldPos, localPos, worldMatrix) as vec3; expandBounds(worldPos, meshBounds); } } return meshBounds; } /** Expands bounds of target by given source. */ function expandBounds(point: vec3, target: bbox): void { for (let i = 0; i < 3; i++) { target.min[i] = Math.min(point[i], target.min[i]); target.max[i] = Math.max(point[i], target.max[i]); } } /** Creates new bounds with min=Infinity, max=-Infinity. */ function createBounds(): bbox { return { min: [Infinity, Infinity, Infinity] as vec3, max: [-Infinity, -Infinity, -Infinity] as vec3, }; }