UNPKG

@babylonjs/viewer

Version:

The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.

250 lines (246 loc) 14.2 kB
import { F as FlowGraphBlock } from './KHR_interactivity-CnR665Qq.esm.js'; import { f as RichTypeVector3, h as RichTypeQuaternion, i as RichTypeMatrix, a as RichTypeBoolean, g as getRichTypeByFlowGraphType, d as RichTypeNumber, F as FlowGraphMatrix2D, j as FlowGraphMatrix3D } from './declarationMapper-mPOKbCS_.esm.js'; import { M as Matrix, V as Vector3, aD as Quaternion, u as RegisterClass } from './index-HyNDfLMI.esm.js'; import { F as FlowGraphUnaryOperationBlock } from './flowGraphUnaryOperationBlock-DApXbJAT.esm.js'; import { F as FlowGraphCachedOperationBlock } from './flowGraphCachedOperationBlock-DSj_4V2c.esm.js'; import { F as FlowGraphBinaryOperationBlock } from './flowGraphBinaryOperationBlock-5TY0sBGP.esm.js'; import './objectModelMapping-OlchA9xj.esm.js'; import './spotLight.pure-C65PiYTZ.esm.js'; /** This file must only contain pure code and pure imports */ /** * Threshold below which the determinant of the normalized 3x3 of a matrix is treated as zero, indicating a * degenerate (non-decomposable) matrix whose columns are linearly dependent. */ const MatrixDecomposeDegenerateEpsilon = 1e-6; /** * Builds a matrix of the given flow graph matrix type with every element set to zero. * @param matrixType the matrix type to build * @returns the zero matrix */ function CreateZeroMatrix(matrixType) { if (matrixType === "Matrix2D" /* FlowGraphTypes.Matrix2D */) { return new FlowGraphMatrix2D([0, 0, 0, 0]); } if (matrixType === "Matrix3D" /* FlowGraphTypes.Matrix3D */) { return new FlowGraphMatrix3D([0, 0, 0, 0, 0, 0, 0, 0, 0]); } return Matrix.FromArray(new Array(16).fill(0)); } /** * Transposes a matrix. */ class FlowGraphTransposeBlock extends FlowGraphUnaryOperationBlock { /** * Creates a new instance of the block. * @param config the configuration of the block */ constructor(config) { super(getRichTypeByFlowGraphType(config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */), getRichTypeByFlowGraphType(config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */), (a) => (a.transpose ? a.transpose() : Matrix.Transpose(a)), "FlowGraphTransposeBlock" /* FlowGraphBlockNames.Transpose */, config); } } /** * Gets the determinant of a matrix. */ class FlowGraphDeterminantBlock extends FlowGraphUnaryOperationBlock { /** * Creates a new instance of the block. * @param config the configuration of the block */ constructor(config) { super(getRichTypeByFlowGraphType(config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */), RichTypeNumber, (a) => a.determinant(), "FlowGraphDeterminantBlock" /* FlowGraphBlockNames.Determinant */, config); } } /** * Inverts a matrix. */ class FlowGraphInvertMatrixBlock extends FlowGraphCachedOperationBlock { /** * Creates a new instance of the inverse block. * @param config the configuration of the block */ constructor(config) { super(getRichTypeByFlowGraphType(config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */), config); this._matrixType = config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */; this.a = this.registerDataInput("a", getRichTypeByFlowGraphType(config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */)); } _doOperation(context) { const a = this.a.getValue(context); // A matrix is only invertible when its determinant is a finite, non-zero number. For a zero, NaN, or // infinite determinant, returning undefined makes the cached base report isValid = false. const determinant = a.determinant(); if (determinant === 0 || !Number.isFinite(determinant)) { return undefined; } return a.inverse ? a.inverse() : Matrix.Invert(a); } /** * A matrix with no inverse reports an all-zero matrix rather than the identity default of the * matrix type, so the output is not mistaken for a meaningful transform. * @returns a matrix of the block's type with every element set to zero */ _getInvalidOutputValue() { return CreateZeroMatrix(this._matrixType); } getClassName() { return "FlowGraphInvertMatrixBlock" /* FlowGraphBlockNames.InvertMatrix */; } } /** * Multiplies two matrices. */ class FlowGraphMatrixMultiplicationBlock extends FlowGraphBinaryOperationBlock { /** * Creates a new instance of the multiplication block. * Note - this is similar to the math multiplication if not using matrix per-component multiplication. * @param config the configuration of the block */ constructor(config) { super(getRichTypeByFlowGraphType(config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */), getRichTypeByFlowGraphType(config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */), getRichTypeByFlowGraphType(config?.matrixType || "Matrix" /* FlowGraphTypes.Matrix */), (a, b) => b.multiply(a), "FlowGraphMatrixMultiplicationBlock" /* FlowGraphBlockNames.MatrixMultiplication */, config); } } /** * Matrix decompose block */ class FlowGraphMatrixDecomposeBlock extends FlowGraphBlock { constructor(config) { super(config); this.input = this.registerDataInput("input", RichTypeMatrix); this.position = this.registerDataOutput("position", RichTypeVector3); this.rotationQuaternion = this.registerDataOutput("rotationQuaternion", RichTypeQuaternion); this.scaling = this.registerDataOutput("scaling", RichTypeVector3); this.isValid = this.registerDataOutput("isValid", RichTypeBoolean, false); } _updateOutputs(context) { // _updateOutputs runs on every read of any of this block's four outputs. Cache the decomposition // per executionId (matching FlowGraphMatrixComposeBlock below) so reading all four outputs in one // frame does the work once instead of four times. const cachedExecutionId = context._getExecutionVariable(this, "executionId", -1); const cachedPosition = context._getExecutionVariable(this, "cachedPosition", null); const cachedRotation = context._getExecutionVariable(this, "cachedRotation", null); const cachedScaling = context._getExecutionVariable(this, "cachedScaling", null); const cachedIsValid = context._getExecutionVariable(this, "cachedIsValid", null); if (cachedExecutionId === context.executionId && cachedPosition && cachedRotation && cachedScaling && cachedIsValid !== null) { this.isValid.setValue(cachedIsValid, context); this.position.setValue(cachedPosition, context); this.rotationQuaternion.setValue(cachedRotation, context); this.scaling.setValue(cachedScaling, context); return; } const matrix = this.input.getValue(context); const m = matrix.m; const keepDegenerateComponents = !!this.config?.keepDegenerateComponents; // The fourth row of the matrix is ignored: the translation comes from the first three elements of the // fourth column, the scale from the lengths of the first three columns of the upper-left 3x3, and the // rotation from that 3x3 once normalized. const translation = new Vector3(m[12], m[13], m[14]); const scaleX = Math.sqrt(m[0] * m[0] + m[1] * m[1] + m[2] * m[2]); const scaleY = Math.sqrt(m[4] * m[4] + m[5] * m[5] + m[6] * m[6]); const scaleZ = Math.sqrt(m[8] * m[8] + m[9] * m[9] + m[10] * m[10]); // The matrix cannot be decomposed: the rotation is undefined, so report an identity rotation and either the // components that were extracted from the matrix or the type defaults. const degenerateOutputs = (keepComponents) => ({ isValid: false, rotationQuaternion: Quaternion.Identity(), position: keepComponents ? translation : Vector3.Zero(), scaling: keepComponents ? new Vector3(scaleX, scaleY, scaleZ) : Vector3.One(), }); let result; const areScalesFinite = Number.isFinite(scaleX) && Number.isFinite(scaleY) && Number.isFinite(scaleZ); const isTranslationFinite = Number.isFinite(m[12]) && Number.isFinite(m[13]) && Number.isFinite(m[14]); if (!areScalesFinite || (!keepDegenerateComponents && !isTranslationFinite)) { result = degenerateOutputs(keepDegenerateComponents); } else if (scaleX === 0 || scaleY === 0 || scaleZ === 0) { // A zero scale component leaves the rotation undefined, but the translation and the (degenerate) scale // are still well-defined, so they are reported as-is. result = degenerateOutputs(true); } else { // The determinant of the upper-left 3x3 (the fourth row is ignored) gives the handedness; dividing by the // product of the scales yields the determinant of the normalized 3x3, which is (close to) zero only when the // columns are linearly dependent — a degenerate matrix that cannot represent a rotation. const determinant = m[0] * (m[5] * m[10] - m[6] * m[9]) - m[4] * (m[1] * m[10] - m[2] * m[9]) + m[8] * (m[1] * m[6] - m[2] * m[5]); const normalizedDeterminant = determinant / (scaleX * scaleY * scaleZ); if (Math.abs(normalizedDeterminant) < MatrixDecomposeDegenerateEpsilon) { result = degenerateOutputs(keepDegenerateComponents); } else { // The remaining matrix is well-formed, so the actual translation/rotation/scale extraction is delegated // to the shared Matrix.decompose. That keeps the rotation and the handedness-sign convention identical to // the rest of Babylon (a left-handed matrix negates the same scale component everywhere). The fourth row is // reset to (0, 0, 0, 1) first because this operation ignores it, whereas Matrix.decompose's internal // determinant would otherwise let a non-standard fourth row flip the handedness. const normalized = Matrix.FromValues(m[0], m[1], m[2], 0, m[4], m[5], m[6], 0, m[8], m[9], m[10], 0, m[12], m[13], m[14], 1); const outScaling = new Vector3(); const outRotation = new Quaternion(); const outPosition = new Vector3(); normalized.decompose(outScaling, outRotation, outPosition); result = { isValid: true, position: outPosition, rotationQuaternion: outRotation, scaling: outScaling }; } } this.isValid.setValue(result.isValid, context); this.position.setValue(result.position, context); this.rotationQuaternion.setValue(result.rotationQuaternion, context); this.scaling.setValue(result.scaling, context); context._setExecutionVariable(this, "cachedIsValid", result.isValid); context._setExecutionVariable(this, "cachedPosition", result.position); context._setExecutionVariable(this, "cachedRotation", result.rotationQuaternion); context._setExecutionVariable(this, "cachedScaling", result.scaling); context._setExecutionVariable(this, "executionId", context.executionId); } getClassName() { return "FlowGraphMatrixDecompose" /* FlowGraphBlockNames.MatrixDecompose */; } } /** * Matrix compose block */ class FlowGraphMatrixComposeBlock extends FlowGraphBlock { constructor(config) { super(config); this.position = this.registerDataInput("position", RichTypeVector3); this.rotationQuaternion = this.registerDataInput("rotationQuaternion", RichTypeQuaternion); this.scaling = this.registerDataInput("scaling", RichTypeVector3); this.value = this.registerDataOutput("value", RichTypeMatrix); } _updateOutputs(context) { const cachedExecutionId = context._getExecutionVariable(this, "executionId", -1); const cachedMatrix = context._getExecutionVariable(this, "cachedMatrix", null); if (cachedExecutionId === context.executionId && cachedMatrix) { this.value.setValue(cachedMatrix, context); } else { const matrix = Matrix.Compose(this.scaling.getValue(context), this.rotationQuaternion.getValue(context), this.position.getValue(context)); this.value.setValue(matrix, context); context._setExecutionVariable(this, "cachedMatrix", matrix); context._setExecutionVariable(this, "executionId", context.executionId); } } getClassName() { return "FlowGraphMatrixCompose" /* FlowGraphBlockNames.MatrixCompose */; } } let _Registered = false; /** * Register side effects for flowGraphMatrixMathBlocks. * Safe to call multiple times; only the first call has an effect. */ function RegisterFlowGraphMatrixMathBlocks() { if (_Registered) { return; } _Registered = true; RegisterClass("FlowGraphTransposeBlock" /* FlowGraphBlockNames.Transpose */, FlowGraphTransposeBlock); RegisterClass("FlowGraphDeterminantBlock" /* FlowGraphBlockNames.Determinant */, FlowGraphDeterminantBlock); RegisterClass("FlowGraphInvertMatrixBlock" /* FlowGraphBlockNames.InvertMatrix */, FlowGraphInvertMatrixBlock); RegisterClass("FlowGraphMatrixMultiplicationBlock" /* FlowGraphBlockNames.MatrixMultiplication */, FlowGraphMatrixMultiplicationBlock); RegisterClass("FlowGraphMatrixDecompose" /* FlowGraphBlockNames.MatrixDecompose */, FlowGraphMatrixDecomposeBlock); RegisterClass("FlowGraphMatrixCompose" /* FlowGraphBlockNames.MatrixCompose */, FlowGraphMatrixComposeBlock); } /** * Re-exports pure implementation and applies runtime side effects. * Import flowGraphMatrixMathBlocks.pure for tree-shakeable, side-effect-free usage. */ RegisterFlowGraphMatrixMathBlocks(); export { FlowGraphDeterminantBlock, FlowGraphInvertMatrixBlock, FlowGraphMatrixComposeBlock, FlowGraphMatrixDecomposeBlock, FlowGraphMatrixMultiplicationBlock, FlowGraphTransposeBlock, RegisterFlowGraphMatrixMathBlocks }; //# sourceMappingURL=flowGraphMatrixMathBlocks-BMIK3kSc.esm.js.map