@babylonjs/loaders 9.11.0 → 9.12.1

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.
Files changed (77) hide show
  1. package/FBX/fbxFileLoader.d.ts +194 -0
  2. package/FBX/fbxFileLoader.js +2440 -0
  3. package/FBX/fbxFileLoader.js.map +1 -0
  4. package/FBX/fbxFileLoader.metadata.d.ts +11 -0
  5. package/FBX/fbxFileLoader.metadata.js +11 -0
  6. package/FBX/fbxFileLoader.metadata.js.map +1 -0
  7. package/FBX/index.d.ts +3 -0
  8. package/FBX/index.js +3 -0
  9. package/FBX/index.js.map +1 -0
  10. package/FBX/interpreter/animation.d.ts +122 -0
  11. package/FBX/interpreter/animation.js +648 -0
  12. package/FBX/interpreter/animation.js.map +1 -0
  13. package/FBX/interpreter/blendShapes.d.ts +44 -0
  14. package/FBX/interpreter/blendShapes.js +192 -0
  15. package/FBX/interpreter/blendShapes.js.map +1 -0
  16. package/FBX/interpreter/connections.d.ts +95 -0
  17. package/FBX/interpreter/connections.js +233 -0
  18. package/FBX/interpreter/connections.js.map +1 -0
  19. package/FBX/interpreter/fbxInterpreter.d.ts +149 -0
  20. package/FBX/interpreter/fbxInterpreter.js +496 -0
  21. package/FBX/interpreter/fbxInterpreter.js.map +1 -0
  22. package/FBX/interpreter/geometry.d.ts +55 -0
  23. package/FBX/interpreter/geometry.js +573 -0
  24. package/FBX/interpreter/geometry.js.map +1 -0
  25. package/FBX/interpreter/materials.d.ts +50 -0
  26. package/FBX/interpreter/materials.js +144 -0
  27. package/FBX/interpreter/materials.js.map +1 -0
  28. package/FBX/interpreter/propertyTemplates.d.ts +22 -0
  29. package/FBX/interpreter/propertyTemplates.js +125 -0
  30. package/FBX/interpreter/propertyTemplates.js.map +1 -0
  31. package/FBX/interpreter/rig.d.ts +20 -0
  32. package/FBX/interpreter/rig.js +259 -0
  33. package/FBX/interpreter/rig.js.map +1 -0
  34. package/FBX/interpreter/sceneDiagnostics.d.ts +14 -0
  35. package/FBX/interpreter/sceneDiagnostics.js +55 -0
  36. package/FBX/interpreter/sceneDiagnostics.js.map +1 -0
  37. package/FBX/interpreter/skeleton.d.ts +93 -0
  38. package/FBX/interpreter/skeleton.js +515 -0
  39. package/FBX/interpreter/skeleton.js.map +1 -0
  40. package/FBX/interpreter/transform.d.ts +21 -0
  41. package/FBX/interpreter/transform.js +92 -0
  42. package/FBX/interpreter/transform.js.map +1 -0
  43. package/FBX/parsers/fbxAsciiParser.d.ts +5 -0
  44. package/FBX/parsers/fbxAsciiParser.js +330 -0
  45. package/FBX/parsers/fbxAsciiParser.js.map +1 -0
  46. package/FBX/parsers/fbxBinaryParser.d.ts +6 -0
  47. package/FBX/parsers/fbxBinaryParser.js +255 -0
  48. package/FBX/parsers/fbxBinaryParser.js.map +1 -0
  49. package/FBX/parsers/zlibInflate.d.ts +7 -0
  50. package/FBX/parsers/zlibInflate.js +350 -0
  51. package/FBX/parsers/zlibInflate.js.map +1 -0
  52. package/FBX/types/fbxTypes.d.ts +54 -0
  53. package/FBX/types/fbxTypes.js +66 -0
  54. package/FBX/types/fbxTypes.js.map +1 -0
  55. package/SPLAT/gaussianSplattingStream.d.ts +341 -0
  56. package/SPLAT/gaussianSplattingStream.js +976 -0
  57. package/SPLAT/gaussianSplattingStream.js.map +1 -0
  58. package/SPLAT/gaussianSplattingWorkBuffer.d.ts +51 -0
  59. package/SPLAT/gaussianSplattingWorkBuffer.js +159 -0
  60. package/SPLAT/gaussianSplattingWorkBuffer.js.map +1 -0
  61. package/SPLAT/gaussianSplattingWorkBufferShaders.d.ts +25 -0
  62. package/SPLAT/gaussianSplattingWorkBufferShaders.js +255 -0
  63. package/SPLAT/gaussianSplattingWorkBufferShaders.js.map +1 -0
  64. package/SPLAT/index.d.ts +1 -0
  65. package/SPLAT/index.js +1 -0
  66. package/SPLAT/index.js.map +1 -1
  67. package/SPLAT/sog.js +18 -16
  68. package/SPLAT/sog.js.map +1 -1
  69. package/SPLAT/splatFileLoader.d.ts +8 -0
  70. package/SPLAT/splatFileLoader.js +49 -0
  71. package/SPLAT/splatFileLoader.js.map +1 -1
  72. package/dynamic.js +9 -0
  73. package/dynamic.js.map +1 -1
  74. package/index.d.ts +1 -0
  75. package/index.js +1 -0
  76. package/index.js.map +1 -1
  77. package/package.json +3 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/FBX/interpreter/animation.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\n/** FBX time units: 46186158000 ticks per second */\r\nconst FBX_TIME_UNIT = 46186158000;\r\nconst KEY_ATTR_DATA_STRIDE = 4;\r\nconst SAMPLED_CURVE_MIN_KEY_COUNT = 8;\r\nconst SAMPLED_CURVE_MAX_INTERVAL_SECONDS = 1 / 23;\r\nconst SAMPLED_CURVE_UNIFORM_TOLERANCE_RATIO = 0.05;\r\nconst SAMPLED_CURVE_LINEAR_DEVIATION_RATIO = 0.01;\r\nconst SAMPLED_CURVE_LINEAR_DEVIATION_ABSOLUTE = 1e-4;\r\nconst SAMPLED_CURVE_DEGENERATE_SLOPE_ABSOLUTE = 1e-5;\r\nconst SAMPLED_CURVE_COMMON_FPS = [24, 25, 30, 48, 50, 60, 100, 120];\r\n\r\nexport type FBXInterpolationType = \"constant\" | \"linear\" | \"cubic\";\r\n\r\n/** A single keyframe */\r\nexport interface FBXKeyframe {\r\n /** Time in seconds */\r\n time: number;\r\n /** Value at this keyframe */\r\n value: number;\r\n /** Interpolation used from this key to the next key */\r\n interpolation: FBXInterpolationType;\r\n /** Constant interpolation variant */\r\n constantMode?: \"standard\" | \"next\";\r\n /** Cubic outgoing slope in value units per second */\r\n rightSlope?: number;\r\n /** Cubic incoming slope for the next key, in value units per second */\r\n nextLeftSlope?: number;\r\n}\r\n\r\n/** An animation curve (one axis of one property) */\r\nexport interface FBXCurveData {\r\n /** Channel: \"d|X\", \"d|Y\", \"d|Z\" */\r\n channel: string;\r\n /** Keyframes */\r\n keys: FBXKeyframe[];\r\n /** True for baked sample curves that should be connected as linear samples */\r\n isSampled?: boolean;\r\n}\r\n\r\n/** An animation curve node (T/R/S for one bone) */\r\nexport interface FBXCurveNodeData {\r\n /** Property type: \"T\" (translation), \"R\" (rotation), \"S\" (scale) */\r\n type: string;\r\n /** Target model (bone) ID */\r\n targetModelId: number;\r\n /** Curves for each axis */\r\n curves: FBXCurveData[];\r\n}\r\n\r\n/** Unsupported animation curve node preserved for diagnostics and future support. */\r\nexport interface FBXUnsupportedCurveNodeData {\r\n /** Raw AnimationCurveNode property type/name */\r\n type: string;\r\n /** CurveNode object ID */\r\n id: number;\r\n /** Target object ID if the curve node is connected to an object/property */\r\n targetId: number | null;\r\n /** OP connection property name on the target, e.g. Visibility */\r\n propertyName?: string;\r\n /** Number of connected animation curves that were ignored */\r\n curveCount: number;\r\n /** Connected curves preserved for diagnostics and future runtime support */\r\n curves: FBXCurveData[];\r\n /** Local default values stored on the unsupported curve node */\r\n defaultValues: Record<string, number>;\r\n}\r\n\r\n/** Recoverable animation import issue. */\r\nexport interface FBXAnimationDiagnostic {\r\n /** Diagnostic category. */\r\n type: \"multiple-animation-layers\" | \"unsupported-layer-blend-mode\" | \"partial-layer-weight\" | \"unsupported-curve-node\";\r\n /** Human-readable diagnostic message. */\r\n message: string;\r\n /** Animation layer name associated with the diagnostic, if applicable. */\r\n layerName?: string;\r\n /** AnimationCurveNode object ID associated with the diagnostic, if applicable. */\r\n curveNodeId?: number;\r\n /** AnimationCurveNode type/name associated with the diagnostic, if applicable. */\r\n curveNodeType?: string;\r\n /** Target object ID associated with the diagnostic, if applicable. */\r\n targetId?: number | null;\r\n /** Target property name associated with the diagnostic, if applicable. */\r\n propertyName?: string;\r\n}\r\n\r\n/** Animation layer with blend mode info */\r\nexport interface FBXAnimationLayerData {\r\n /** Layer name */\r\n name: string;\r\n /** Layer weight (0-100, default 100) */\r\n weight: number;\r\n /** Layer weight normalized to 0-1 */\r\n normalizedWeight: number;\r\n /** Blend mode: 0=Additive, 1=Override, 2=OverridePassthrough */\r\n blendMode: number;\r\n /** Curve nodes in this layer */\r\n curveNodes: FBXCurveNodeData[];\r\n /** Unsupported/non-TRS curve nodes preserved for diagnostics */\r\n unsupportedCurveNodes: FBXUnsupportedCurveNodeData[];\r\n /** Recoverable layer diagnostics */\r\n diagnostics: FBXAnimationDiagnostic[];\r\n}\r\n\r\n/** One animation clip (AnimationStack) */\r\nexport interface FBXAnimationStackData {\r\n /** Animation name */\r\n name: string;\r\n /** Clip start in seconds after any keyframe rebasing */\r\n startTime: number;\r\n /** Clip stop in seconds after any keyframe rebasing */\r\n stopTime: number;\r\n /** Duration in seconds */\r\n duration: number;\r\n /** Per-bone curve nodes (flattened from all layers for backward compat) */\r\n curveNodes: FBXCurveNodeData[];\r\n /** Animation layers (preserves blend mode info) */\r\n layers: FBXAnimationLayerData[];\r\n /** Unsupported/non-TRS curve nodes preserved for diagnostics */\r\n unsupportedCurveNodes: FBXUnsupportedCurveNodeData[];\r\n /** Recoverable animation diagnostics */\r\n diagnostics: FBXAnimationDiagnostic[];\r\n}\r\n\r\n/**\r\n * Extract all animation stacks from the FBX scene.\r\n */\r\nexport function extractAnimations(objectMap: FBXObjectMap): FBXAnimationStackData[] {\r\n const stacks: FBXAnimationStackData[] = [];\r\n\r\n for (const [id, node] of Array.from(objectMap.objects)) {\r\n if (node.name === \"AnimationStack\") {\r\n const stack = extractAnimStack(id, node, objectMap);\r\n if (stack) {\r\n stacks.push(stack);\r\n }\r\n }\r\n }\r\n\r\n return stacks;\r\n}\r\n\r\nfunction extractAnimStack(stackId: number, stackNode: FBXNode, objectMap: FBXObjectMap): FBXAnimationStackData | null {\r\n const name = cleanFBXName(getPropertyValue<string>(stackNode, 1) ?? \"Animation\");\r\n const declaredTimeSpan = extractAnimationStackTimeSpan(stackNode);\r\n\r\n // Find AnimationLayer children of this stack\r\n const layerEntries = getChildren(objectMap, stackId, \"AnimationLayer\");\r\n if (layerEntries.length === 0) {\r\n return null;\r\n }\r\n\r\n // Collect all CurveNodes from all layers\r\n const allCurveNodes: FBXCurveNodeData[] = [];\r\n const allUnsupportedCurveNodes: FBXUnsupportedCurveNodeData[] = [];\r\n const layers: FBXAnimationLayerData[] = [];\r\n const diagnostics: FBXAnimationDiagnostic[] = [];\r\n let minTime = Infinity;\r\n let maxTime = 0;\r\n\r\n for (const { id: layerId, node: layerNode } of layerEntries) {\r\n // Extract layer properties\r\n const layerName = cleanFBXName(getPropertyValue<string>(layerNode, 1) ?? \"Layer\");\r\n let weight = 100;\r\n let blendMode = 0;\r\n\r\n const props70 = findChildByName(layerNode, \"Properties70\");\r\n if (props70) {\r\n for (const p of props70.children) {\r\n if (p.name !== \"P\") {\r\n continue;\r\n }\r\n const pName = getPropertyValue<string>(p, 0);\r\n if (pName === \"Weight\") {\r\n const v = p.properties[4]?.value;\r\n if (typeof v === \"number\") {\r\n weight = v;\r\n }\r\n } else if (pName === \"BlendMode\") {\r\n const v = p.properties[4]?.value;\r\n if (typeof v === \"number\") {\r\n blendMode = v;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // AnimationCurveNodes are children of the layer\r\n const curveNodeEntries = getChildren(objectMap, layerId, \"AnimationCurveNode\");\r\n const layerCurveNodes: FBXCurveNodeData[] = [];\r\n const layerUnsupportedCurveNodes: FBXUnsupportedCurveNodeData[] = [];\r\n const layerDiagnostics: FBXAnimationDiagnostic[] = [];\r\n\r\n for (const { id: curveNodeId, node: curveNodeNode } of curveNodeEntries) {\r\n const curveNodeData = extractCurveNode(curveNodeId, curveNodeNode, objectMap);\r\n if (!curveNodeData) {\r\n const unsupported = extractUnsupportedCurveNode(curveNodeId, curveNodeNode, objectMap);\r\n if (unsupported) {\r\n scanCurveTimes(unsupported.curves, (time) => {\r\n if (time < minTime) {\r\n minTime = time;\r\n }\r\n if (time > maxTime) {\r\n maxTime = time;\r\n }\r\n });\r\n layerUnsupportedCurveNodes.push(unsupported);\r\n allUnsupportedCurveNodes.push(unsupported);\r\n const diagnostic: FBXAnimationDiagnostic = {\r\n type: \"unsupported-curve-node\",\r\n message: `AnimationCurveNode '${unsupported.type}' is preserved as diagnostic data but not evaluated at runtime.`,\r\n layerName,\r\n curveNodeId,\r\n curveNodeType: unsupported.type,\r\n targetId: unsupported.targetId,\r\n propertyName: unsupported.propertyName,\r\n };\r\n layerDiagnostics.push(diagnostic);\r\n diagnostics.push(diagnostic);\r\n }\r\n continue;\r\n }\r\n\r\n for (const curve of curveNodeData.curves) {\r\n for (const key of curve.keys) {\r\n if (key.time < minTime) {\r\n minTime = key.time;\r\n }\r\n if (key.time > maxTime) {\r\n maxTime = key.time;\r\n }\r\n }\r\n }\r\n\r\n layerCurveNodes.push(curveNodeData);\r\n allCurveNodes.push(curveNodeData);\r\n }\r\n\r\n layers.push({\r\n name: layerName,\r\n weight,\r\n normalizedWeight: weight / 100,\r\n blendMode,\r\n curveNodes: layerCurveNodes,\r\n unsupportedCurveNodes: layerUnsupportedCurveNodes,\r\n diagnostics: layerDiagnostics,\r\n });\r\n }\r\n\r\n if (allCurveNodes.length === 0 && allUnsupportedCurveNodes.length === 0) {\r\n return null;\r\n }\r\n\r\n if (layers.length > 1) {\r\n diagnostics.push({\r\n type: \"multiple-animation-layers\",\r\n message: \"Multiple animation layers are preserved, but runtime blending is not yet evaluated.\",\r\n });\r\n }\r\n for (const layer of layers) {\r\n if (layer.blendMode !== 0) {\r\n const diagnostic: FBXAnimationDiagnostic = {\r\n type: \"unsupported-layer-blend-mode\",\r\n message: `Animation layer blend mode ${layer.blendMode} is preserved but not yet blended at runtime.`,\r\n layerName: layer.name,\r\n };\r\n layer.diagnostics.push(diagnostic);\r\n diagnostics.push(diagnostic);\r\n }\r\n if (layer.weight !== 100) {\r\n const diagnostic: FBXAnimationDiagnostic = {\r\n type: \"partial-layer-weight\",\r\n message: `Animation layer weight ${layer.weight} is preserved but not yet applied at runtime.`,\r\n layerName: layer.name,\r\n };\r\n layer.diagnostics.push(diagnostic);\r\n diagnostics.push(diagnostic);\r\n }\r\n }\r\n\r\n const timeOffset = minTime > 0 && isFinite(minTime) ? minTime : 0;\r\n\r\n // Rebase all keyframe times so the animation starts at 0\r\n if (timeOffset > 0) {\r\n for (const cn of allCurveNodes) {\r\n for (const curve of cn.curves) {\r\n for (const key of curve.keys) {\r\n key.time -= timeOffset;\r\n }\r\n }\r\n }\r\n for (const cn of allUnsupportedCurveNodes) {\r\n for (const curve of cn.curves) {\r\n for (const key of curve.keys) {\r\n key.time -= timeOffset;\r\n }\r\n }\r\n }\r\n maxTime -= timeOffset;\r\n }\r\n\r\n const declaredStart = declaredTimeSpan ? Math.max(declaredTimeSpan.start - timeOffset, 0) : 0;\r\n const declaredStop = declaredTimeSpan ? Math.max(declaredTimeSpan.stop - timeOffset, declaredStart) : 0;\r\n const hasDeclaredDuration = declaredStop > declaredStart;\r\n const startTime = hasDeclaredDuration ? declaredStart : 0;\r\n const stopTime = hasDeclaredDuration ? declaredStop : maxTime;\r\n\r\n return {\r\n name,\r\n startTime,\r\n stopTime,\r\n duration: Math.max(stopTime - startTime, 0),\r\n curveNodes: allCurveNodes,\r\n layers,\r\n unsupportedCurveNodes: allUnsupportedCurveNodes,\r\n diagnostics,\r\n };\r\n}\r\n\r\nfunction extractAnimationStackTimeSpan(stackNode: FBXNode): { start: number; stop: number } | null {\r\n const props70 = findChildByName(stackNode, \"Properties70\");\r\n if (!props70) {\r\n return null;\r\n }\r\n\r\n let start = 0;\r\n let stop: number | null = null;\r\n\r\n for (const p of props70.children) {\r\n if (p.name !== \"P\") {\r\n continue;\r\n }\r\n const pName = getPropertyValue<string>(p, 0);\r\n if (pName === \"LocalStart\" || pName === \"ReferenceStart\") {\r\n start = fbxTimeToSeconds(p.properties[4]?.value) ?? start;\r\n } else if (pName === \"LocalStop\" || pName === \"ReferenceStop\") {\r\n stop = fbxTimeToSeconds(p.properties[4]?.value) ?? stop;\r\n }\r\n }\r\n\r\n return stop !== null ? { start, stop } : null;\r\n}\r\n\r\nfunction extractCurveNode(curveNodeId: number, curveNodeNode: FBXNode, objectMap: FBXObjectMap): FBXCurveNodeData | null {\r\n const typeName = cleanFBXName(getPropertyValue<string>(curveNodeNode, 1) ?? \"\");\r\n\r\n // Handle T (translation), R (rotation), S (scale) targeting Models\r\n if (typeName === \"T\" || typeName === \"R\" || typeName === \"S\") {\r\n const targetModelId = findCurveNodeTarget(curveNodeId, objectMap);\r\n if (targetModelId === null) {\r\n return null;\r\n }\r\n\r\n const curves = extractCurves(curveNodeId, objectMap);\r\n if (curves.length === 0) {\r\n return null;\r\n }\r\n\r\n return {\r\n type: typeName,\r\n targetModelId,\r\n curves,\r\n };\r\n }\r\n\r\n // Handle DeformPercent targeting BlendShapeChannels\r\n if (typeName === \"DeformPercent\") {\r\n const targetId = findCurveNodeBlendShapeTarget(curveNodeId, objectMap);\r\n if (targetId === null) {\r\n return null;\r\n }\r\n\r\n const curves = extractCurves(curveNodeId, objectMap);\r\n if (curves.length === 0) {\r\n return null;\r\n }\r\n\r\n return {\r\n type: \"DeformPercent\",\r\n targetModelId: targetId,\r\n curves,\r\n };\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction extractUnsupportedCurveNode(curveNodeId: number, curveNodeNode: FBXNode, objectMap: FBXObjectMap): FBXUnsupportedCurveNodeData | null {\r\n const typeName = cleanFBXName(getPropertyValue<string>(curveNodeNode, 1) ?? \"\");\r\n const curves = extractCurves(curveNodeId, objectMap);\r\n const defaultValues = extractCurveNodeDefaultValues(curveNodeNode);\r\n if (curves.length === 0 && Object.keys(defaultValues).length === 0) {\r\n return null;\r\n }\r\n\r\n let targetId: number | null = null;\r\n let propertyName: string | undefined;\r\n for (const conn of objectMap.connections) {\r\n if (conn.childId === curveNodeId && conn.type === \"OP\") {\r\n targetId = conn.parentId;\r\n propertyName = conn.propertyName;\r\n break;\r\n }\r\n }\r\n\r\n return {\r\n type: typeName,\r\n id: curveNodeId,\r\n targetId,\r\n propertyName,\r\n curveCount: curves.length,\r\n curves,\r\n defaultValues,\r\n };\r\n}\r\n\r\nfunction scanCurveTimes(curves: FBXCurveData[], visit: (time: number) => void): void {\r\n for (const curve of curves) {\r\n for (const key of curve.keys) {\r\n visit(key.time);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Find the Model that an AnimationCurveNode targets.\r\n * The CurveNode connects to the Model via OP connection with a property name.\r\n */\r\nfunction findCurveNodeTarget(curveNodeId: number, objectMap: FBXObjectMap): number | null {\r\n // Look for connections where this curveNode is a child (going up to parent)\r\n // The OP connection from curveNode → Model has the property name (e.g. \"Lcl Translation\")\r\n for (const conn of objectMap.connections) {\r\n if (conn.childId === curveNodeId && conn.type === \"OP\") {\r\n const parentNode = objectMap.objects.get(conn.parentId);\r\n if (parentNode && parentNode.name === \"Model\") {\r\n return conn.parentId;\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Find the BlendShapeChannel that a DeformPercent AnimationCurveNode targets.\r\n */\r\nfunction findCurveNodeBlendShapeTarget(curveNodeId: number, objectMap: FBXObjectMap): number | null {\r\n for (const conn of objectMap.connections) {\r\n if (conn.childId === curveNodeId && conn.type === \"OP\") {\r\n const parentNode = objectMap.objects.get(conn.parentId);\r\n if (parentNode && parentNode.name === \"Deformer\") {\r\n const subType = getPropertyValue<string>(parentNode, 2);\r\n if (subType === \"BlendShapeChannel\") {\r\n return conn.parentId;\r\n }\r\n }\r\n }\r\n }\r\n // Also check OO connections\r\n for (const conn of objectMap.connections) {\r\n if (conn.childId === curveNodeId && conn.type === \"OO\") {\r\n const parentNode = objectMap.objects.get(conn.parentId);\r\n if (parentNode && parentNode.name === \"Deformer\") {\r\n const subType = getPropertyValue<string>(parentNode, 2);\r\n if (subType === \"BlendShapeChannel\") {\r\n return conn.parentId;\r\n }\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Extract AnimationCurves connected to a CurveNode.\r\n * Each curve connects via OP with channel \"d|X\", \"d|Y\", or \"d|Z\".\r\n */\r\nfunction extractCurves(curveNodeId: number, objectMap: FBXObjectMap): FBXCurveData[] {\r\n const curves: FBXCurveData[] = [];\r\n\r\n // Find AnimationCurve children of this CurveNode\r\n for (const conn of objectMap.connections) {\r\n if (conn.parentId === curveNodeId && conn.type === \"OP\") {\r\n const curveNode = objectMap.objects.get(conn.childId);\r\n if (!curveNode || curveNode.name !== \"AnimationCurve\") {\r\n continue;\r\n }\r\n\r\n const channel = conn.propertyName ?? \"d|X\";\r\n const keys = extractKeyframes(curveNode);\r\n if (keys.length > 0) {\r\n const isSampled = isSampledAnimationCurve(curveNode, keys);\r\n curves.push({ channel, keys: isSampled ? makeLinearSampleKeys(keys) : keys, isSampled });\r\n }\r\n }\r\n }\r\n\r\n // Also check OO connections (some exporters use OO for curve→curveNode)\r\n if (curves.length === 0) {\r\n const ooChildren = getChildren(objectMap, curveNodeId, \"AnimationCurve\");\r\n // For OO connections, infer channel from order (X, Y, Z)\r\n const channelNames = [\"d|X\", \"d|Y\", \"d|Z\"];\r\n for (let i = 0; i < ooChildren.length && i < 3; i++) {\r\n const keys = extractKeyframes(ooChildren[i].node);\r\n if (keys.length > 0) {\r\n const isSampled = isSampledAnimationCurve(ooChildren[i].node, keys);\r\n curves.push({ channel: channelNames[i], keys: isSampled ? makeLinearSampleKeys(keys) : keys, isSampled });\r\n }\r\n }\r\n }\r\n\r\n return curves;\r\n}\r\n\r\nfunction extractCurveNodeDefaultValues(curveNodeNode: FBXNode): Record<string, number> {\r\n const defaults: Record<string, number> = {};\r\n const props70 = findChildByName(curveNodeNode, \"Properties70\");\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?.startsWith(\"d|\")) {\r\n continue;\r\n }\r\n const value = toNumber(p.properties[4]?.value);\r\n if (value !== null) {\r\n defaults[propName] = value;\r\n }\r\n }\r\n return defaults;\r\n}\r\n\r\n/**\r\n * Extract keyframes from an AnimationCurve node.\r\n */\r\nfunction extractKeyframes(curveNode: FBXNode): FBXKeyframe[] {\r\n const keyTimeNode = findChildByName(curveNode, \"KeyTime\");\r\n const keyValueNode = findChildByName(curveNode, \"KeyValueFloat\");\r\n\r\n if (!keyTimeNode || !keyValueNode) {\r\n return [];\r\n }\r\n\r\n const keyTimes = toInt64Array(keyTimeNode.properties[0]?.value);\r\n const keyValues = toFloat32Array(keyValueNode.properties[0]?.value);\r\n const keyAttrFlags = toInt32Array(findChildByName(curveNode, \"KeyAttrFlags\")?.properties[0]?.value);\r\n const keyAttrData = toFloat32Array(findChildByName(curveNode, \"KeyAttrDataFloat\")?.properties[0]?.value);\r\n const keyAttrRefCount = toInt32Array(findChildByName(curveNode, \"KeyAttrRefCount\")?.properties[0]?.value);\r\n\r\n if (!keyTimes || !keyValues) {\r\n return [];\r\n }\r\n if (keyTimes.length !== keyValues.length) {\r\n return [];\r\n }\r\n\r\n const keyAttributeIndices = buildKeyAttributeIndices(keyTimes.length, keyAttrFlags, keyAttrRefCount);\r\n\r\n const keys: FBXKeyframe[] = [];\r\n for (let i = 0; i < keyTimes.length; i++) {\r\n const attrIndex = keyAttributeIndices[i];\r\n const flag = attrIndex >= 0 ? (keyAttrFlags?.[attrIndex] ?? 0) : 0;\r\n const dataOffset = attrIndex * KEY_ATTR_DATA_STRIDE;\r\n\r\n keys.push({\r\n time: Number(keyTimes[i]) / FBX_TIME_UNIT,\r\n value: keyValues[i],\r\n interpolation: getInterpolationType(flag),\r\n constantMode: (flag & 0x00000100) !== 0 ? \"next\" : \"standard\",\r\n rightSlope: getFiniteKeyAttrData(keyAttrData, dataOffset),\r\n nextLeftSlope: getFiniteKeyAttrData(keyAttrData, dataOffset + 1),\r\n });\r\n }\r\n\r\n return keys;\r\n}\r\n\r\nfunction isSampledAnimationCurve(curveNode: FBXNode, keys: readonly FBXKeyframe[]): boolean {\r\n const rawName = getPropertyValue<string>(curveNode, 1) ?? \"\";\r\n return cleanFBXName(rawName) === \"FbxMayaSample Curve\" || isFrameBakedSampledCurve(keys);\r\n}\r\n\r\n/**\r\n * Determines whether a key sequence appears to be a uniformly frame-baked sampled curve.\r\n * @param keys - Keyframes to inspect\r\n * @returns true if the keys look like sampled frame data rather than authored interpolation\r\n */\r\nexport function isFrameBakedSampledCurve(keys: readonly FBXKeyframe[]): boolean {\r\n if (keys.length < SAMPLED_CURVE_MIN_KEY_COUNT) {\r\n return false;\r\n }\r\n\r\n const deltas: number[] = [];\r\n for (let i = 1; i < keys.length; i++) {\r\n const delta = keys[i].time - keys[i - 1].time;\r\n if (!(delta > 0)) {\r\n return false;\r\n }\r\n deltas.push(delta);\r\n }\r\n\r\n const averageDelta = deltas.reduce((sum, delta) => sum + delta, 0) / deltas.length;\r\n if (averageDelta > SAMPLED_CURVE_MAX_INTERVAL_SECONDS) {\r\n return false;\r\n }\r\n\r\n const uniformTolerance = Math.max(1e-6, averageDelta * SAMPLED_CURVE_UNIFORM_TOLERANCE_RATIO);\r\n if (deltas.some((delta) => Math.abs(delta - averageDelta) > uniformTolerance)) {\r\n return false;\r\n }\r\n\r\n const sampledFps = 1 / averageDelta;\r\n const matchesCommonFps = SAMPLED_CURVE_COMMON_FPS.some((fps) => Math.abs(sampledFps - fps) <= Math.max(0.25, fps * 0.02));\r\n if (!matchesCommonFps) {\r\n return false;\r\n }\r\n\r\n return !hasMeaningfulCubicTangents(keys);\r\n}\r\n\r\nfunction makeLinearSampleKeys(keys: FBXKeyframe[]): FBXKeyframe[] {\r\n return keys.map((key) => ({\r\n time: key.time,\r\n value: key.value,\r\n interpolation: \"linear\",\r\n }));\r\n}\r\n\r\nfunction hasMeaningfulCubicTangents(keys: readonly FBXKeyframe[]): boolean {\r\n let hasCubicSegment = false;\r\n let hasCompleteTangents = true;\r\n let allSlopesDegenerate = true;\r\n let minValue = Number.POSITIVE_INFINITY;\r\n let maxValue = Number.NEGATIVE_INFINITY;\r\n let maxLinearDeviation = 0;\r\n\r\n for (const key of keys) {\r\n minValue = Math.min(minValue, key.value);\r\n maxValue = Math.max(maxValue, key.value);\r\n }\r\n\r\n for (let i = 0; i < keys.length - 1; i++) {\r\n const key = keys[i];\r\n const nextKey = keys[i + 1];\r\n if (key.interpolation !== \"cubic\") {\r\n continue;\r\n }\r\n\r\n hasCubicSegment = true;\r\n const segmentDuration = nextKey.time - key.time;\r\n if (!(segmentDuration > 0)) {\r\n continue;\r\n }\r\n\r\n const linearSlope = (nextKey.value - key.value) / segmentDuration;\r\n const rightSlope = key.rightSlope;\r\n const nextLeftSlope = key.nextLeftSlope;\r\n if (rightSlope === undefined || nextLeftSlope === undefined) {\r\n hasCompleteTangents = false;\r\n continue;\r\n }\r\n\r\n if (Math.abs(rightSlope) > SAMPLED_CURVE_DEGENERATE_SLOPE_ABSOLUTE || Math.abs(nextLeftSlope) > SAMPLED_CURVE_DEGENERATE_SLOPE_ABSOLUTE) {\r\n allSlopesDegenerate = false;\r\n }\r\n\r\n for (const t of [0.25, 0.5, 0.75]) {\r\n const cubic = cubicHermite(key.value, nextKey.value, rightSlope, nextLeftSlope, segmentDuration, t);\r\n const linear = key.value + t * segmentDuration * linearSlope;\r\n maxLinearDeviation = Math.max(maxLinearDeviation, Math.abs(cubic - linear));\r\n }\r\n }\r\n\r\n if (!hasCubicSegment || !hasCompleteTangents || allSlopesDegenerate) {\r\n return false;\r\n }\r\n\r\n const range = maxValue - minValue;\r\n const deviationTolerance = Math.max(SAMPLED_CURVE_LINEAR_DEVIATION_ABSOLUTE, range * SAMPLED_CURVE_LINEAR_DEVIATION_RATIO);\r\n return maxLinearDeviation > deviationTolerance;\r\n}\r\n\r\n/**\r\n * Samples an FBX animation curve at a specific time.\r\n * @param curveData - Curve data to sample\r\n * @param time - Time in seconds\r\n * @returns The sampled value, or null when the curve has no keys\r\n */\r\nexport function sampleFBXCurveAtTime(curveData: FBXCurveData | undefined, time: number): number | null {\r\n if (!curveData || curveData.keys.length === 0) {\r\n return null;\r\n }\r\n\r\n const keys = curveData.keys;\r\n\r\n if (time <= keys[0].time) {\r\n return keys[0].value;\r\n }\r\n if (time >= keys[keys.length - 1].time) {\r\n return keys[keys.length - 1].value;\r\n }\r\n\r\n for (let i = 0; i < keys.length - 1; i++) {\r\n const key = keys[i];\r\n const nextKey = keys[i + 1];\r\n if (time < key.time || time > nextKey.time) {\r\n continue;\r\n }\r\n\r\n if (nextKey.time === key.time) {\r\n return key.value;\r\n }\r\n if (key.interpolation === \"constant\") {\r\n return key.constantMode === \"next\" ? nextKey.value : key.value;\r\n }\r\n\r\n const segmentDuration = nextKey.time - key.time;\r\n const t = (time - key.time) / segmentDuration;\r\n\r\n if (key.interpolation === \"cubic\" && !curveData.isSampled) {\r\n const linearSlope = (nextKey.value - key.value) / segmentDuration;\r\n const rightSlope = key.rightSlope ?? linearSlope;\r\n const nextLeftSlope = key.nextLeftSlope ?? linearSlope;\r\n return cubicHermite(key.value, nextKey.value, rightSlope, nextLeftSlope, segmentDuration, t);\r\n }\r\n\r\n return key.value + t * (nextKey.value - key.value);\r\n }\r\n\r\n return keys[keys.length - 1].value;\r\n}\r\n\r\n// ── Utilities ──────────────────────────────────────────────────────────────────\r\n\r\nfunction toInt64Array(value: unknown): Float64Array | null {\r\n if (value instanceof Float64Array) {\r\n return value;\r\n }\r\n return null;\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 Float32Array || 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] = value[i];\r\n }\r\n return result;\r\n }\r\n return null;\r\n}\r\n\r\nfunction fbxTimeToSeconds(value: unknown): number | null {\r\n if (typeof value === \"number\") {\r\n return value / FBX_TIME_UNIT;\r\n }\r\n return null;\r\n}\r\n\r\nfunction toNumber(value: unknown): number | null {\r\n if (typeof value === \"number\") {\r\n return value;\r\n }\r\n return null;\r\n}\r\n\r\nfunction toFloat32Array(value: unknown): Float32Array | null {\r\n if (value instanceof Float32Array) {\r\n return value;\r\n }\r\n if (value instanceof Float64Array) {\r\n const result = new Float32Array(value.length);\r\n for (let i = 0; i < value.length; i++) {\r\n result[i] = value[i];\r\n }\r\n return result;\r\n }\r\n return null;\r\n}\r\n\r\nfunction buildKeyAttributeIndices(keyCount: number, keyAttrFlags: Int32Array | null, keyAttrRefCount: Int32Array | null): number[] {\r\n if (!keyAttrFlags || keyAttrFlags.length === 0) {\r\n return new Array(keyCount).fill(-1);\r\n }\r\n\r\n if (keyAttrRefCount && keyAttrRefCount.length > 0) {\r\n let total = 0;\r\n for (const count of keyAttrRefCount) {\r\n total += count;\r\n }\r\n\r\n if (total === keyCount) {\r\n const indices: number[] = [];\r\n for (let attrIndex = 0; attrIndex < keyAttrRefCount.length; attrIndex++) {\r\n const count = keyAttrRefCount[attrIndex];\r\n for (let i = 0; i < count; i++) {\r\n indices.push(attrIndex);\r\n }\r\n }\r\n return indices;\r\n }\r\n }\r\n\r\n if (keyAttrFlags.length === keyCount) {\r\n return Array.from({ length: keyCount }, (_, i) => i);\r\n }\r\n\r\n if (keyAttrFlags.length === 1) {\r\n return new Array(keyCount).fill(0);\r\n }\r\n\r\n return Array.from({ length: keyCount }, (_, i) => Math.min(i, keyAttrFlags.length - 1));\r\n}\r\n\r\nfunction getInterpolationType(flag: number): FBXInterpolationType {\r\n if ((flag & 0x00000008) !== 0) {\r\n return \"cubic\";\r\n }\r\n if ((flag & 0x00000004) !== 0) {\r\n return \"linear\";\r\n }\r\n if ((flag & 0x00000002) !== 0) {\r\n return \"constant\";\r\n }\r\n return \"linear\";\r\n}\r\n\r\nfunction getFiniteKeyAttrData(keyAttrData: Float32Array | null, index: number): number | undefined {\r\n if (!keyAttrData || index < 0 || index >= keyAttrData.length) {\r\n return undefined;\r\n }\r\n const value = keyAttrData[index];\r\n return Number.isFinite(value) ? value : undefined;\r\n}\r\n\r\nfunction cubicHermite(value0: number, value1: number, slope0: number, slope1: number, segmentDuration: number, t: number): number {\r\n const t2 = t * t;\r\n const t3 = t2 * t;\r\n const h00 = 2 * t3 - 3 * t2 + 1;\r\n const h10 = t3 - 2 * t2 + t;\r\n const h01 = -2 * t3 + 3 * t2;\r\n const h11 = t3 - t2;\r\n\r\n return h00 * value0 + h10 * segmentDuration * slope0 + h01 * value1 + h11 * segmentDuration * slope1;\r\n}\r\n"]}
