@babylonjs/loaders 9.26.0 → 9.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FBX/fbxConstraintBehavior.d.ts +188 -0
- package/FBX/fbxConstraintBehavior.js +532 -0
- package/FBX/fbxConstraintBehavior.js.map +1 -0
- package/FBX/fbxFileLoader.pure.d.ts +175 -6
- package/FBX/fbxFileLoader.pure.js +1521 -286
- package/FBX/fbxFileLoader.pure.js.map +1 -1
- package/FBX/index.d.ts +4 -1
- package/FBX/index.js +1 -0
- package/FBX/index.js.map +1 -1
- package/FBX/interpreter/animation.d.ts +73 -33
- package/FBX/interpreter/animation.js +620 -223
- package/FBX/interpreter/animation.js.map +1 -1
- package/FBX/interpreter/animationCurve.d.ts +91 -0
- package/FBX/interpreter/animationCurve.js +623 -0
- package/FBX/interpreter/animationCurve.js.map +1 -0
- package/FBX/interpreter/blendShapes.js +9 -18
- package/FBX/interpreter/blendShapes.js.map +1 -1
- package/FBX/interpreter/connections.d.ts +1 -1
- package/FBX/interpreter/connections.js +173 -34
- package/FBX/interpreter/connections.js.map +1 -1
- package/FBX/interpreter/constraints.d.ts +68 -0
- package/FBX/interpreter/constraints.js +143 -0
- package/FBX/interpreter/constraints.js.map +1 -0
- package/FBX/interpreter/fbxInterpreter.d.ts +89 -4
- package/FBX/interpreter/fbxInterpreter.js +474 -122
- package/FBX/interpreter/fbxInterpreter.js.map +1 -1
- package/FBX/interpreter/geometry.d.ts +1 -1
- package/FBX/interpreter/geometry.js +150 -92
- package/FBX/interpreter/geometry.js.map +1 -1
- package/FBX/interpreter/legacyDocument.d.ts +11 -0
- package/FBX/interpreter/legacyDocument.js +425 -0
- package/FBX/interpreter/legacyDocument.js.map +1 -0
- package/FBX/interpreter/materialModel.d.ts +71 -0
- package/FBX/interpreter/materialModel.js +622 -0
- package/FBX/interpreter/materialModel.js.map +1 -0
- package/FBX/interpreter/materials.d.ts +13 -1
- package/FBX/interpreter/materials.js +88 -5
- package/FBX/interpreter/materials.js.map +1 -1
- package/FBX/interpreter/nodeTransform.d.ts +32 -0
- package/FBX/interpreter/nodeTransform.js +54 -0
- package/FBX/interpreter/nodeTransform.js.map +1 -0
- package/FBX/interpreter/nurbs.d.ts +99 -0
- package/FBX/interpreter/nurbs.js +627 -0
- package/FBX/interpreter/nurbs.js.map +1 -0
- package/FBX/interpreter/propertyTemplates.d.ts +23 -0
- package/FBX/interpreter/propertyTemplates.js +109 -2
- package/FBX/interpreter/propertyTemplates.js.map +1 -1
- package/FBX/interpreter/rig.js +16 -0
- package/FBX/interpreter/rig.js.map +1 -1
- package/FBX/interpreter/sceneDiagnostics.js +28 -3
- package/FBX/interpreter/sceneDiagnostics.js.map +1 -1
- package/FBX/interpreter/skeleton.d.ts +4 -18
- package/FBX/interpreter/skeleton.js +16 -94
- package/FBX/interpreter/skeleton.js.map +1 -1
- package/FBX/parsers/fbxAsciiParser.js +119 -9
- package/FBX/parsers/fbxAsciiParser.js.map +1 -1
- package/FBX/parsers/fbxBinaryParser.js +74 -22
- package/FBX/parsers/fbxBinaryParser.js.map +1 -1
- package/FBX/pure.d.ts +1 -0
- package/FBX/pure.js +1 -0
- package/FBX/pure.js.map +1 -1
- package/FBX/types/fbxTypes.d.ts +18 -2
- package/FBX/types/fbxTypes.js +40 -12
- package/FBX/types/fbxTypes.js.map +1 -1
- package/SPLAT/gaussianSplattingStream.d.ts +79 -25
- package/SPLAT/gaussianSplattingStream.js +320 -95
- package/SPLAT/gaussianSplattingStream.js.map +1 -1
- package/USD/usdCommandProtocol.d.ts +20 -4
- package/USD/usdCommandProtocol.js +25 -3
- package/USD/usdCommandProtocol.js.map +1 -1
- package/USD/usdFileLoader.pure.js +2 -0
- package/USD/usdFileLoader.pure.js.map +1 -1
- package/USD/usdSceneMaterializer.js +430 -92
- package/USD/usdSceneMaterializer.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +110 -3
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +468 -74
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.d.ts +47 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.js +68 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.d.ts +2 -2
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.js +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.js +38 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.d.ts +41 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.js +63 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.d.ts +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.js +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.d.ts +112 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js +773 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +18 -10
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +299 -54
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.d.ts +2 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js +7 -2
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.js +89 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.d.ts +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.js +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +55 -1
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js +124 -76
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity.types.d.ts +18 -1
- package/glTF/2.0/Extensions/KHR_interactivity.types.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.d.ts +2 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +114 -56
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.d.ts +2 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +80 -35
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -1
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js +3 -2
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js.map +1 -1
- package/glTF/2.0/Extensions/objectModelMapping.d.ts +4 -2
- package/glTF/2.0/Extensions/objectModelMapping.js +33 -4
- package/glTF/2.0/Extensions/objectModelMapping.js.map +1 -1
- package/glTF/2.0/glTFLoader.pure.d.ts +1 -1
- package/glTF/2.0/glTFLoader.pure.js +9 -4
- package/glTF/2.0/glTFLoader.pure.js.map +1 -1
- package/glTF/2.0/glTFLoaderExtension.d.ts +2 -1
- package/glTF/2.0/glTFLoaderExtension.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type FBXNodeTransformData } from "./nodeTransform.js";
|
|
2
|
+
import { type FBXPropertyTemplate, type FBXPropertyTemplateMap } from "./propertyTemplates.js";
|
|
1
3
|
import { type FBXNode } from "../types/fbxTypes.js";
|
|
2
4
|
import { type FBXObjectMap } from "./connections.js";
|
|
3
5
|
export type FBXClusterMode = "Normalize" | "Additive" | "TotalOne" | "Unknown";
|
|
@@ -72,22 +74,6 @@ export interface FBXSkinData {
|
|
|
72
74
|
/** Recoverable skinning/bind diagnostics */
|
|
73
75
|
diagnostics: FBXSkinDiagnostic[];
|
|
74
76
|
}
|
|
75
|
-
|
|
76
|
-
* Extract all skin deformers from the FBX scene.
|
|
77
|
-
* Returns skin data including bone hierarchy and vertex weights.
|
|
78
|
-
*/
|
|
79
|
-
export declare function extractSkins(objectMap: FBXObjectMap): FBXSkinData[];
|
|
77
|
+
export declare function extractSkins(objectMap: FBXObjectMap, propertyTemplates?: FBXPropertyTemplateMap): FBXSkinData[];
|
|
80
78
|
export declare function isSkeletonModel(modelNode: FBXNode): boolean;
|
|
81
|
-
export declare function extractBoneTransform(modelNode: FBXNode):
|
|
82
|
-
translation: [number, number, number];
|
|
83
|
-
rotation: [number, number, number];
|
|
84
|
-
preRotation: [number, number, number];
|
|
85
|
-
postRotation: [number, number, number];
|
|
86
|
-
rotationPivot: [number, number, number];
|
|
87
|
-
scalingPivot: [number, number, number];
|
|
88
|
-
rotationOffset: [number, number, number];
|
|
89
|
-
scalingOffset: [number, number, number];
|
|
90
|
-
scale: [number, number, number];
|
|
91
|
-
rotationOrder: number;
|
|
92
|
-
inheritType: number;
|
|
93
|
-
};
|
|
79
|
+
export declare function extractBoneTransform(modelNode: FBXNode, template?: FBXPropertyTemplate): FBXNodeTransformData;
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */
|
|
2
|
-
import {
|
|
2
|
+
import { extractNodeTransform } from "./nodeTransform.js";
|
|
3
|
+
import { getPropertyTemplate } from "./propertyTemplates.js";
|
|
4
|
+
import { findChildByName, getPropertyValue, cleanFBXName, getNodeArray } from "../types/fbxTypes.js";
|
|
3
5
|
import { getChildren } from "./connections.js";
|
|
4
6
|
const MAX_BONE_INFLUENCES = 8;
|
|
5
7
|
/**
|
|
6
8
|
* Extract all skin deformers from the FBX scene.
|
|
7
9
|
* Returns skin data including bone hierarchy and vertex weights.
|
|
8
10
|
*/
|
|
9
|
-
|
|
11
|
+
// Template used to resolve bone transform defaults while extractSkins runs (bones are Models).
|
|
12
|
+
let currentModelTemplate;
|
|
13
|
+
export function extractSkins(objectMap, propertyTemplates) {
|
|
14
|
+
currentModelTemplate = propertyTemplates ? (getPropertyTemplate(propertyTemplates, "Model", "FbxNode") ?? getPropertyTemplate(propertyTemplates, "Model")) : undefined;
|
|
10
15
|
const skins = [];
|
|
11
16
|
for (const [id, node] of Array.from(objectMap.objects)) {
|
|
12
17
|
if (node.name === "Deformer" && getPropertyValue(node, 2) === "Skin") {
|
|
@@ -158,7 +163,7 @@ function extractBindPoseMatrices(geometryId, objectMap) {
|
|
|
158
163
|
const nodeChild = findChildByName(poseChild, "Node");
|
|
159
164
|
const matrixChild = findChildByName(poseChild, "Matrix");
|
|
160
165
|
const nodeId = nodeChild?.properties[0]?.value;
|
|
161
|
-
const matrixValue = matrixChild
|
|
166
|
+
const matrixValue = getNodeArray(matrixChild);
|
|
162
167
|
if (typeof nodeId !== "number") {
|
|
163
168
|
continue;
|
|
164
169
|
}
|
|
@@ -224,85 +229,8 @@ export function isSkeletonModel(modelNode) {
|
|
|
224
229
|
const subType = getPropertyValue(modelNode, 2);
|
|
225
230
|
return subType === "Root" || subType === "LimbNode";
|
|
226
231
|
}
|
|
227
|
-
export function extractBoneTransform(modelNode) {
|
|
228
|
-
|
|
229
|
-
const rotation = [0, 0, 0];
|
|
230
|
-
const preRotation = [0, 0, 0];
|
|
231
|
-
const postRotation = [0, 0, 0];
|
|
232
|
-
const rotationPivot = [0, 0, 0];
|
|
233
|
-
const scalingPivot = [0, 0, 0];
|
|
234
|
-
const rotationOffset = [0, 0, 0];
|
|
235
|
-
const scalingOffset = [0, 0, 0];
|
|
236
|
-
const scale = [1, 1, 1];
|
|
237
|
-
let rotationOrder = 0;
|
|
238
|
-
let inheritType = 1;
|
|
239
|
-
const props70 = findChildByName(modelNode, "Properties70");
|
|
240
|
-
if (!props70) {
|
|
241
|
-
return { translation, rotation, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, scale, rotationOrder, inheritType };
|
|
242
|
-
}
|
|
243
|
-
for (const p of props70.children) {
|
|
244
|
-
if (p.name !== "P") {
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
const propName = getPropertyValue(p, 0);
|
|
248
|
-
if (!propName) {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
switch (propName) {
|
|
252
|
-
case "Lcl Translation":
|
|
253
|
-
translation[0] = toNumber(p.properties[4]?.value) ?? 0;
|
|
254
|
-
translation[1] = toNumber(p.properties[5]?.value) ?? 0;
|
|
255
|
-
translation[2] = toNumber(p.properties[6]?.value) ?? 0;
|
|
256
|
-
break;
|
|
257
|
-
case "Lcl Rotation":
|
|
258
|
-
rotation[0] = toNumber(p.properties[4]?.value) ?? 0;
|
|
259
|
-
rotation[1] = toNumber(p.properties[5]?.value) ?? 0;
|
|
260
|
-
rotation[2] = toNumber(p.properties[6]?.value) ?? 0;
|
|
261
|
-
break;
|
|
262
|
-
case "PreRotation":
|
|
263
|
-
preRotation[0] = toNumber(p.properties[4]?.value) ?? 0;
|
|
264
|
-
preRotation[1] = toNumber(p.properties[5]?.value) ?? 0;
|
|
265
|
-
preRotation[2] = toNumber(p.properties[6]?.value) ?? 0;
|
|
266
|
-
break;
|
|
267
|
-
case "PostRotation":
|
|
268
|
-
postRotation[0] = toNumber(p.properties[4]?.value) ?? 0;
|
|
269
|
-
postRotation[1] = toNumber(p.properties[5]?.value) ?? 0;
|
|
270
|
-
postRotation[2] = toNumber(p.properties[6]?.value) ?? 0;
|
|
271
|
-
break;
|
|
272
|
-
case "RotationPivot":
|
|
273
|
-
rotationPivot[0] = toNumber(p.properties[4]?.value) ?? 0;
|
|
274
|
-
rotationPivot[1] = toNumber(p.properties[5]?.value) ?? 0;
|
|
275
|
-
rotationPivot[2] = toNumber(p.properties[6]?.value) ?? 0;
|
|
276
|
-
break;
|
|
277
|
-
case "ScalingPivot":
|
|
278
|
-
scalingPivot[0] = toNumber(p.properties[4]?.value) ?? 0;
|
|
279
|
-
scalingPivot[1] = toNumber(p.properties[5]?.value) ?? 0;
|
|
280
|
-
scalingPivot[2] = toNumber(p.properties[6]?.value) ?? 0;
|
|
281
|
-
break;
|
|
282
|
-
case "RotationOffset":
|
|
283
|
-
rotationOffset[0] = toNumber(p.properties[4]?.value) ?? 0;
|
|
284
|
-
rotationOffset[1] = toNumber(p.properties[5]?.value) ?? 0;
|
|
285
|
-
rotationOffset[2] = toNumber(p.properties[6]?.value) ?? 0;
|
|
286
|
-
break;
|
|
287
|
-
case "ScalingOffset":
|
|
288
|
-
scalingOffset[0] = toNumber(p.properties[4]?.value) ?? 0;
|
|
289
|
-
scalingOffset[1] = toNumber(p.properties[5]?.value) ?? 0;
|
|
290
|
-
scalingOffset[2] = toNumber(p.properties[6]?.value) ?? 0;
|
|
291
|
-
break;
|
|
292
|
-
case "Lcl Scaling":
|
|
293
|
-
scale[0] = toNumber(p.properties[4]?.value) ?? 1;
|
|
294
|
-
scale[1] = toNumber(p.properties[5]?.value) ?? 1;
|
|
295
|
-
scale[2] = toNumber(p.properties[6]?.value) ?? 1;
|
|
296
|
-
break;
|
|
297
|
-
case "RotationOrder":
|
|
298
|
-
rotationOrder = toNumber(p.properties[4]?.value) ?? 0;
|
|
299
|
-
break;
|
|
300
|
-
case "InheritType":
|
|
301
|
-
inheritType = toNumber(p.properties[4]?.value) ?? 1;
|
|
302
|
-
break;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return { translation, rotation, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, scale, rotationOrder, inheritType };
|
|
232
|
+
export function extractBoneTransform(modelNode, template) {
|
|
233
|
+
return extractNodeTransform(modelNode, template ?? currentModelTemplate);
|
|
306
234
|
}
|
|
307
235
|
function extractClusterMatrices(clusterNode) {
|
|
308
236
|
let bindPoseMatrix = null;
|
|
@@ -311,7 +239,7 @@ function extractClusterMatrices(clusterNode) {
|
|
|
311
239
|
let clusterMode = "Normalize";
|
|
312
240
|
const transformNode = findChildByName(clusterNode, "Transform");
|
|
313
241
|
if (transformNode && transformNode.properties[0]) {
|
|
314
|
-
const val = transformNode
|
|
242
|
+
const val = getNodeArray(transformNode);
|
|
315
243
|
if (val instanceof Float64Array && val.length === 16) {
|
|
316
244
|
bindPoseMatrix = val;
|
|
317
245
|
}
|
|
@@ -321,7 +249,7 @@ function extractClusterMatrices(clusterNode) {
|
|
|
321
249
|
}
|
|
322
250
|
const transformLinkNode = findChildByName(clusterNode, "TransformLink");
|
|
323
251
|
if (transformLinkNode && transformLinkNode.properties[0]) {
|
|
324
|
-
const val = transformLinkNode
|
|
252
|
+
const val = getNodeArray(transformLinkNode);
|
|
325
253
|
if (val instanceof Float64Array && val.length === 16) {
|
|
326
254
|
transformLinkMatrix = val;
|
|
327
255
|
}
|
|
@@ -331,7 +259,7 @@ function extractClusterMatrices(clusterNode) {
|
|
|
331
259
|
}
|
|
332
260
|
const transformAssociateModelNode = findChildByName(clusterNode, "TransformAssociateModel");
|
|
333
261
|
if (transformAssociateModelNode && transformAssociateModelNode.properties[0]) {
|
|
334
|
-
const val = transformAssociateModelNode
|
|
262
|
+
const val = getNodeArray(transformAssociateModelNode);
|
|
335
263
|
if (val instanceof Float64Array && val.length === 16) {
|
|
336
264
|
transformAssociateModelMatrix = val;
|
|
337
265
|
}
|
|
@@ -418,7 +346,7 @@ function extractVertexWeights(bones, boneModelMap, objectMap) {
|
|
|
418
346
|
if (!indexesNode) {
|
|
419
347
|
continue;
|
|
420
348
|
}
|
|
421
|
-
const indexes = toInt32Array(indexesNode
|
|
349
|
+
const indexes = toInt32Array(getNodeArray(indexesNode));
|
|
422
350
|
if (!indexes) {
|
|
423
351
|
continue;
|
|
424
352
|
}
|
|
@@ -447,8 +375,8 @@ function extractVertexWeights(bones, boneModelMap, objectMap) {
|
|
|
447
375
|
if (!indexesNode || !weightsNode) {
|
|
448
376
|
continue;
|
|
449
377
|
}
|
|
450
|
-
const indexes = toInt32Array(indexesNode
|
|
451
|
-
const weights = toFloat64Array(weightsNode
|
|
378
|
+
const indexes = toInt32Array(getNodeArray(indexesNode));
|
|
379
|
+
const weights = toFloat64Array(getNodeArray(weightsNode));
|
|
452
380
|
if (!indexes || !weights) {
|
|
453
381
|
continue;
|
|
454
382
|
}
|
|
@@ -484,12 +412,6 @@ function extractVertexWeights(bones, boneModelMap, objectMap) {
|
|
|
484
412
|
return { boneIndices, boneWeights };
|
|
485
413
|
}
|
|
486
414
|
// ── Utilities ──────────────────────────────────────────────────────────────────
|
|
487
|
-
function toNumber(value) {
|
|
488
|
-
if (typeof value === "number") {
|
|
489
|
-
return value;
|
|
490
|
-
}
|
|
491
|
-
return undefined;
|
|
492
|
-
}
|
|
493
415
|
function toInt32Array(value) {
|
|
494
416
|
if (value instanceof Int32Array) {
|
|
495
417
|
return value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/FBX/interpreter/skeleton.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */\r\nimport { type FBXNode, findChildByName, getPropertyValue, cleanFBXName } from \"../types/fbxTypes\";\r\n\r\nimport { type FBXObjectMap, getChildren } from \"./connections\";\r\n\r\nconst MAX_BONE_INFLUENCES = 8;\r\n\r\nexport type FBXClusterMode = \"Normalize\" | \"Additive\" | \"TotalOne\" | \"Unknown\";\r\n\r\nexport interface FBXSkinDiagnostic {\r\n type: \"cluster-mode-runtime-unsupported\" | \"missing-cluster-transform\" | \"missing-cluster-transform-link\" | \"missing-bind-pose-matrix\" | \"associate-model-present\";\r\n message: string;\r\n boneModelId?: number;\r\n boneName?: string;\r\n clusterMode?: FBXClusterMode;\r\n}\r\n\r\n/** Represents a single bone (cluster) in the FBX skeleton */\r\nexport interface FBXBoneData {\r\n /** The Model node ID for this bone */\r\n modelId: number;\r\n /** Bone name (from the Model node) */\r\n name: string;\r\n /** Index of this bone in the skeleton */\r\n index: number;\r\n /** Index of the parent bone (-1 for root) */\r\n parentIndex: number;\r\n /** Whether this bone corresponds to an FBX Cluster with vertex weights */\r\n isCluster: boolean;\r\n /** Local translation from parent (Lcl Translation) */\r\n translation: [number, number, number];\r\n /** Local rotation in degrees (Lcl Rotation) */\r\n rotation: [number, number, number];\r\n /** Pre-rotation in degrees (applied before Lcl Rotation) */\r\n preRotation: [number, number, number];\r\n /** Post-rotation in degrees (applied after Lcl Rotation, inverted) */\r\n postRotation: [number, number, number];\r\n /** Rotation pivot point */\r\n rotationPivot: [number, number, number];\r\n /** Scaling pivot point */\r\n scalingPivot: [number, number, number];\r\n /** Rotation offset */\r\n rotationOffset: [number, number, number];\r\n /** Scaling offset */\r\n scalingOffset: [number, number, number];\r\n /** Local scale (Lcl Scaling) */\r\n scale: [number, number, number];\r\n /** Rotation order: 0=XYZ, 1=XZY, 2=YZX, 3=YXZ, 4=ZXY, 5=ZYX */\r\n rotationOrder: number;\r\n /** FBX transform inheritance mode. 0=RrSs, 1=RSrs, 2=Rrs */\r\n inheritType: number;\r\n /** Cluster skinning mode */\r\n clusterMode: FBXClusterMode;\r\n /** Bind pose transform matrix (cluster Transform, 4x4) */\r\n bindPoseMatrix: Float64Array | null;\r\n /** Bone's world transform at bind time (cluster TransformLink, 4x4) */\r\n transformLinkMatrix: Float64Array | null;\r\n /** Associate model world transform at bind time (cluster TransformAssociateModel, 4x4) */\r\n transformAssociateModelMatrix: Float64Array | null;\r\n /** Model's absolute matrix from the FBX BindPose, when present */\r\n modelBindPoseMatrix: Float64Array | null;\r\n /** Recoverable bind/skinning diagnostics for this bone */\r\n diagnostics: FBXSkinDiagnostic[];\r\n}\r\n\r\n/** Represents a skin deformer with its clusters */\r\nexport interface FBXSkinData {\r\n /** Skin deformer ID */\r\n id: number;\r\n /** Geometry ID this skin is attached to */\r\n geometryId: number;\r\n /** Mesh model world matrix from the FBX BindPose, when present */\r\n meshBindPoseMatrix: Float64Array | null;\r\n /** Bones in this skeleton */\r\n bones: FBXBoneData[];\r\n /** Per-vertex bone indices, sorted by descending weight and capped for Babylon skinning */\r\n boneIndices: number[][];\r\n /** Per-vertex bone weights, matching boneIndices */\r\n boneWeights: number[][];\r\n /** Recoverable skinning/bind diagnostics */\r\n diagnostics: FBXSkinDiagnostic[];\r\n}\r\n\r\n/**\r\n * Extract all skin deformers from the FBX scene.\r\n * Returns skin data including bone hierarchy and vertex weights.\r\n */\r\nexport function extractSkins(objectMap: FBXObjectMap): FBXSkinData[] {\r\n const skins: FBXSkinData[] = [];\r\n\r\n for (const [id, node] of Array.from(objectMap.objects)) {\r\n if (node.name === \"Deformer\" && getPropertyValue<string>(node, 2) === \"Skin\") {\r\n const skin = extractSkin(id, node, objectMap);\r\n if (skin) {\r\n skins.push(skin);\r\n }\r\n }\r\n }\r\n\r\n return skins;\r\n}\r\n\r\nfunction extractSkin(skinId: number, _skinNode: FBXNode, objectMap: FBXObjectMap): FBXSkinData | null {\r\n // Find the geometry this skin is attached to\r\n // Skin is a child of the geometry in FBX connection graph\r\n const skinParent = objectMap.parentOf.get(skinId);\r\n if (!skinParent) {\r\n return null;\r\n }\r\n\r\n const geometryId = skinParent.id;\r\n const geometryNode = objectMap.objects.get(geometryId);\r\n if (!geometryNode || geometryNode.name !== \"Geometry\") {\r\n return null;\r\n }\r\n const modelParent = objectMap.parentOf.get(geometryId);\r\n const modelParentNode = modelParent ? objectMap.objects.get(modelParent.id) : undefined;\r\n const meshModelId = modelParentNode?.name === \"Model\" ? modelParent!.id : undefined;\r\n\r\n // Find all clusters (children of this skin)\r\n const clusterEntries = getChildren(objectMap, skinId, \"Deformer\");\r\n if (clusterEntries.length === 0) {\r\n return null;\r\n }\r\n\r\n // For each cluster, find the connected bone Model\r\n // Connection graph: BoneModel → Cluster (bone is child of cluster)\r\n const boneModelMap = new Map<number, { clusterId: number; clusterNode: FBXNode }>();\r\n for (const { id: clusterId, node: clusterNode } of clusterEntries) {\r\n const subType = getPropertyValue<string>(clusterNode, 2);\r\n if (subType !== \"Cluster\") {\r\n continue;\r\n }\r\n\r\n // The bone Model is a child of the Cluster\r\n const boneChildren = getChildren(objectMap, clusterId, \"Model\");\r\n if (boneChildren.length > 0) {\r\n boneModelMap.set(boneChildren[0].id, { clusterId, clusterNode });\r\n }\r\n }\r\n\r\n // Build bone hierarchy from Model parent-child relationships. Include\r\n // skeleton-like ancestors even when they are not weighted clusters; some\r\n // rigs (for example 3ds Max Biped) animate a non-cluster root above the\r\n // clustered bones.\r\n const bindPoseMatrices = extractBindPoseMatrices(geometryId, objectMap);\r\n const skinDiagnostics: FBXSkinDiagnostic[] = [];\r\n const bones = buildBoneHierarchy(boneModelMap, bindPoseMatrices, objectMap, skinDiagnostics);\r\n if (bones.length === 0) {\r\n return null;\r\n }\r\n\r\n // Extract per-vertex weights from clusters\r\n const { boneIndices, boneWeights } = extractVertexWeights(bones, boneModelMap, objectMap);\r\n\r\n return {\r\n id: skinId,\r\n geometryId,\r\n meshBindPoseMatrix: meshModelId !== undefined ? (bindPoseMatrices.get(meshModelId) ?? null) : null,\r\n bones,\r\n boneIndices,\r\n boneWeights,\r\n diagnostics: skinDiagnostics,\r\n };\r\n}\r\n\r\n/**\r\n * Build a flat ordered bone list with parent indices from the FBX Model hierarchy.\r\n */\r\nfunction buildBoneHierarchy(\r\n boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>,\r\n bindPoseMatrices: Map<number, Float64Array>,\r\n objectMap: FBXObjectMap,\r\n skinDiagnostics: FBXSkinDiagnostic[]\r\n): FBXBoneData[] {\r\n const bones: FBXBoneData[] = [];\r\n const visited = new Set<number>();\r\n const skeletonModelIds = collectSkeletonModelIds(boneModelMap, objectMap);\r\n const parentByModelId = buildSkeletonParentMap(skeletonModelIds, objectMap);\r\n const childrenByModelId = buildSkeletonChildrenMap(skeletonModelIds, parentByModelId);\r\n\r\n const rootBoneIds = Array.from(skeletonModelIds).filter((modelId) => !parentByModelId.has(modelId));\r\n\r\n // BFS to build ordered list\r\n const queue: { modelId: number; parentIndex: number }[] = rootBoneIds.map((id) => ({\r\n modelId: id,\r\n parentIndex: -1,\r\n }));\r\n\r\n while (queue.length > 0) {\r\n const { modelId, parentIndex } = queue.shift()!;\r\n if (visited.has(modelId)) {\r\n continue;\r\n }\r\n visited.add(modelId);\r\n\r\n const modelNode = objectMap.objects.get(modelId);\r\n if (!modelNode) {\r\n continue;\r\n }\r\n\r\n const boneIndex = bones.length;\r\n\r\n const clusterInfo = boneModelMap.get(modelId);\r\n const transform = extractBoneTransform(modelNode);\r\n const { bindPoseMatrix, transformLinkMatrix, transformAssociateModelMatrix, clusterMode } = clusterInfo\r\n ? extractClusterMatrices(clusterInfo.clusterNode)\r\n : { bindPoseMatrix: null, transformLinkMatrix: null, transformAssociateModelMatrix: null, clusterMode: \"Unknown\" as const };\r\n const diagnostics = createBoneDiagnostics(\r\n modelId,\r\n cleanFBXName(getPropertyValue<string>(modelNode, 1) ?? `Bone${boneIndex}`),\r\n clusterInfo !== undefined,\r\n clusterMode,\r\n bindPoseMatrix,\r\n transformLinkMatrix,\r\n transformAssociateModelMatrix,\r\n bindPoseMatrices.get(modelId) ?? null\r\n );\r\n skinDiagnostics.push(...diagnostics);\r\n\r\n bones.push({\r\n modelId,\r\n name: cleanFBXName(getPropertyValue<string>(modelNode, 1) ?? `Bone${boneIndex}`),\r\n index: boneIndex,\r\n parentIndex,\r\n isCluster: clusterInfo !== undefined,\r\n translation: transform.translation,\r\n rotation: transform.rotation,\r\n preRotation: transform.preRotation,\r\n postRotation: transform.postRotation,\r\n rotationPivot: transform.rotationPivot,\r\n scalingPivot: transform.scalingPivot,\r\n rotationOffset: transform.rotationOffset,\r\n scalingOffset: transform.scalingOffset,\r\n scale: transform.scale,\r\n rotationOrder: transform.rotationOrder,\r\n inheritType: transform.inheritType,\r\n clusterMode,\r\n bindPoseMatrix,\r\n transformLinkMatrix,\r\n transformAssociateModelMatrix,\r\n modelBindPoseMatrix: bindPoseMatrices.get(modelId) ?? null,\r\n diagnostics,\r\n });\r\n\r\n for (const childId of childrenByModelId.get(modelId) ?? []) {\r\n if (!visited.has(childId)) {\r\n queue.push({ modelId: childId, parentIndex: boneIndex });\r\n }\r\n }\r\n }\r\n\r\n return bones;\r\n}\r\n\r\nfunction extractBindPoseMatrices(geometryId: number, objectMap: FBXObjectMap): Map<number, Float64Array> {\r\n const modelParent = objectMap.parentOf.get(geometryId);\r\n const modelParentNode = modelParent ? objectMap.objects.get(modelParent.id) : undefined;\r\n const modelId = modelParentNode?.name === \"Model\" ? modelParent!.id : undefined;\r\n if (modelId === undefined) {\r\n return new Map();\r\n }\r\n\r\n for (const [, poseNode] of Array.from(objectMap.objects)) {\r\n if (poseNode.name !== \"Pose\" || getPropertyValue<string>(poseNode, 2) !== \"BindPose\") {\r\n continue;\r\n }\r\n\r\n const matrices = new Map<number, Float64Array>();\r\n for (const poseChild of poseNode.children) {\r\n if (poseChild.name !== \"PoseNode\") {\r\n continue;\r\n }\r\n\r\n const nodeChild = findChildByName(poseChild, \"Node\");\r\n const matrixChild = findChildByName(poseChild, \"Matrix\");\r\n const nodeId = nodeChild?.properties[0]?.value;\r\n const matrixValue = matrixChild?.properties[0]?.value;\r\n if (typeof nodeId !== \"number\") {\r\n continue;\r\n }\r\n\r\n const matrix = toFloat64Array(matrixValue);\r\n if (matrix?.length === 16) {\r\n matrices.set(nodeId, matrix);\r\n }\r\n }\r\n\r\n if (matrices.has(modelId)) {\r\n return matrices;\r\n }\r\n }\r\n\r\n return new Map();\r\n}\r\n\r\nfunction buildSkeletonChildrenMap(skeletonModelIds: Set<number>, parentByModelId: Map<number, number>): Map<number, number[]> {\r\n const childrenByModelId = new Map<number, number[]>();\r\n\r\n for (const modelId of Array.from(skeletonModelIds)) {\r\n const parentId = parentByModelId.get(modelId);\r\n if (parentId === undefined) {\r\n continue;\r\n }\r\n\r\n if (!childrenByModelId.has(parentId)) {\r\n childrenByModelId.set(parentId, []);\r\n }\r\n childrenByModelId.get(parentId)!.push(modelId);\r\n }\r\n\r\n return childrenByModelId;\r\n}\r\n\r\nfunction collectSkeletonModelIds(boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>, objectMap: FBXObjectMap): Set<number> {\r\n const skeletonModelIds = new Set<number>(Array.from(boneModelMap.keys()));\r\n\r\n for (const modelId of Array.from(boneModelMap.keys())) {\r\n let parentId = findModelParentId(modelId, objectMap);\r\n while (parentId !== undefined) {\r\n const parentNode = objectMap.objects.get(parentId);\r\n if (!parentNode || parentNode.name !== \"Model\") {\r\n break;\r\n }\r\n\r\n skeletonModelIds.add(parentId);\r\n parentId = findModelParentId(parentId, objectMap);\r\n }\r\n }\r\n\r\n return skeletonModelIds;\r\n}\r\n\r\nfunction buildSkeletonParentMap(skeletonModelIds: Set<number>, objectMap: FBXObjectMap): Map<number, number> {\r\n const parentByModelId = new Map<number, number>();\r\n\r\n for (const modelId of Array.from(skeletonModelIds)) {\r\n let parentId = findModelParentId(modelId, objectMap);\r\n while (parentId !== undefined) {\r\n if (skeletonModelIds.has(parentId)) {\r\n parentByModelId.set(modelId, parentId);\r\n break;\r\n }\r\n parentId = findModelParentId(parentId, objectMap);\r\n }\r\n }\r\n\r\n return parentByModelId;\r\n}\r\n\r\nfunction findModelParentId(modelId: number, objectMap: FBXObjectMap): number | undefined {\r\n const parentConnection = objectMap.connections.find((conn) => conn.type === \"OO\" && conn.childId === modelId && objectMap.objects.get(conn.parentId)?.name === \"Model\");\r\n return parentConnection?.parentId;\r\n}\r\n\r\nexport function isSkeletonModel(modelNode: FBXNode): boolean {\r\n const subType = getPropertyValue<string>(modelNode, 2);\r\n return subType === \"Root\" || subType === \"LimbNode\";\r\n}\r\n\r\nexport function extractBoneTransform(modelNode: FBXNode): {\r\n translation: [number, number, number];\r\n rotation: [number, number, number];\r\n preRotation: [number, number, number];\r\n postRotation: [number, number, number];\r\n rotationPivot: [number, number, number];\r\n scalingPivot: [number, number, number];\r\n rotationOffset: [number, number, number];\r\n scalingOffset: [number, number, number];\r\n scale: [number, number, number];\r\n rotationOrder: number;\r\n inheritType: number;\r\n} {\r\n const translation: [number, number, number] = [0, 0, 0];\r\n const rotation: [number, number, number] = [0, 0, 0];\r\n const preRotation: [number, number, number] = [0, 0, 0];\r\n const postRotation: [number, number, number] = [0, 0, 0];\r\n const rotationPivot: [number, number, number] = [0, 0, 0];\r\n const scalingPivot: [number, number, number] = [0, 0, 0];\r\n const rotationOffset: [number, number, number] = [0, 0, 0];\r\n const scalingOffset: [number, number, number] = [0, 0, 0];\r\n const scale: [number, number, number] = [1, 1, 1];\r\n let rotationOrder = 0;\r\n let inheritType = 1;\r\n\r\n const props70 = findChildByName(modelNode, \"Properties70\");\r\n if (!props70) {\r\n return { translation, rotation, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, scale, rotationOrder, inheritType };\r\n }\r\n\r\n for (const p of props70.children) {\r\n if (p.name !== \"P\") {\r\n continue;\r\n }\r\n const propName = getPropertyValue<string>(p, 0);\r\n if (!propName) {\r\n continue;\r\n }\r\n\r\n switch (propName) {\r\n case \"Lcl Translation\":\r\n translation[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n translation[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n translation[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"Lcl Rotation\":\r\n rotation[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n rotation[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n rotation[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"PreRotation\":\r\n preRotation[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n preRotation[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n preRotation[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"PostRotation\":\r\n postRotation[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n postRotation[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n postRotation[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"RotationPivot\":\r\n rotationPivot[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n rotationPivot[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n rotationPivot[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"ScalingPivot\":\r\n scalingPivot[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n scalingPivot[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n scalingPivot[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"RotationOffset\":\r\n rotationOffset[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n rotationOffset[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n rotationOffset[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"ScalingOffset\":\r\n scalingOffset[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n scalingOffset[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n scalingOffset[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"Lcl Scaling\":\r\n scale[0] = toNumber(p.properties[4]?.value) ?? 1;\r\n scale[1] = toNumber(p.properties[5]?.value) ?? 1;\r\n scale[2] = toNumber(p.properties[6]?.value) ?? 1;\r\n break;\r\n case \"RotationOrder\":\r\n rotationOrder = toNumber(p.properties[4]?.value) ?? 0;\r\n break;\r\n case \"InheritType\":\r\n inheritType = toNumber(p.properties[4]?.value) ?? 1;\r\n break;\r\n }\r\n }\r\n\r\n return { translation, rotation, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, scale, rotationOrder, inheritType };\r\n}\r\n\r\nfunction extractClusterMatrices(clusterNode: FBXNode): {\r\n bindPoseMatrix: Float64Array | null;\r\n transformLinkMatrix: Float64Array | null;\r\n transformAssociateModelMatrix: Float64Array | null;\r\n clusterMode: FBXClusterMode;\r\n} {\r\n let bindPoseMatrix: Float64Array | null = null;\r\n let transformLinkMatrix: Float64Array | null = null;\r\n let transformAssociateModelMatrix: Float64Array | null = null;\r\n let clusterMode: FBXClusterMode = \"Normalize\";\r\n\r\n const transformNode = findChildByName(clusterNode, \"Transform\");\r\n if (transformNode && transformNode.properties[0]) {\r\n const val = transformNode.properties[0].value;\r\n if (val instanceof Float64Array && val.length === 16) {\r\n bindPoseMatrix = val;\r\n } else if (val instanceof Float32Array && val.length === 16) {\r\n bindPoseMatrix = new Float64Array(val);\r\n }\r\n }\r\n\r\n const transformLinkNode = findChildByName(clusterNode, \"TransformLink\");\r\n if (transformLinkNode && transformLinkNode.properties[0]) {\r\n const val = transformLinkNode.properties[0].value;\r\n if (val instanceof Float64Array && val.length === 16) {\r\n transformLinkMatrix = val;\r\n } else if (val instanceof Float32Array && val.length === 16) {\r\n transformLinkMatrix = new Float64Array(val);\r\n }\r\n }\r\n\r\n const transformAssociateModelNode = findChildByName(clusterNode, \"TransformAssociateModel\");\r\n if (transformAssociateModelNode && transformAssociateModelNode.properties[0]) {\r\n const val = transformAssociateModelNode.properties[0].value;\r\n if (val instanceof Float64Array && val.length === 16) {\r\n transformAssociateModelMatrix = val;\r\n } else if (val instanceof Float32Array && val.length === 16) {\r\n transformAssociateModelMatrix = new Float64Array(val);\r\n }\r\n }\r\n\r\n const modeNode = findChildByName(clusterNode, \"Mode\");\r\n const mode = modeNode ? getPropertyValue<string>(modeNode, 0) : undefined;\r\n if (mode === \"Normalize\" || mode === \"Additive\" || mode === \"TotalOne\") {\r\n clusterMode = mode;\r\n } else if (mode) {\r\n clusterMode = \"Unknown\";\r\n }\r\n\r\n return { bindPoseMatrix, transformLinkMatrix, transformAssociateModelMatrix, clusterMode };\r\n}\r\n\r\nfunction createBoneDiagnostics(\r\n modelId: number,\r\n boneName: string,\r\n isCluster: boolean,\r\n clusterMode: FBXClusterMode,\r\n bindPoseMatrix: Float64Array | null,\r\n transformLinkMatrix: Float64Array | null,\r\n transformAssociateModelMatrix: Float64Array | null,\r\n modelBindPoseMatrix: Float64Array | null\r\n): FBXSkinDiagnostic[] {\r\n if (!isCluster) {\r\n return [];\r\n }\r\n\r\n const diagnostics: FBXSkinDiagnostic[] = [];\r\n if (clusterMode === \"Additive\" || clusterMode === \"TotalOne\") {\r\n diagnostics.push({\r\n type: \"cluster-mode-runtime-unsupported\",\r\n message: `Cluster mode '${clusterMode}' is preserved but not applied by Babylon linear blend skinning.`,\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n if (!bindPoseMatrix) {\r\n diagnostics.push({\r\n type: \"missing-cluster-transform\",\r\n message: \"Cluster is missing Transform matrix; falling back to rest/bind-pose data.\",\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n if (!transformLinkMatrix) {\r\n diagnostics.push({\r\n type: \"missing-cluster-transform-link\",\r\n message: \"Cluster is missing TransformLink matrix; falling back to model bind pose or rest transform.\",\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n if (!modelBindPoseMatrix) {\r\n diagnostics.push({\r\n type: \"missing-bind-pose-matrix\",\r\n message: \"No BindPose matrix was found for this bone model.\",\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n if (transformAssociateModelMatrix) {\r\n diagnostics.push({\r\n type: \"associate-model-present\",\r\n message: \"TransformAssociateModel is preserved for future associate-model skinning semantics.\",\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n\r\n return diagnostics;\r\n}\r\n\r\n/**\r\n * Extract per-vertex bone indices and weights from cluster data.\r\n * Returns arrays indexed by control point index.\r\n */\r\nfunction extractVertexWeights(\r\n bones: FBXBoneData[],\r\n boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>,\r\n objectMap: FBXObjectMap\r\n): { boneIndices: number[][]; boneWeights: number[][] } {\r\n // We need to find the max vertex index to size our arrays\r\n let maxVertexIndex = 0;\r\n\r\n // First pass: find max vertex index\r\n for (const bone of bones) {\r\n const clusterInfo = boneModelMap.get(bone.modelId);\r\n if (!clusterInfo) {\r\n continue;\r\n }\r\n\r\n const indexesNode = findChildByName(clusterInfo.clusterNode, \"Indexes\");\r\n if (!indexesNode) {\r\n continue;\r\n }\r\n\r\n const indexes = toInt32Array(indexesNode.properties[0]?.value);\r\n if (!indexes) {\r\n continue;\r\n }\r\n\r\n for (let i = 0; i < indexes.length; i++) {\r\n if (indexes[i] > maxVertexIndex) {\r\n maxVertexIndex = indexes[i];\r\n }\r\n }\r\n }\r\n\r\n // Initialize arrays\r\n const vertexCount = maxVertexIndex + 1;\r\n const boneIndices: number[][] = new Array(vertexCount);\r\n const boneWeights: number[][] = new Array(vertexCount);\r\n for (let i = 0; i < vertexCount; i++) {\r\n boneIndices[i] = [];\r\n boneWeights[i] = [];\r\n }\r\n\r\n // Second pass: collect influences\r\n for (const bone of bones) {\r\n const clusterInfo = boneModelMap.get(bone.modelId);\r\n if (!clusterInfo) {\r\n continue;\r\n }\r\n\r\n const indexesNode = findChildByName(clusterInfo.clusterNode, \"Indexes\");\r\n const weightsNode = findChildByName(clusterInfo.clusterNode, \"Weights\");\r\n if (!indexesNode || !weightsNode) {\r\n continue;\r\n }\r\n\r\n const indexes = toInt32Array(indexesNode.properties[0]?.value);\r\n const weights = toFloat64Array(weightsNode.properties[0]?.value);\r\n if (!indexes || !weights) {\r\n continue;\r\n }\r\n\r\n for (let i = 0; i < indexes.length; i++) {\r\n const vertIdx = indexes[i];\r\n boneIndices[vertIdx].push(bone.index);\r\n boneWeights[vertIdx].push(weights[i]);\r\n }\r\n }\r\n\r\n // Sort by weight descending and cap to Babylon's primary + extra influence buffers.\r\n for (let i = 0; i < vertexCount; i++) {\r\n if (boneIndices[i].length === 0) {\r\n continue;\r\n }\r\n\r\n const pairs = boneIndices[i].map((bi, idx) => ({\r\n index: bi,\r\n weight: boneWeights[i][idx],\r\n }));\r\n pairs.sort((a, b) => b.weight - a.weight);\r\n const cappedPairs = pairs.slice(0, MAX_BONE_INFLUENCES);\r\n boneIndices[i] = cappedPairs.map((p) => p.index);\r\n boneWeights[i] = cappedPairs.map((p) => p.weight);\r\n }\r\n\r\n // Normalize weights to sum to 1.0\r\n for (let i = 0; i < vertexCount; i++) {\r\n const sum = boneWeights[i].reduce((a, b) => a + b, 0);\r\n if (sum > 0) {\r\n for (let j = 0; j < boneWeights[i].length; j++) {\r\n boneWeights[i][j] /= sum;\r\n }\r\n }\r\n }\r\n\r\n return { boneIndices, boneWeights };\r\n}\r\n\r\n// ── Utilities ──────────────────────────────────────────────────────────────────\r\n\r\nfunction toNumber(value: unknown): number | undefined {\r\n if (typeof value === \"number\") {\r\n return value;\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction toInt32Array(value: unknown): Int32Array | null {\r\n if (value instanceof Int32Array) {\r\n return value;\r\n }\r\n if (value instanceof Float64Array) {\r\n const result = new Int32Array(value.length);\r\n for (let i = 0; i < value.length; i++) {\r\n result[i] = Math.round(value[i]);\r\n }\r\n return result;\r\n }\r\n return null;\r\n}\r\n\r\nfunction toFloat64Array(value: unknown): Float64Array | null {\r\n if (value instanceof Float64Array) {\r\n return value;\r\n }\r\n if (value instanceof Float32Array) {\r\n return new Float64Array(value);\r\n }\r\n return null;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"skeleton.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/FBX/interpreter/skeleton.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */\nimport { extractNodeTransform, type FBXNodeTransformData } from \"./nodeTransform\";\nimport { getPropertyTemplate, type FBXPropertyTemplate, type FBXPropertyTemplateMap } from \"./propertyTemplates\";\nimport { type FBXNode, findChildByName, getPropertyValue, cleanFBXName, getNodeArray } from \"../types/fbxTypes\";\n\nimport { type FBXObjectMap, getChildren } from \"./connections\";\n\nconst MAX_BONE_INFLUENCES = 8;\n\nexport type FBXClusterMode = \"Normalize\" | \"Additive\" | \"TotalOne\" | \"Unknown\";\n\nexport interface FBXSkinDiagnostic {\n type: \"cluster-mode-runtime-unsupported\" | \"missing-cluster-transform\" | \"missing-cluster-transform-link\" | \"missing-bind-pose-matrix\" | \"associate-model-present\";\n message: string;\n boneModelId?: number;\n boneName?: string;\n clusterMode?: FBXClusterMode;\n}\n\n/** Represents a single bone (cluster) in the FBX skeleton */\nexport interface FBXBoneData {\n /** The Model node ID for this bone */\n modelId: number;\n /** Bone name (from the Model node) */\n name: string;\n /** Index of this bone in the skeleton */\n index: number;\n /** Index of the parent bone (-1 for root) */\n parentIndex: number;\n /** Whether this bone corresponds to an FBX Cluster with vertex weights */\n isCluster: boolean;\n /** Local translation from parent (Lcl Translation) */\n translation: [number, number, number];\n /** Local rotation in degrees (Lcl Rotation) */\n rotation: [number, number, number];\n /** Pre-rotation in degrees (applied before Lcl Rotation) */\n preRotation: [number, number, number];\n /** Post-rotation in degrees (applied after Lcl Rotation, inverted) */\n postRotation: [number, number, number];\n /** Rotation pivot point */\n rotationPivot: [number, number, number];\n /** Scaling pivot point */\n scalingPivot: [number, number, number];\n /** Rotation offset */\n rotationOffset: [number, number, number];\n /** Scaling offset */\n scalingOffset: [number, number, number];\n /** Local scale (Lcl Scaling) */\n scale: [number, number, number];\n /** Rotation order: 0=XYZ, 1=XZY, 2=YZX, 3=YXZ, 4=ZXY, 5=ZYX */\n rotationOrder: number;\n /** FBX transform inheritance mode. 0=RrSs, 1=RSrs, 2=Rrs */\n inheritType: number;\n /** Cluster skinning mode */\n clusterMode: FBXClusterMode;\n /** Bind pose transform matrix (cluster Transform, 4x4) */\n bindPoseMatrix: Float64Array | null;\n /** Bone's world transform at bind time (cluster TransformLink, 4x4) */\n transformLinkMatrix: Float64Array | null;\n /** Associate model world transform at bind time (cluster TransformAssociateModel, 4x4) */\n transformAssociateModelMatrix: Float64Array | null;\n /** Model's absolute matrix from the FBX BindPose, when present */\n modelBindPoseMatrix: Float64Array | null;\n /** Recoverable bind/skinning diagnostics for this bone */\n diagnostics: FBXSkinDiagnostic[];\n}\n\n/** Represents a skin deformer with its clusters */\nexport interface FBXSkinData {\n /** Skin deformer ID */\n id: number;\n /** Geometry ID this skin is attached to */\n geometryId: number;\n /** Mesh model world matrix from the FBX BindPose, when present */\n meshBindPoseMatrix: Float64Array | null;\n /** Bones in this skeleton */\n bones: FBXBoneData[];\n /** Per-vertex bone indices, sorted by descending weight and capped for Babylon skinning */\n boneIndices: number[][];\n /** Per-vertex bone weights, matching boneIndices */\n boneWeights: number[][];\n /** Recoverable skinning/bind diagnostics */\n diagnostics: FBXSkinDiagnostic[];\n}\n\n/**\n * Extract all skin deformers from the FBX scene.\n * Returns skin data including bone hierarchy and vertex weights.\n */\n// Template used to resolve bone transform defaults while extractSkins runs (bones are Models).\nlet currentModelTemplate: FBXPropertyTemplate | undefined;\n\nexport function extractSkins(objectMap: FBXObjectMap, propertyTemplates?: FBXPropertyTemplateMap): FBXSkinData[] {\n currentModelTemplate = propertyTemplates ? (getPropertyTemplate(propertyTemplates, \"Model\", \"FbxNode\") ?? getPropertyTemplate(propertyTemplates, \"Model\")) : undefined;\n const skins: FBXSkinData[] = [];\n\n for (const [id, node] of Array.from(objectMap.objects)) {\n if (node.name === \"Deformer\" && getPropertyValue<string>(node, 2) === \"Skin\") {\n const skin = extractSkin(id, node, objectMap);\n if (skin) {\n skins.push(skin);\n }\n }\n }\n\n return skins;\n}\n\nfunction extractSkin(skinId: number, _skinNode: FBXNode, objectMap: FBXObjectMap): FBXSkinData | null {\n // Find the geometry this skin is attached to\n // Skin is a child of the geometry in FBX connection graph\n const skinParent = objectMap.parentOf.get(skinId);\n if (!skinParent) {\n return null;\n }\n\n const geometryId = skinParent.id;\n const geometryNode = objectMap.objects.get(geometryId);\n if (!geometryNode || geometryNode.name !== \"Geometry\") {\n return null;\n }\n const modelParent = objectMap.parentOf.get(geometryId);\n const modelParentNode = modelParent ? objectMap.objects.get(modelParent.id) : undefined;\n const meshModelId = modelParentNode?.name === \"Model\" ? modelParent!.id : undefined;\n\n // Find all clusters (children of this skin)\n const clusterEntries = getChildren(objectMap, skinId, \"Deformer\");\n if (clusterEntries.length === 0) {\n return null;\n }\n\n // For each cluster, find the connected bone Model\n // Connection graph: BoneModel → Cluster (bone is child of cluster)\n const boneModelMap = new Map<number, { clusterId: number; clusterNode: FBXNode }>();\n for (const { id: clusterId, node: clusterNode } of clusterEntries) {\n const subType = getPropertyValue<string>(clusterNode, 2);\n if (subType !== \"Cluster\") {\n continue;\n }\n\n // The bone Model is a child of the Cluster\n const boneChildren = getChildren(objectMap, clusterId, \"Model\");\n if (boneChildren.length > 0) {\n boneModelMap.set(boneChildren[0].id, { clusterId, clusterNode });\n }\n }\n\n // Build bone hierarchy from Model parent-child relationships. Include\n // skeleton-like ancestors even when they are not weighted clusters; some\n // rigs (for example 3ds Max Biped) animate a non-cluster root above the\n // clustered bones.\n const bindPoseMatrices = extractBindPoseMatrices(geometryId, objectMap);\n const skinDiagnostics: FBXSkinDiagnostic[] = [];\n const bones = buildBoneHierarchy(boneModelMap, bindPoseMatrices, objectMap, skinDiagnostics);\n if (bones.length === 0) {\n return null;\n }\n\n // Extract per-vertex weights from clusters\n const { boneIndices, boneWeights } = extractVertexWeights(bones, boneModelMap, objectMap);\n\n return {\n id: skinId,\n geometryId,\n meshBindPoseMatrix: meshModelId !== undefined ? (bindPoseMatrices.get(meshModelId) ?? null) : null,\n bones,\n boneIndices,\n boneWeights,\n diagnostics: skinDiagnostics,\n };\n}\n\n/**\n * Build a flat ordered bone list with parent indices from the FBX Model hierarchy.\n */\nfunction buildBoneHierarchy(\n boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>,\n bindPoseMatrices: Map<number, Float64Array>,\n objectMap: FBXObjectMap,\n skinDiagnostics: FBXSkinDiagnostic[]\n): FBXBoneData[] {\n const bones: FBXBoneData[] = [];\n const visited = new Set<number>();\n const skeletonModelIds = collectSkeletonModelIds(boneModelMap, objectMap);\n const parentByModelId = buildSkeletonParentMap(skeletonModelIds, objectMap);\n const childrenByModelId = buildSkeletonChildrenMap(skeletonModelIds, parentByModelId);\n\n const rootBoneIds = Array.from(skeletonModelIds).filter((modelId) => !parentByModelId.has(modelId));\n\n // BFS to build ordered list\n const queue: { modelId: number; parentIndex: number }[] = rootBoneIds.map((id) => ({\n modelId: id,\n parentIndex: -1,\n }));\n\n while (queue.length > 0) {\n const { modelId, parentIndex } = queue.shift()!;\n if (visited.has(modelId)) {\n continue;\n }\n visited.add(modelId);\n\n const modelNode = objectMap.objects.get(modelId);\n if (!modelNode) {\n continue;\n }\n\n const boneIndex = bones.length;\n\n const clusterInfo = boneModelMap.get(modelId);\n const transform = extractBoneTransform(modelNode);\n const { bindPoseMatrix, transformLinkMatrix, transformAssociateModelMatrix, clusterMode } = clusterInfo\n ? extractClusterMatrices(clusterInfo.clusterNode)\n : { bindPoseMatrix: null, transformLinkMatrix: null, transformAssociateModelMatrix: null, clusterMode: \"Unknown\" as const };\n const diagnostics = createBoneDiagnostics(\n modelId,\n cleanFBXName(getPropertyValue<string>(modelNode, 1) ?? `Bone${boneIndex}`),\n clusterInfo !== undefined,\n clusterMode,\n bindPoseMatrix,\n transformLinkMatrix,\n transformAssociateModelMatrix,\n bindPoseMatrices.get(modelId) ?? null\n );\n skinDiagnostics.push(...diagnostics);\n\n bones.push({\n modelId,\n name: cleanFBXName(getPropertyValue<string>(modelNode, 1) ?? `Bone${boneIndex}`),\n index: boneIndex,\n parentIndex,\n isCluster: clusterInfo !== undefined,\n translation: transform.translation,\n rotation: transform.rotation,\n preRotation: transform.preRotation,\n postRotation: transform.postRotation,\n rotationPivot: transform.rotationPivot,\n scalingPivot: transform.scalingPivot,\n rotationOffset: transform.rotationOffset,\n scalingOffset: transform.scalingOffset,\n scale: transform.scale,\n rotationOrder: transform.rotationOrder,\n inheritType: transform.inheritType,\n clusterMode,\n bindPoseMatrix,\n transformLinkMatrix,\n transformAssociateModelMatrix,\n modelBindPoseMatrix: bindPoseMatrices.get(modelId) ?? null,\n diagnostics,\n });\n\n for (const childId of childrenByModelId.get(modelId) ?? []) {\n if (!visited.has(childId)) {\n queue.push({ modelId: childId, parentIndex: boneIndex });\n }\n }\n }\n\n return bones;\n}\n\nfunction extractBindPoseMatrices(geometryId: number, objectMap: FBXObjectMap): Map<number, Float64Array> {\n const modelParent = objectMap.parentOf.get(geometryId);\n const modelParentNode = modelParent ? objectMap.objects.get(modelParent.id) : undefined;\n const modelId = modelParentNode?.name === \"Model\" ? modelParent!.id : undefined;\n if (modelId === undefined) {\n return new Map();\n }\n\n for (const [, poseNode] of Array.from(objectMap.objects)) {\n if (poseNode.name !== \"Pose\" || getPropertyValue<string>(poseNode, 2) !== \"BindPose\") {\n continue;\n }\n\n const matrices = new Map<number, Float64Array>();\n for (const poseChild of poseNode.children) {\n if (poseChild.name !== \"PoseNode\") {\n continue;\n }\n\n const nodeChild = findChildByName(poseChild, \"Node\");\n const matrixChild = findChildByName(poseChild, \"Matrix\");\n const nodeId = nodeChild?.properties[0]?.value;\n const matrixValue = getNodeArray(matrixChild);\n if (typeof nodeId !== \"number\") {\n continue;\n }\n\n const matrix = toFloat64Array(matrixValue);\n if (matrix?.length === 16) {\n matrices.set(nodeId, matrix);\n }\n }\n\n if (matrices.has(modelId)) {\n return matrices;\n }\n }\n\n return new Map();\n}\n\nfunction buildSkeletonChildrenMap(skeletonModelIds: Set<number>, parentByModelId: Map<number, number>): Map<number, number[]> {\n const childrenByModelId = new Map<number, number[]>();\n\n for (const modelId of Array.from(skeletonModelIds)) {\n const parentId = parentByModelId.get(modelId);\n if (parentId === undefined) {\n continue;\n }\n\n if (!childrenByModelId.has(parentId)) {\n childrenByModelId.set(parentId, []);\n }\n childrenByModelId.get(parentId)!.push(modelId);\n }\n\n return childrenByModelId;\n}\n\nfunction collectSkeletonModelIds(boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>, objectMap: FBXObjectMap): Set<number> {\n const skeletonModelIds = new Set<number>(Array.from(boneModelMap.keys()));\n\n for (const modelId of Array.from(boneModelMap.keys())) {\n let parentId = findModelParentId(modelId, objectMap);\n while (parentId !== undefined) {\n const parentNode = objectMap.objects.get(parentId);\n if (!parentNode || parentNode.name !== \"Model\") {\n break;\n }\n\n skeletonModelIds.add(parentId);\n parentId = findModelParentId(parentId, objectMap);\n }\n }\n\n return skeletonModelIds;\n}\n\nfunction buildSkeletonParentMap(skeletonModelIds: Set<number>, objectMap: FBXObjectMap): Map<number, number> {\n const parentByModelId = new Map<number, number>();\n\n for (const modelId of Array.from(skeletonModelIds)) {\n let parentId = findModelParentId(modelId, objectMap);\n while (parentId !== undefined) {\n if (skeletonModelIds.has(parentId)) {\n parentByModelId.set(modelId, parentId);\n break;\n }\n parentId = findModelParentId(parentId, objectMap);\n }\n }\n\n return parentByModelId;\n}\n\nfunction findModelParentId(modelId: number, objectMap: FBXObjectMap): number | undefined {\n const parentConnection = objectMap.connections.find((conn) => conn.type === \"OO\" && conn.childId === modelId && objectMap.objects.get(conn.parentId)?.name === \"Model\");\n return parentConnection?.parentId;\n}\n\nexport function isSkeletonModel(modelNode: FBXNode): boolean {\n const subType = getPropertyValue<string>(modelNode, 2);\n return subType === \"Root\" || subType === \"LimbNode\";\n}\n\nexport function extractBoneTransform(modelNode: FBXNode, template?: FBXPropertyTemplate): FBXNodeTransformData {\n return extractNodeTransform(modelNode, template ?? currentModelTemplate);\n}\n\nfunction extractClusterMatrices(clusterNode: FBXNode): {\n bindPoseMatrix: Float64Array | null;\n transformLinkMatrix: Float64Array | null;\n transformAssociateModelMatrix: Float64Array | null;\n clusterMode: FBXClusterMode;\n} {\n let bindPoseMatrix: Float64Array | null = null;\n let transformLinkMatrix: Float64Array | null = null;\n let transformAssociateModelMatrix: Float64Array | null = null;\n let clusterMode: FBXClusterMode = \"Normalize\";\n\n const transformNode = findChildByName(clusterNode, \"Transform\");\n if (transformNode && transformNode.properties[0]) {\n const val = getNodeArray(transformNode);\n if (val instanceof Float64Array && val.length === 16) {\n bindPoseMatrix = val;\n } else if (val instanceof Float32Array && val.length === 16) {\n bindPoseMatrix = new Float64Array(val);\n }\n }\n\n const transformLinkNode = findChildByName(clusterNode, \"TransformLink\");\n if (transformLinkNode && transformLinkNode.properties[0]) {\n const val = getNodeArray(transformLinkNode);\n if (val instanceof Float64Array && val.length === 16) {\n transformLinkMatrix = val;\n } else if (val instanceof Float32Array && val.length === 16) {\n transformLinkMatrix = new Float64Array(val);\n }\n }\n\n const transformAssociateModelNode = findChildByName(clusterNode, \"TransformAssociateModel\");\n if (transformAssociateModelNode && transformAssociateModelNode.properties[0]) {\n const val = getNodeArray(transformAssociateModelNode);\n if (val instanceof Float64Array && val.length === 16) {\n transformAssociateModelMatrix = val;\n } else if (val instanceof Float32Array && val.length === 16) {\n transformAssociateModelMatrix = new Float64Array(val);\n }\n }\n\n const modeNode = findChildByName(clusterNode, \"Mode\");\n const mode = modeNode ? getPropertyValue<string>(modeNode, 0) : undefined;\n if (mode === \"Normalize\" || mode === \"Additive\" || mode === \"TotalOne\") {\n clusterMode = mode;\n } else if (mode) {\n clusterMode = \"Unknown\";\n }\n\n return { bindPoseMatrix, transformLinkMatrix, transformAssociateModelMatrix, clusterMode };\n}\n\nfunction createBoneDiagnostics(\n modelId: number,\n boneName: string,\n isCluster: boolean,\n clusterMode: FBXClusterMode,\n bindPoseMatrix: Float64Array | null,\n transformLinkMatrix: Float64Array | null,\n transformAssociateModelMatrix: Float64Array | null,\n modelBindPoseMatrix: Float64Array | null\n): FBXSkinDiagnostic[] {\n if (!isCluster) {\n return [];\n }\n\n const diagnostics: FBXSkinDiagnostic[] = [];\n if (clusterMode === \"Additive\" || clusterMode === \"TotalOne\") {\n diagnostics.push({\n type: \"cluster-mode-runtime-unsupported\",\n message: `Cluster mode '${clusterMode}' is preserved but not applied by Babylon linear blend skinning.`,\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n if (!bindPoseMatrix) {\n diagnostics.push({\n type: \"missing-cluster-transform\",\n message: \"Cluster is missing Transform matrix; falling back to rest/bind-pose data.\",\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n if (!transformLinkMatrix) {\n diagnostics.push({\n type: \"missing-cluster-transform-link\",\n message: \"Cluster is missing TransformLink matrix; falling back to model bind pose or rest transform.\",\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n if (!modelBindPoseMatrix) {\n diagnostics.push({\n type: \"missing-bind-pose-matrix\",\n message: \"No BindPose matrix was found for this bone model.\",\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n if (transformAssociateModelMatrix) {\n diagnostics.push({\n type: \"associate-model-present\",\n message: \"TransformAssociateModel is preserved for future associate-model skinning semantics.\",\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n\n return diagnostics;\n}\n\n/**\n * Extract per-vertex bone indices and weights from cluster data.\n * Returns arrays indexed by control point index.\n */\nfunction extractVertexWeights(\n bones: FBXBoneData[],\n boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>,\n objectMap: FBXObjectMap\n): { boneIndices: number[][]; boneWeights: number[][] } {\n // We need to find the max vertex index to size our arrays\n let maxVertexIndex = 0;\n\n // First pass: find max vertex index\n for (const bone of bones) {\n const clusterInfo = boneModelMap.get(bone.modelId);\n if (!clusterInfo) {\n continue;\n }\n\n const indexesNode = findChildByName(clusterInfo.clusterNode, \"Indexes\");\n if (!indexesNode) {\n continue;\n }\n\n const indexes = toInt32Array(getNodeArray(indexesNode));\n if (!indexes) {\n continue;\n }\n\n for (let i = 0; i < indexes.length; i++) {\n if (indexes[i] > maxVertexIndex) {\n maxVertexIndex = indexes[i];\n }\n }\n }\n\n // Initialize arrays\n const vertexCount = maxVertexIndex + 1;\n const boneIndices: number[][] = new Array(vertexCount);\n const boneWeights: number[][] = new Array(vertexCount);\n for (let i = 0; i < vertexCount; i++) {\n boneIndices[i] = [];\n boneWeights[i] = [];\n }\n\n // Second pass: collect influences\n for (const bone of bones) {\n const clusterInfo = boneModelMap.get(bone.modelId);\n if (!clusterInfo) {\n continue;\n }\n\n const indexesNode = findChildByName(clusterInfo.clusterNode, \"Indexes\");\n const weightsNode = findChildByName(clusterInfo.clusterNode, \"Weights\");\n if (!indexesNode || !weightsNode) {\n continue;\n }\n\n const indexes = toInt32Array(getNodeArray(indexesNode));\n const weights = toFloat64Array(getNodeArray(weightsNode));\n if (!indexes || !weights) {\n continue;\n }\n\n for (let i = 0; i < indexes.length; i++) {\n const vertIdx = indexes[i];\n boneIndices[vertIdx].push(bone.index);\n boneWeights[vertIdx].push(weights[i]);\n }\n }\n\n // Sort by weight descending and cap to Babylon's primary + extra influence buffers.\n for (let i = 0; i < vertexCount; i++) {\n if (boneIndices[i].length === 0) {\n continue;\n }\n\n const pairs = boneIndices[i].map((bi, idx) => ({\n index: bi,\n weight: boneWeights[i][idx],\n }));\n pairs.sort((a, b) => b.weight - a.weight);\n const cappedPairs = pairs.slice(0, MAX_BONE_INFLUENCES);\n boneIndices[i] = cappedPairs.map((p) => p.index);\n boneWeights[i] = cappedPairs.map((p) => p.weight);\n }\n\n // Normalize weights to sum to 1.0\n for (let i = 0; i < vertexCount; i++) {\n const sum = boneWeights[i].reduce((a, b) => a + b, 0);\n if (sum > 0) {\n for (let j = 0; j < boneWeights[i].length; j++) {\n boneWeights[i][j] /= sum;\n }\n }\n }\n\n return { boneIndices, boneWeights };\n}\n\n// ── Utilities ──────────────────────────────────────────────────────────────────\n\nfunction toInt32Array(value: unknown): Int32Array | null {\n if (value instanceof Int32Array) {\n return value;\n }\n if (value instanceof Float64Array) {\n const result = new Int32Array(value.length);\n for (let i = 0; i < value.length; i++) {\n result[i] = Math.round(value[i]);\n }\n return result;\n }\n return null;\n}\n\nfunction toFloat64Array(value: unknown): Float64Array | null {\n if (value instanceof Float64Array) {\n return value;\n }\n if (value instanceof Float32Array) {\n return new Float64Array(value);\n }\n return null;\n}\n"]}
|
|
@@ -15,15 +15,43 @@ export function parseAsciiFBX(text) {
|
|
|
15
15
|
nodes.push(node);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
if (version >= 7200) {
|
|
19
|
+
reinterpretKeyAttrDataFloat(nodes);
|
|
20
|
+
}
|
|
18
21
|
return { version, nodes };
|
|
19
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* In ASCII files of version 7.2+, `KeyAttrDataFloat` holds the raw 32-bit float bit patterns written as integers
|
|
25
|
+
* (some elements are genuinely integers). Reinterpret them so tangent data reads like the binary format.
|
|
26
|
+
*/
|
|
27
|
+
function reinterpretKeyAttrDataFloat(nodes) {
|
|
28
|
+
for (const node of nodes) {
|
|
29
|
+
if (node.name === "KeyAttrDataFloat" && node.properties.length === 1 && node.properties[0].value instanceof Float64Array) {
|
|
30
|
+
const raw = node.properties[0].value;
|
|
31
|
+
const bits = new Int32Array(raw.length);
|
|
32
|
+
for (let i = 0; i < raw.length; i++) {
|
|
33
|
+
bits[i] = raw[i] | 0;
|
|
34
|
+
}
|
|
35
|
+
node.properties[0] = { type: "float32[]", value: new Float32Array(bits.buffer) };
|
|
36
|
+
}
|
|
37
|
+
if (node.children.length > 0) {
|
|
38
|
+
reinterpretKeyAttrDataFloat(node.children);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
20
42
|
/** Extract FBX version from the header comment (e.g. "; FBX 7.7.0 project file") */
|
|
21
43
|
function parseVersion(text) {
|
|
22
44
|
const match = text.match(/;\s*FBX\s+(\d+)\.(\d+)\.(\d+)/);
|
|
23
|
-
if (
|
|
24
|
-
|
|
45
|
+
if (match) {
|
|
46
|
+
return parseInt(match[1]) * 1000 + parseInt(match[2]) * 100 + parseInt(match[3]);
|
|
47
|
+
}
|
|
48
|
+
// Some files lack the header comment. The FBXHeaderExtension block carries the version too.
|
|
49
|
+
const ext = text.match(/FBXVersion:\s*(\d+)/);
|
|
50
|
+
if (ext) {
|
|
51
|
+
return parseInt(ext[1]);
|
|
25
52
|
}
|
|
26
|
-
|
|
53
|
+
// Fall back to the layout heuristic: Properties70 blocks only exist in 7.x files.
|
|
54
|
+
return text.includes("Properties70") ? 7000 : 6000;
|
|
27
55
|
}
|
|
28
56
|
// ── Tokenizer ──────────────────────────────────────────────────────────────────
|
|
29
57
|
var TokenType;
|
|
@@ -150,6 +178,10 @@ class Tokenizer {
|
|
|
150
178
|
if (this.pos < this.len) {
|
|
151
179
|
this.pos++; // skip closing quote
|
|
152
180
|
}
|
|
181
|
+
// The SDK writes double quotes inside strings as "
|
|
182
|
+
if (value.includes(""")) {
|
|
183
|
+
value = value.split(""").join('"');
|
|
184
|
+
}
|
|
153
185
|
return { type: 2 /* TokenType.String */, value, pos: startPos };
|
|
154
186
|
}
|
|
155
187
|
readNumber() {
|
|
@@ -158,6 +190,15 @@ class Tokenizer {
|
|
|
158
190
|
if (this.text[this.pos] === "-" || this.text[this.pos] === "+") {
|
|
159
191
|
this.pos++;
|
|
160
192
|
}
|
|
193
|
+
// Word-form specials: inf, infinity, nan, ind (any case), optionally signed, optionally with a
|
|
194
|
+
// parenthesised payload such as nan(ind) or nan(12345).
|
|
195
|
+
if (this.pos < this.len && this.isIdentStart(this.text[this.pos])) {
|
|
196
|
+
while (this.pos < this.len && this.isIdentStart(this.text[this.pos])) {
|
|
197
|
+
this.pos++;
|
|
198
|
+
}
|
|
199
|
+
this.skipSpecialNumberSuffix();
|
|
200
|
+
return { type: 1 /* TokenType.Number */, value: this.text.substring(startPos, this.pos), pos: startPos };
|
|
201
|
+
}
|
|
161
202
|
while (this.pos < this.len && this.isDigit(this.text[this.pos])) {
|
|
162
203
|
this.pos++;
|
|
163
204
|
}
|
|
@@ -177,6 +218,14 @@ class Tokenizer {
|
|
|
177
218
|
this.pos++;
|
|
178
219
|
}
|
|
179
220
|
}
|
|
221
|
+
// MSVC-style specials: 1.#INF, -1.#IND, 1.#QNAN, 1.#SNAN, 2.#IND12345678
|
|
222
|
+
if (this.pos < this.len && this.text[this.pos] === "#") {
|
|
223
|
+
this.pos++;
|
|
224
|
+
while (this.pos < this.len && (this.isIdentStart(this.text[this.pos]) || this.isDigit(this.text[this.pos]))) {
|
|
225
|
+
this.pos++;
|
|
226
|
+
}
|
|
227
|
+
this.skipSpecialNumberSuffix();
|
|
228
|
+
}
|
|
180
229
|
return { type: 1 /* TokenType.Number */, value: this.text.substring(startPos, this.pos), pos: startPos };
|
|
181
230
|
}
|
|
182
231
|
readIdentifier() {
|
|
@@ -184,25 +233,57 @@ class Tokenizer {
|
|
|
184
233
|
while (this.pos < this.len && this.isIdentChar(this.text[this.pos])) {
|
|
185
234
|
this.pos++;
|
|
186
235
|
}
|
|
236
|
+
// Malformed special numbers such as "snan(" or "Nan((" lex as identifiers; swallow their parenthesised tail.
|
|
237
|
+
this.skipSpecialNumberSuffix();
|
|
187
238
|
return { type: 0 /* TokenType.Identifier */, value: this.text.substring(startPos, this.pos), pos: startPos };
|
|
188
239
|
}
|
|
240
|
+
/** Consumes a run of parentheses and alphanumerics that some writers append to nan/inf tokens. */
|
|
241
|
+
skipSpecialNumberSuffix() {
|
|
242
|
+
if (this.pos < this.len && this.text[this.pos] === "(") {
|
|
243
|
+
while (this.pos < this.len) {
|
|
244
|
+
const ch = this.text[this.pos];
|
|
245
|
+
if (ch === "(" || ch === ")" || this.isIdentChar(ch)) {
|
|
246
|
+
this.pos++;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
189
254
|
isDigit(ch) {
|
|
190
255
|
return ch >= "0" && ch <= "9";
|
|
191
256
|
}
|
|
192
257
|
isNumberStart(ch) {
|
|
193
|
-
if (this.isDigit(ch)) {
|
|
258
|
+
if (this.isDigit(ch) || ch === ".") {
|
|
194
259
|
return true;
|
|
195
260
|
}
|
|
196
261
|
if ((ch === "-" || ch === "+") && this.pos + 1 < this.len) {
|
|
197
|
-
|
|
262
|
+
const next = this.text[this.pos + 1];
|
|
263
|
+
return this.isDigit(next) || next === "." || isSpecialNumberWord(this.text.substring(this.pos + 1, this.pos + 10));
|
|
264
|
+
}
|
|
265
|
+
if (isSpecialNumberWord(this.text.substring(this.pos, this.pos + 9))) {
|
|
266
|
+
// Bare inf/nan words in value position; identifiers followed by ':' are node names and never match.
|
|
267
|
+
return !this.isFollowedByColon(this.pos);
|
|
198
268
|
}
|
|
199
269
|
return false;
|
|
200
270
|
}
|
|
271
|
+
isFollowedByColon(from) {
|
|
272
|
+
let p = from;
|
|
273
|
+
while (p < this.len && this.isIdentChar(this.text[p])) {
|
|
274
|
+
p++;
|
|
275
|
+
}
|
|
276
|
+
while (p < this.len && (this.text[p] === " " || this.text[p] === "\t")) {
|
|
277
|
+
p++;
|
|
278
|
+
}
|
|
279
|
+
return p < this.len && this.text[p] === ":";
|
|
280
|
+
}
|
|
201
281
|
isIdentStart(ch) {
|
|
202
282
|
return (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z") || ch === "_";
|
|
203
283
|
}
|
|
204
284
|
isIdentChar(ch) {
|
|
205
|
-
|
|
285
|
+
// '-' appears inside node names such as "Pre-Extrapolation" / "Post-Extrapolation".
|
|
286
|
+
return this.isIdentStart(ch) || this.isDigit(ch) || ch === "|" || ch === "-";
|
|
206
287
|
}
|
|
207
288
|
}
|
|
208
289
|
// ── Node Parsing ───────────────────────────────────────────────────────────────
|
|
@@ -247,7 +328,11 @@ function parseNodeFromTokens(tokenizer) {
|
|
|
247
328
|
const tok = tokenizer.next();
|
|
248
329
|
const numVal = parseNumericValue(tok.value);
|
|
249
330
|
if (Number.isInteger(numVal) && !tok.value.includes(".") && !tok.value.includes("e") && !tok.value.includes("E")) {
|
|
250
|
-
|
|
331
|
+
const property = { type: isInt32(numVal) ? "int32" : "int64", value: numVal };
|
|
332
|
+
if (!Number.isSafeInteger(numVal)) {
|
|
333
|
+
property.raw = canonicalIntegerText(tok.value);
|
|
334
|
+
}
|
|
335
|
+
properties.push(property);
|
|
251
336
|
}
|
|
252
337
|
else {
|
|
253
338
|
properties.push({ type: "float64", value: numVal });
|
|
@@ -310,7 +395,12 @@ function parseArrayValues(tokenizer, count) {
|
|
|
310
395
|
}
|
|
311
396
|
if (peek.type === 1 /* TokenType.Number */) {
|
|
312
397
|
const tok = tokenizer.next();
|
|
313
|
-
values.push(
|
|
398
|
+
values.push(parseNumericValue(tok.value));
|
|
399
|
+
}
|
|
400
|
+
else if (peek.type === 0 /* TokenType.Identifier */ && !tokenizer.isNextNodeStart()) {
|
|
401
|
+
// Unrecognised nan/inf spellings ("snan", "infty", "ind") still count as values.
|
|
402
|
+
const tok = tokenizer.next();
|
|
403
|
+
values.push(parseNumericValue(tok.value));
|
|
314
404
|
}
|
|
315
405
|
else {
|
|
316
406
|
break;
|
|
@@ -321,8 +411,28 @@ function parseArrayValues(tokenizer, count) {
|
|
|
321
411
|
}
|
|
322
412
|
return values;
|
|
323
413
|
}
|
|
414
|
+
/** Matches a leading inf/infinity/nan/ind word (case-insensitive) at the start of the string. */
|
|
415
|
+
function isSpecialNumberWord(str) {
|
|
416
|
+
return /^(?:inf(?:inity)?|nan|ind)(?![A-Za-z0-9_|])/i.test(str);
|
|
417
|
+
}
|
|
324
418
|
function parseNumericValue(str) {
|
|
325
|
-
|
|
419
|
+
const n = Number(str);
|
|
420
|
+
if (!Number.isNaN(n)) {
|
|
421
|
+
return n;
|
|
422
|
+
}
|
|
423
|
+
// "1.#INF", "-1.#IND", "1.#QNAN", "inf", "-Infinity", "nan", "nan(ind)", "infty"
|
|
424
|
+
const sign = str.startsWith("-") ? -1 : 1;
|
|
425
|
+
const body = str.replace(/^[+-]/, "").replace(/\(.*$/, "");
|
|
426
|
+
if (/#INF/i.test(body) || /^inf/i.test(body)) {
|
|
427
|
+
return sign * Infinity;
|
|
428
|
+
}
|
|
429
|
+
return NaN;
|
|
430
|
+
}
|
|
431
|
+
/** Integer text without sign prefix noise or leading zeros, so equal values produce equal keys. */
|
|
432
|
+
function canonicalIntegerText(text) {
|
|
433
|
+
const negative = text.startsWith("-");
|
|
434
|
+
const digits = text.replace(/^[+-]/, "").replace(/^0+(?=\d)/, "");
|
|
435
|
+
return negative && digits !== "0" ? `-${digits}` : digits;
|
|
326
436
|
}
|
|
327
437
|
function isInt32(value) {
|
|
328
438
|
return value >= -2147483648 && value <= 2147483647;
|