@@ -0,0 +1,44 @@
1
+ import { type FBXObjectMap } from "./connections.js";
2
+ /** A single morph target (shape) within a blend shape channel */
3
+ export interface FBXShapeData {
4
+ /** Sparse vertex indices affected by this shape */
5
+ indices: Uint32Array;
6
+ /** Absolute vertex positions for affected vertices [x,y,z,...] */
7
+ vertices: Float64Array;
8
+ /** Normals for affected vertices [x,y,z,...] (optional) */
9
+ normals: Float64Array | null;
10
+ }
11
+ export interface FBXBlendShapeDiagnostic {
12
+ type: "full-weights-mismatch" | "missing-full-weights";
13
+ message: string;
14
+ channelId: number;
15
+ channelName: string;
16
+ }
17
+ /** A blend shape channel (one animatable morph target) */
18
+ export interface FBXBlendShapeChannelData {
19
+ /** Channel name */
20
+ name: string;
21
+ /** Channel node ID */
22
+ id: number;
23
+ /** Default weight (0-100 in FBX) */
24
+ deformPercent: number;
25
+ /** Shape geometry (typically one per channel, but FBX supports in-between shapes) */
26
+ shapes: FBXShapeData[];
27
+ /** In-between full weights in FBX DeformPercent units (0-100), one per shape when present */
28
+ fullWeights: number[] | null;
29
+ /** Recoverable blend-shape diagnostics */
30
+ diagnostics: FBXBlendShapeDiagnostic[];
31
+ }
32
+ /** A blend shape deformer attached to a geometry */
33
+ export interface FBXBlendShapeData {
34
+ /** Deformer ID */
35
+ id: number;
36
+ /** Geometry ID this blend shape is attached to */
37
+ geometryId: number;
38
+ /** Channels (each is an animatable morph target) */
39
+ channels: FBXBlendShapeChannelData[];
40
+ }
41
+ /**
42
+ * Extract all blend shape deformers from the FBX scene.
43
+ */
44
+ export declare function extractBlendShapes(objectMap: FBXObjectMap): FBXBlendShapeData[];
@@ -0,0 +1,192 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */
2
+ import { findChildByName, getPropertyValue, cleanFBXName } from "../types/fbxTypes.js";
3
+ import { getChildren } from "./connections.js";
4
+ /**
5
+ * Extract all blend shape deformers from the FBX scene.
6
+ */
7
+ export function extractBlendShapes(objectMap) {
8
+ const blendShapes = [];
9
+ for (const [id, node] of Array.from(objectMap.objects)) {
10
+ if (node.name === "Deformer" && getPropertyValue(node, 2) === "BlendShape") {
11
+ const bs = extractBlendShape(id, node, objectMap);
12
+ if (bs) {
13
+ blendShapes.push(bs);
14
+ }
15
+ }
16
+ }
17
+ return blendShapes;
18
+ }
19
+ function extractBlendShape(deformerId, _deformerNode, objectMap) {
20
+ // Find the geometry this blend shape is attached to
21
+ const parent = objectMap.parentOf.get(deformerId);
22
+ if (!parent) {
23
+ return null;
24
+ }
25
+ const parentNode = objectMap.objects.get(parent.id);
26
+ if (!parentNode || parentNode.name !== "Geometry") {
27
+ return null;
28
+ }
29
+ const geometryId = parent.id;
30
+ // Find BlendShapeChannel children
31
+ const channels = [];
32
+ const channelChildren = getChildren(objectMap, deformerId, "Deformer");
33
+ for (const { id: channelId, node: channelNode } of channelChildren) {
34
+ const subType = getPropertyValue(channelNode, 2);
35
+ if (subType !== "BlendShapeChannel") {
36
+ continue;
37
+ }
38
+ const channelName = cleanFBXName(getPropertyValue(channelNode, 1) ?? "MorphTarget");
39
+ // Read DeformPercent from Properties70
40
+ let deformPercent = 0;
41
+ const props70 = findChildByName(channelNode, "Properties70");
42
+ if (props70) {
43
+ for (const p of props70.children) {
44
+ if (p.name !== "P") {
45
+ continue;
46
+ }
47
+ const pName = getPropertyValue(p, 0);
48
+ if (pName === "DeformPercent") {
49
+ const val = p.properties[4]?.value;
50
+ if (typeof val === "number") {
51
+ deformPercent = val;
52
+ }
53
+ }
54
+ }
55
+ }
56
+ const rawFullWeights = extractFullWeights(channelNode);
57
+ // Find connected Shape geometries
58
+ const shapes = [];
59
+ const shapeChildren = getChildren(objectMap, channelId, "Geometry");
60
+ for (const { node: shapeNode } of shapeChildren) {
61
+ const shapeSubType = getPropertyValue(shapeNode, 2);
62
+ if (shapeSubType !== "Shape") {
63
+ continue;
64
+ }
65
+ const shape = extractShape(shapeNode);
66
+ if (shape) {
67
+ shapes.push(shape);
68
+ }
69
+ }
70
+ if (shapes.length > 0) {
71
+ const diagnostics = [];
72
+ const fullWeights = normalizeFullWeights(rawFullWeights, shapes, channelId, channelName, diagnostics);
73
+ channels.push({
74
+ name: channelName,
75
+ id: channelId,
76
+ deformPercent,
77
+ shapes: sortShapesByFullWeight(shapes, fullWeights),
78
+ fullWeights: fullWeights ? [...fullWeights].sort((a, b) => a - b) : null,
79
+ diagnostics,
80
+ });
81
+ }
82
+ }
83
+ if (channels.length === 0) {
84
+ return null;
85
+ }
86
+ return {
87
+ id: deformerId,
88
+ geometryId,
89
+ channels,
90
+ };
91
+ }
92
+ function extractFullWeights(channelNode) {
93
+ const fullWeightsNode = findChildByName(channelNode, "FullWeights");
94
+ const rawFullWeights = fullWeightsNode?.properties[0]?.value;
95
+ if (!rawFullWeights) {
96
+ return null;
97
+ }
98
+ if (rawFullWeights instanceof Float64Array || rawFullWeights instanceof Float32Array || rawFullWeights instanceof Int32Array) {
99
+ return Array.from(rawFullWeights, (value) => Number(value));
100
+ }
101
+ return null;
102
+ }
103
+ function normalizeFullWeights(fullWeights, shapes, channelId, channelName, diagnostics) {
104
+ if (!fullWeights) {
105
+ if (shapes.length > 1) {
106
+ diagnostics.push({
107
+ type: "missing-full-weights",
108
+ message: "Blend shape channel has multiple shapes but no FullWeights; using the first shape for compatibility.",
109
+ channelId,
110
+ channelName,
111
+ });
112
+ }
113
+ return null;
114
+ }
115
+ if (fullWeights.length !== shapes.length) {
116
+ if (shapes.length === 1) {
117
+ return null;
118
+ }
119
+ diagnostics.push({
120
+ type: "full-weights-mismatch",
121
+ message: `FullWeights length ${fullWeights.length} does not match shape count ${shapes.length}; using the first shape for compatibility.`,
122
+ channelId,
123
+ channelName,
124
+ });
125
+ return null;
126
+ }
127
+ return fullWeights;
128
+ }
129
+ function sortShapesByFullWeight(shapes, fullWeights) {
130
+ if (!fullWeights || fullWeights.length !== shapes.length) {
131
+ return shapes.length > 1 ? [shapes[0]] : shapes;
132
+ }
133
+ return shapes
134
+ .map((shape, index) => ({ shape, weight: fullWeights[index] }))
135
+ .sort((a, b) => a.weight - b.weight)
136
+ .map((entry) => entry.shape);
137
+ }
138
+ function extractShape(shapeNode) {
139
+ // Shape has: Indexes (sparse vertex indices), Vertices (delta offsets from base), Normals (optional delta)
140
+ const indexesNode = findChildByName(shapeNode, "Indexes");
141
+ const verticesNode = findChildByName(shapeNode, "Vertices");
142
+ if (!indexesNode || !verticesNode) {
143
+ return null;
144
+ }
145
+ const rawIndices = indexesNode.properties[0]?.value;
146
+ const rawVertices = verticesNode.properties[0]?.value;
147
+ if (!rawIndices || !rawVertices) {
148
+ return null;
149
+ }
150
+ const indices = toUint32Array(rawIndices);
151
+ if (!indices) {
152
+ return null;
153
+ }
154
+ // Convert vertices
155
+ let vertices;
156
+ if (rawVertices instanceof Float64Array) {
157
+ vertices = rawVertices;
158
+ }
159
+ else if (rawVertices instanceof Float32Array) {
160
+ vertices = new Float64Array(rawVertices);
161
+ }
162
+ else {
163
+ return null;
164
+ }
165
+ // Optional normals
166
+ let normals = null;
167
+ const normalsNode = findChildByName(shapeNode, "Normals");
168
+ if (normalsNode) {
169
+ const rawNormals = normalsNode.properties[0]?.value;
170
+ if (rawNormals instanceof Float64Array) {
171
+ normals = rawNormals;
172
+ }
173
+ else if (rawNormals instanceof Float32Array) {
174
+ normals = new Float64Array(rawNormals);
175
+ }
176
+ }
177
+ return { indices, vertices, normals };
178
+ }
179
+ function toUint32Array(value) {
180
+ if (value instanceof Uint32Array) {
181
+ return value;
182
+ }
183
+ if (value instanceof Int32Array || value instanceof Float32Array || value instanceof Float64Array) {
184
+ const result = new Uint32Array(value.length);
185
+ for (let i = 0; i < value.length; i++) {
186
+ result[i] = value[i];
187
+ }
188
+ return result;
189
+ }
190
+ return null;
191
+ }
192
+ //# sourceMappingURL=blendShapes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blendShapes.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/FBX/interpreter/blendShapes.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\n/** A single morph target (shape) within a blend shape channel */\r\nexport interface FBXShapeData {\r\n /** Sparse vertex indices affected by this shape */\r\n indices: Uint32Array;\r\n /** Absolute vertex positions for affected vertices [x,y,z,...] */\r\n vertices: Float64Array;\r\n /** Normals for affected vertices [x,y,z,...] (optional) */\r\n normals: Float64Array | null;\r\n}\r\n\r\nexport interface FBXBlendShapeDiagnostic {\r\n type: \"full-weights-mismatch\" | \"missing-full-weights\";\r\n message: string;\r\n channelId: number;\r\n channelName: string;\r\n}\r\n\r\n/** A blend shape channel (one animatable morph target) */\r\nexport interface FBXBlendShapeChannelData {\r\n /** Channel name */\r\n name: string;\r\n /** Channel node ID */\r\n id: number;\r\n /** Default weight (0-100 in FBX) */\r\n deformPercent: number;\r\n /** Shape geometry (typically one per channel, but FBX supports in-between shapes) */\r\n shapes: FBXShapeData[];\r\n /** In-between full weights in FBX DeformPercent units (0-100), one per shape when present */\r\n fullWeights: number[] | null;\r\n /** Recoverable blend-shape diagnostics */\r\n diagnostics: FBXBlendShapeDiagnostic[];\r\n}\r\n\r\n/** A blend shape deformer attached to a geometry */\r\nexport interface FBXBlendShapeData {\r\n /** Deformer ID */\r\n id: number;\r\n /** Geometry ID this blend shape is attached to */\r\n geometryId: number;\r\n /** Channels (each is an animatable morph target) */\r\n channels: FBXBlendShapeChannelData[];\r\n}\r\n\r\n/**\r\n * Extract all blend shape deformers from the FBX scene.\r\n */\r\nexport function extractBlendShapes(objectMap: FBXObjectMap): FBXBlendShapeData[] {\r\n const blendShapes: FBXBlendShapeData[] = [];\r\n\r\n for (const [id, node] of Array.from(objectMap.objects)) {\r\n if (node.name === \"Deformer\" && getPropertyValue<string>(node, 2) === \"BlendShape\") {\r\n const bs = extractBlendShape(id, node, objectMap);\r\n if (bs) {\r\n blendShapes.push(bs);\r\n }\r\n }\r\n }\r\n\r\n return blendShapes;\r\n}\r\n\r\nfunction extractBlendShape(deformerId: number, _deformerNode: FBXNode, objectMap: FBXObjectMap): FBXBlendShapeData | null {\r\n // Find the geometry this blend shape is attached to\r\n const parent = objectMap.parentOf.get(deformerId);\r\n if (!parent) {\r\n return null;\r\n }\r\n\r\n const parentNode = objectMap.objects.get(parent.id);\r\n if (!parentNode || parentNode.name !== \"Geometry\") {\r\n return null;\r\n }\r\n\r\n const geometryId = parent.id;\r\n\r\n // Find BlendShapeChannel children\r\n const channels: FBXBlendShapeChannelData[] = [];\r\n const channelChildren = getChildren(objectMap, deformerId, \"Deformer\");\r\n\r\n for (const { id: channelId, node: channelNode } of channelChildren) {\r\n const subType = getPropertyValue<string>(channelNode, 2);\r\n if (subType !== \"BlendShapeChannel\") {\r\n continue;\r\n }\r\n\r\n const channelName = cleanFBXName(getPropertyValue<string>(channelNode, 1) ?? \"MorphTarget\");\r\n\r\n // Read DeformPercent from Properties70\r\n let deformPercent = 0;\r\n const props70 = findChildByName(channelNode, \"Properties70\");\r\n if (props70) {\r\n for (const p of props70.children) {\r\n if (p.name !== \"P\") {\r\n continue;\r\n }\r\n const pName = getPropertyValue<string>(p, 0);\r\n if (pName === \"DeformPercent\") {\r\n const val = p.properties[4]?.value;\r\n if (typeof val === \"number\") {\r\n deformPercent = val;\r\n }\r\n }\r\n }\r\n }\r\n\r\n const rawFullWeights = extractFullWeights(channelNode);\r\n\r\n // Find connected Shape geometries\r\n const shapes: FBXShapeData[] = [];\r\n const shapeChildren = getChildren(objectMap, channelId, \"Geometry\");\r\n\r\n for (const { node: shapeNode } of shapeChildren) {\r\n const shapeSubType = getPropertyValue<string>(shapeNode, 2);\r\n if (shapeSubType !== \"Shape\") {\r\n continue;\r\n }\r\n\r\n const shape = extractShape(shapeNode);\r\n if (shape) {\r\n shapes.push(shape);\r\n }\r\n }\r\n\r\n if (shapes.length > 0) {\r\n const diagnostics: FBXBlendShapeDiagnostic[] = [];\r\n const fullWeights = normalizeFullWeights(rawFullWeights, shapes, channelId, channelName, diagnostics);\r\n channels.push({\r\n name: channelName,\r\n id: channelId,\r\n deformPercent,\r\n shapes: sortShapesByFullWeight(shapes, fullWeights),\r\n fullWeights: fullWeights ? [...fullWeights].sort((a, b) => a - b) : null,\r\n diagnostics,\r\n });\r\n }\r\n }\r\n\r\n if (channels.length === 0) {\r\n return null;\r\n }\r\n\r\n return {\r\n id: deformerId,\r\n geometryId,\r\n channels,\r\n };\r\n}\r\n\r\nfunction extractFullWeights(channelNode: FBXNode): number[] | null {\r\n const fullWeightsNode = findChildByName(channelNode, \"FullWeights\");\r\n const rawFullWeights = fullWeightsNode?.properties[0]?.value;\r\n if (!rawFullWeights) {\r\n return null;\r\n }\r\n\r\n if (rawFullWeights instanceof Float64Array || rawFullWeights instanceof Float32Array || rawFullWeights instanceof Int32Array) {\r\n return Array.from(rawFullWeights, (value) => Number(value));\r\n }\r\n return null;\r\n}\r\n\r\nfunction normalizeFullWeights(\r\n fullWeights: number[] | null,\r\n shapes: FBXShapeData[],\r\n channelId: number,\r\n channelName: string,\r\n diagnostics: FBXBlendShapeDiagnostic[]\r\n): number[] | null {\r\n if (!fullWeights) {\r\n if (shapes.length > 1) {\r\n diagnostics.push({\r\n type: \"missing-full-weights\",\r\n message: \"Blend shape channel has multiple shapes but no FullWeights; using the first shape for compatibility.\",\r\n channelId,\r\n channelName,\r\n });\r\n }\r\n return null;\r\n }\r\n\r\n if (fullWeights.length !== shapes.length) {\r\n if (shapes.length === 1) {\r\n return null;\r\n }\r\n\r\n diagnostics.push({\r\n type: \"full-weights-mismatch\",\r\n message: `FullWeights length ${fullWeights.length} does not match shape count ${shapes.length}; using the first shape for compatibility.`,\r\n channelId,\r\n channelName,\r\n });\r\n return null;\r\n }\r\n\r\n return fullWeights;\r\n}\r\n\r\nfunction sortShapesByFullWeight(shapes: FBXShapeData[], fullWeights: number[] | null): FBXShapeData[] {\r\n if (!fullWeights || fullWeights.length !== shapes.length) {\r\n return shapes.length > 1 ? [shapes[0]] : shapes;\r\n }\r\n\r\n return shapes\r\n .map((shape, index) => ({ shape, weight: fullWeights[index] }))\r\n .sort((a, b) => a.weight - b.weight)\r\n .map((entry) => entry.shape);\r\n}\r\n\r\nfunction extractShape(shapeNode: FBXNode): FBXShapeData | null {\r\n // Shape has: Indexes (sparse vertex indices), Vertices (delta offsets from base), Normals (optional delta)\r\n const indexesNode = findChildByName(shapeNode, \"Indexes\");\r\n const verticesNode = findChildByName(shapeNode, \"Vertices\");\r\n\r\n if (!indexesNode || !verticesNode) {\r\n return null;\r\n }\r\n\r\n const rawIndices = indexesNode.properties[0]?.value;\r\n const rawVertices = verticesNode.properties[0]?.value;\r\n\r\n if (!rawIndices || !rawVertices) {\r\n return null;\r\n }\r\n\r\n const indices = toUint32Array(rawIndices);\r\n if (!indices) {\r\n return null;\r\n }\r\n\r\n // Convert vertices\r\n let vertices: Float64Array;\r\n if (rawVertices instanceof Float64Array) {\r\n vertices = rawVertices;\r\n } else if (rawVertices instanceof Float32Array) {\r\n vertices = new Float64Array(rawVertices);\r\n } else {\r\n return null;\r\n }\r\n\r\n // Optional normals\r\n let normals: Float64Array | null = null;\r\n const normalsNode = findChildByName(shapeNode, \"Normals\");\r\n if (normalsNode) {\r\n const rawNormals = normalsNode.properties[0]?.value;\r\n if (rawNormals instanceof Float64Array) {\r\n normals = rawNormals;\r\n } else if (rawNormals instanceof Float32Array) {\r\n normals = new Float64Array(rawNormals);\r\n }\r\n }\r\n\r\n return { indices, vertices, normals };\r\n}\r\n\r\nfunction toUint32Array(value: unknown): Uint32Array | null {\r\n if (value instanceof Uint32Array) {\r\n return value;\r\n }\r\n if (value instanceof Int32Array || value instanceof Float32Array || value instanceof Float64Array) {\r\n const result = new Uint32Array(value.length);\r\n for (let i = 0; i < value.length; i++) {\r\n result[i] = value[i];\r\n }\r\n return result;\r\n }\r\n return null;\r\n}\r\n"]}
@@ -0,0 +1,95 @@
1
+ import { type FBXDocument, type FBXNode } from "../types/fbxTypes.js";
2
+ /** Connection type: OO = object-to-object, OP = object-to-property */
3
+ export type ConnectionType = "OO" | "OP";
4
+ /** A resolved FBX object connection. */
5
+ export interface FBXConnection {
6
+ /** Connection type. */
7
+ type: ConnectionType;
8
+ /** Child object ID. */
9
+ childId: number;
10
+ /** Parent object ID. */
11
+ parentId: number;
12
+ /** For OP connections, the property name on the parent (e.g. "DiffuseColor") */
13
+ propertyName?: string;
14
+ }
15
+ /** Object table entry used by the FBX connection graph. */
16
+ export interface FBXObjectEntry {
17
+ /** Object ID. */
18
+ id: number;
19
+ /** Object node. */
20
+ node: FBXNode;
21
+ /** Source of the object entry. */
22
+ source: "Objects" | "legacySyntheticGeometry";
23
+ /** Legacy string object name, when applicable. */
24
+ legacyName?: string;
25
+ /** True if the object was synthesized for legacy compatibility. */
26
+ synthetic: boolean;
27
+ }
28
+ /** Raw connection-table entry and import status. */
29
+ export interface FBXConnectionEntry {
30
+ /** Source node name. */
31
+ source: "C" | "Connect";
32
+ /** Raw connection type. */
33
+ rawType?: string;
34
+ /** Child object ID, when resolved. */
35
+ childId?: number;
36
+ /** Parent object ID, when resolved. */
37
+ parentId?: number;
38
+ /** OP connection property name, when present. */
39
+ propertyName?: string;
40
+ /** True if the connection was accepted into the resolved graph. */
41
+ accepted: boolean;
42
+ }
43
+ /** Reason a connection produced a diagnostic. */
44
+ export type FBXConnectionDiagnosticReason = "unsupported-connection-type" | "missing-connection-endpoint" | "unresolved-legacy-endpoint" | "unresolved-object-reference" | "duplicate-parent" | "self-loop";
45
+ /** Recoverable connection graph issue. */
46
+ export interface FBXConnectionDiagnostic {
47
+ /** Diagnostic reason. */
48
+ reason: FBXConnectionDiagnosticReason;
49
+ /** Human-readable diagnostic message. */
50
+ message: string;
51
+ /** Connection-table index associated with the diagnostic, if applicable. */
52
+ connectionIndex?: number;
53
+ /** Connection type associated with the diagnostic, if applicable. */
54
+ type?: string;
55
+ /** Child object ID associated with the diagnostic, if applicable. */
56
+ childId?: number;
57
+ /** Parent object ID associated with the diagnostic, if applicable. */
58
+ parentId?: number;
59
+ /** OP connection property name associated with the diagnostic, if applicable. */
60
+ propertyName?: string;
61
+ }
62
+ /** Resolved FBX object and connection graph. */
63
+ export interface FBXObjectMap {
64
+ /** All objects by their unique ID */
65
+ objects: Map<number, FBXNode>;
66
+ /** Object table entries, including synthetic compatibility objects */
67
+ objectEntries: FBXObjectEntry[];
68
+ /** Children of each object ID */
69
+ childrenOf: Map<number, {
70
+ id: number;
71
+ propertyName?: string;
72
+ }[]>;
73
+ /** Parent of each object ID */
74
+ parentOf: Map<number, {
75
+ id: number;
76
+ propertyName?: string;
77
+ }>;
78
+ /** Raw connection list */
79
+ connections: FBXConnection[];
80
+ /** Raw connection-table entries and whether they were accepted into the graph */
81
+ connectionEntries: FBXConnectionEntry[];
82
+ /** Unsupported or suspicious connection shapes encountered while preserving graph behavior */
83
+ diagnostics: FBXConnectionDiagnostic[];
84
+ }
85
+ /**
86
+ * Build a connection graph from a parsed FBX document.
87
+ * Maps object IDs to their FBXNode and resolves parent-child relationships.
88
+ */
89
+ export declare function resolveConnections(doc: FBXDocument): FBXObjectMap;
90
+ /** Get all child objects of a given parent ID, optionally filtered by node name */
91
+ export declare function getChildren(map: FBXObjectMap, parentId: number, nodeName?: string): {
92
+ id: number;
93
+ node: FBXNode;
94
+ propertyName?: string;
95
+ }[];