|
@@ -103,9 +103,9 @@
|
|
|
var images = parseImages( FBXTree );
|
|
|
var textures = parseTextures( FBXTree, new THREE.TextureLoader( this.manager ).setPath( resourceDirectory ), images, connections );
|
|
|
var materials = parseMaterials( FBXTree, textures, connections );
|
|
|
- var deformers = parseDeformers( FBXTree, connections );
|
|
|
- var geometryMap = parseGeometries( FBXTree, connections, deformers );
|
|
|
- var sceneGraph = parseScene( FBXTree, connections, deformers, geometryMap, materials );
|
|
|
+ var skeletons = parseDeformers( FBXTree, connections );
|
|
|
+ var geometryMap = parseGeometries( FBXTree, connections, skeletons );
|
|
|
+ var sceneGraph = parseScene( FBXTree, connections, skeletons, geometryMap, materials );
|
|
|
|
|
|
return sceneGraph;
|
|
|
|
|
@@ -310,7 +310,7 @@
|
|
|
|
|
|
var texture = loadTexture( textureNode, loader, imageMap, connections );
|
|
|
|
|
|
- texture.FBX_ID = textureNode.id;
|
|
|
+ texture.ID = textureNode.id;
|
|
|
|
|
|
texture.name = textureNode.attrName;
|
|
|
|
|
@@ -419,7 +419,7 @@
|
|
|
// FBX format currently only supports Lambert and Phong shading models
|
|
|
function parseMaterial( FBXTree, materialNode, textureMap, connections ) {
|
|
|
|
|
|
- var FBX_ID = materialNode.id;
|
|
|
+ var ID = materialNode.id;
|
|
|
var name = materialNode.attrName;
|
|
|
var type = materialNode.properties.ShadingModel;
|
|
|
|
|
@@ -431,9 +431,9 @@
|
|
|
}
|
|
|
|
|
|
// Ignore unused materials which don't have any connections.
|
|
|
- if ( ! connections.has( FBX_ID ) ) return null;
|
|
|
+ if ( ! connections.has( ID ) ) return null;
|
|
|
|
|
|
- var parameters = parseParameters( FBXTree, materialNode.properties, textureMap, FBX_ID, connections );
|
|
|
+ var parameters = parseParameters( FBXTree, materialNode.properties, textureMap, ID, connections );
|
|
|
|
|
|
var material;
|
|
|
|
|
@@ -461,8 +461,7 @@
|
|
|
|
|
|
// Parse FBX material and return parameters suitable for a three.js material
|
|
|
// Also parse the texture map and return any textures associated with the material
|
|
|
- function parseParameters( FBXTree, properties, textureMap, FBX_ID, connections ) {
|
|
|
-
|
|
|
+ function parseParameters( FBXTree, properties, textureMap, ID, connections ) {
|
|
|
|
|
|
var parameters = {};
|
|
|
|
|
@@ -517,7 +516,7 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- connections.get( FBX_ID ).children.forEach( function ( child ) {
|
|
|
+ connections.get( ID ).children.forEach( function ( child ) {
|
|
|
|
|
|
var type = child.relationship;
|
|
|
|
|
@@ -594,7 +593,7 @@
|
|
|
// Generates map of Skeleton-like objects for use later when generating and binding skeletons.
|
|
|
function parseDeformers( FBXTree, connections ) {
|
|
|
|
|
|
- var deformers = {};
|
|
|
+ var skeletons = {};
|
|
|
|
|
|
if ( 'Deformer' in FBXTree.Objects.subNodes ) {
|
|
|
|
|
@@ -607,10 +606,14 @@
|
|
|
if ( deformerNode.attrType === 'Skin' ) {
|
|
|
|
|
|
var relationships = connections.get( parseInt( nodeID ) );
|
|
|
+
|
|
|
var skeleton = parseSkeleton( relationships, DeformerNodes );
|
|
|
- skeleton.FBX_ID = parseInt( nodeID );
|
|
|
+ skeleton.ID = nodeID;
|
|
|
+
|
|
|
+ if ( relationships.parents.length > 1 ) console.warn( 'THREE.FBXLoader: skeleton attached to more than one geometry is not supported.' );
|
|
|
+ skeleton.geometryID = relationships.parents[ 0 ].ID;
|
|
|
|
|
|
- deformers[ nodeID ] = skeleton;
|
|
|
+ skeletons[ nodeID ] = skeleton;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -618,47 +621,51 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- return deformers;
|
|
|
+ return skeletons;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Parse single nodes in FBXTree.Objects.subNodes.Deformer
|
|
|
- // Generates a "Skeleton Representation" of FBX nodes based on an FBX Skin Deformer's connections
|
|
|
- // and an object containing SubDeformer nodes.
|
|
|
- function parseSkeleton( connections, DeformerNodes ) {
|
|
|
+ // The top level deformer nodes have type 'Skin' and subDeformer nodes have type 'Cluster'
|
|
|
+ // Each skin node represents a skeleton and each cluster node represents a bone
|
|
|
+ function parseSkeleton( connections, deformerNodes ) {
|
|
|
|
|
|
- var subDeformers = {};
|
|
|
+ var rawBones = [];
|
|
|
|
|
|
- connections.children.forEach( function ( child, i ) {
|
|
|
+ connections.children.forEach( function ( child ) {
|
|
|
|
|
|
- var subDeformerNode = DeformerNodes[ child.ID ];
|
|
|
+ var subDeformerNode = deformerNodes[ child.ID ];
|
|
|
|
|
|
- var subDeformer = {
|
|
|
+ if ( subDeformerNode.attrType !== 'Cluster' ) return;
|
|
|
|
|
|
- FBX_ID: child.ID,
|
|
|
- index: i,
|
|
|
+ var rawBone = {
|
|
|
+
|
|
|
+ ID: child.ID,
|
|
|
indices: [],
|
|
|
weights: [],
|
|
|
+
|
|
|
+ // the global initial transform of the geometry node this bone is connected to
|
|
|
transform: new THREE.Matrix4().fromArray( subDeformerNode.subNodes.Transform.properties.a ),
|
|
|
+
|
|
|
+ // the global initial transform of this bone
|
|
|
transformLink: new THREE.Matrix4().fromArray( subDeformerNode.subNodes.TransformLink.properties.a ),
|
|
|
- linkMode: subDeformerNode.properties.Mode,
|
|
|
|
|
|
};
|
|
|
|
|
|
if ( 'Indexes' in subDeformerNode.subNodes ) {
|
|
|
|
|
|
- subDeformer.indices = subDeformerNode.subNodes.Indexes.properties.a;
|
|
|
- subDeformer.weights = subDeformerNode.subNodes.Weights.properties.a;
|
|
|
+ rawBone.indices = subDeformerNode.subNodes.Indexes.properties.a;
|
|
|
+ rawBone.weights = subDeformerNode.subNodes.Weights.properties.a;
|
|
|
|
|
|
}
|
|
|
|
|
|
- subDeformers[ child.ID ] = subDeformer;
|
|
|
+ rawBones.push( rawBone );
|
|
|
|
|
|
} );
|
|
|
|
|
|
return {
|
|
|
|
|
|
- map: subDeformers,
|
|
|
+ rawBones: rawBones,
|
|
|
bones: []
|
|
|
|
|
|
};
|
|
@@ -666,7 +673,7 @@
|
|
|
}
|
|
|
|
|
|
// Parse nodes in FBXTree.Objects.subNodes.Geometry
|
|
|
- function parseGeometries( FBXTree, connections, deformers ) {
|
|
|
+ function parseGeometries( FBXTree, connections, skeletons ) {
|
|
|
|
|
|
var geometryMap = new Map();
|
|
|
|
|
@@ -677,7 +684,7 @@
|
|
|
for ( var nodeID in geometryNodes ) {
|
|
|
|
|
|
var relationships = connections.get( parseInt( nodeID ) );
|
|
|
- var geo = parseGeometry( FBXTree, relationships, geometryNodes[ nodeID ], deformers );
|
|
|
+ var geo = parseGeometry( FBXTree, relationships, geometryNodes[ nodeID ], skeletons );
|
|
|
geometryMap.set( parseInt( nodeID ), geo );
|
|
|
|
|
|
}
|
|
@@ -689,12 +696,12 @@
|
|
|
}
|
|
|
|
|
|
// Parse single node in FBXTree.Objects.subNodes.Geometry
|
|
|
- function parseGeometry( FBXTree, relationships, geometryNode, deformers ) {
|
|
|
+ function parseGeometry( FBXTree, relationships, geometryNode, skeletons ) {
|
|
|
|
|
|
switch ( geometryNode.attrType ) {
|
|
|
|
|
|
case 'Mesh':
|
|
|
- return parseMeshGeometry( FBXTree, relationships, geometryNode, deformers );
|
|
|
+ return parseMeshGeometry( FBXTree, relationships, geometryNode, skeletons );
|
|
|
break;
|
|
|
|
|
|
case 'NurbsCurve':
|
|
@@ -706,27 +713,25 @@
|
|
|
}
|
|
|
|
|
|
// Parse single node mesh geometry in FBXTree.Objects.subNodes.Geometry
|
|
|
- function parseMeshGeometry( FBXTree, relationships, geometryNode, deformers ) {
|
|
|
-
|
|
|
- var deformer = relationships.children.reduce( function ( deformer, child ) {
|
|
|
-
|
|
|
- if ( deformers[ child.ID ] !== undefined ) deformer = deformers[ child.ID ];
|
|
|
-
|
|
|
- return deformer;
|
|
|
-
|
|
|
- }, null );
|
|
|
+ function parseMeshGeometry( FBXTree, relationships, geometryNode, skeletons ) {
|
|
|
|
|
|
var modelNodes = relationships.parents.map( function ( parent ) {
|
|
|
|
|
|
- var modelNode = FBXTree.Objects.subNodes.Model[ parent.ID ];
|
|
|
-
|
|
|
- return modelNode;
|
|
|
+ return FBXTree.Objects.subNodes.Model[ parent.ID ];
|
|
|
|
|
|
} );
|
|
|
|
|
|
// don't create geometry if it is not associated with any models
|
|
|
if ( modelNodes.length === 0 ) return;
|
|
|
|
|
|
+ var skeleton = relationships.children.reduce( function ( skeleton, child ) {
|
|
|
+
|
|
|
+ if ( skeletons[ child.ID ] !== undefined ) skeleton = skeletons[ child.ID ];
|
|
|
+
|
|
|
+ return skeleton;
|
|
|
+
|
|
|
+ }, null );
|
|
|
+
|
|
|
var preTransform = new THREE.Matrix4();
|
|
|
|
|
|
// TODO: if there is more than one model associated with the geometry, AND the models have
|
|
@@ -751,12 +756,12 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- return genGeometry( FBXTree, relationships, geometryNode, deformer, preTransform );
|
|
|
+ return genGeometry( FBXTree, relationships, geometryNode, skeleton, preTransform );
|
|
|
|
|
|
}
|
|
|
|
|
|
// Generate a THREE.BufferGeometry from a node in FBXTree.Objects.subNodes.Geometry
|
|
|
- function genGeometry( FBXTree, relationships, geometryNode, deformer, preTransform ) {
|
|
|
+ function genGeometry( FBXTree, relationships, geometryNode, skeleton, preTransform ) {
|
|
|
|
|
|
var subNodes = geometryNode.subNodes;
|
|
|
|
|
@@ -805,30 +810,25 @@
|
|
|
|
|
|
var weightTable = {};
|
|
|
|
|
|
- if ( deformer ) {
|
|
|
-
|
|
|
- var subDeformers = deformer.map;
|
|
|
+ if ( skeleton !== null ) {
|
|
|
|
|
|
- for ( var key in subDeformers ) {
|
|
|
+ skeleton.rawBones.forEach( function ( rawBone, i ) {
|
|
|
|
|
|
- var subDeformer = subDeformers[ key ];
|
|
|
-
|
|
|
- subDeformer.indices.forEach( function ( index, i ) {
|
|
|
-
|
|
|
- var weight = subDeformer.weights[ i ];
|
|
|
+ // loop over the bone's vertex indices and weights
|
|
|
+ rawBone.indices.forEach( function ( index, j ) {
|
|
|
|
|
|
if ( weightTable[ index ] === undefined ) weightTable[ index ] = [];
|
|
|
|
|
|
weightTable[ index ].push( {
|
|
|
|
|
|
- id: subDeformer.index,
|
|
|
- weight: weight
|
|
|
+ id: i,
|
|
|
+ weight: rawBone.weights[ j ],
|
|
|
|
|
|
} );
|
|
|
|
|
|
} );
|
|
|
|
|
|
- }
|
|
|
+ } );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -876,7 +876,7 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( deformer ) {
|
|
|
+ if ( skeleton ) {
|
|
|
|
|
|
if ( weightTable[ vertexIndex ] !== undefined ) {
|
|
|
|
|
@@ -999,7 +999,7 @@
|
|
|
vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 1 ] ] );
|
|
|
vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 2 ] ] );
|
|
|
|
|
|
- if ( deformer ) {
|
|
|
+ if ( skeleton ) {
|
|
|
|
|
|
vertexWeightsBuffer.push( faceWeights[ 0 ] );
|
|
|
vertexWeightsBuffer.push( faceWeights[ 1 ] );
|
|
@@ -1126,14 +1126,14 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( deformer ) {
|
|
|
+ if ( skeleton ) {
|
|
|
|
|
|
geo.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( weightsIndicesBuffer, 4 ) );
|
|
|
|
|
|
geo.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( vertexWeightsBuffer, 4 ) );
|
|
|
|
|
|
// used later to bind the skeleton to the model
|
|
|
- geo.FBX_Deformer = deformer;
|
|
|
+ geo.FBX_Deformer = skeleton;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1487,21 +1487,20 @@
|
|
|
}
|
|
|
|
|
|
// create the main THREE.Group() to be returned by the loader
|
|
|
- function parseScene( FBXTree, connections, deformers, geometryMap, materialMap ) {
|
|
|
+ function parseScene( FBXTree, connections, skeletons, geometryMap, materialMap ) {
|
|
|
|
|
|
var sceneGraph = new THREE.Group();
|
|
|
|
|
|
- var modelMap = parseModels( FBXTree, deformers, geometryMap, materialMap, connections );
|
|
|
+ var modelMap = parseModels( FBXTree, skeletons, geometryMap, materialMap, connections );
|
|
|
|
|
|
var modelNodes = FBXTree.Objects.subNodes.Model;
|
|
|
|
|
|
modelMap.forEach( function ( model ) {
|
|
|
|
|
|
- var modelNode = modelNodes[ model.FBX_ID ];
|
|
|
-
|
|
|
- setModelTransforms( FBXTree, model, modelNode, connections, sceneGraph );
|
|
|
+ var modelNode = modelNodes[ model.ID ];
|
|
|
+ setLookAtProperties( FBXTree, model, modelNode, connections, sceneGraph );
|
|
|
|
|
|
- var parentConnections = connections.get( model.FBX_ID ).parents;
|
|
|
+ var parentConnections = connections.get( model.ID ).parents;
|
|
|
|
|
|
parentConnections.forEach( function ( connection ) {
|
|
|
|
|
@@ -1516,9 +1515,11 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
+
|
|
|
} );
|
|
|
|
|
|
- bindSkeleton( FBXTree, deformers, geometryMap, modelMap, connections, sceneGraph );
|
|
|
+
|
|
|
+ bindSkeleton( FBXTree, skeletons, geometryMap, modelMap, connections, sceneGraph );
|
|
|
|
|
|
addAnimations( FBXTree, connections, sceneGraph, modelMap );
|
|
|
|
|
@@ -1529,7 +1530,7 @@
|
|
|
}
|
|
|
|
|
|
// parse nodes in FBXTree.Objects.subNodes.Model
|
|
|
- function parseModels( FBXTree, deformers, geometryMap, materialMap, connections ) {
|
|
|
+ function parseModels( FBXTree, skeletons, geometryMap, materialMap, connections ) {
|
|
|
|
|
|
var modelMap = new Map();
|
|
|
var modelNodes = FBXTree.Objects.subNodes.Model;
|
|
@@ -1539,37 +1540,8 @@
|
|
|
var id = parseInt( nodeID );
|
|
|
var node = modelNodes[ nodeID ];
|
|
|
var relationships = connections.get( id );
|
|
|
- var model = null;
|
|
|
-
|
|
|
- // create bones
|
|
|
- relationships.parents.forEach( function ( parent ) {
|
|
|
-
|
|
|
- for ( var FBX_ID in deformers ) {
|
|
|
-
|
|
|
- var deformer = deformers[ FBX_ID ];
|
|
|
- var subDeformers = deformer.map;
|
|
|
- var subDeformer = subDeformers[ parent.ID ];
|
|
|
-
|
|
|
- if ( subDeformer ) {
|
|
|
-
|
|
|
- var model2 = model;
|
|
|
- model = new THREE.Bone();
|
|
|
- deformer.bones[ subDeformer.index ] = model;
|
|
|
-
|
|
|
- // In cases where a bone is shared between multiple meshes
|
|
|
- // model will already be defined and we'll hit this case
|
|
|
- // TODO: currently doesn't work correctly
|
|
|
- if ( model2 !== null ) {
|
|
|
-
|
|
|
- model.add( model2 );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- } );
|
|
|
+ var model = buildSkeleton( relationships, skeletons, id, node.attrName );
|
|
|
|
|
|
if ( ! model ) {
|
|
|
|
|
@@ -1587,17 +1559,20 @@
|
|
|
case 'NurbsCurve':
|
|
|
model = createCurve( relationships, geometryMap );
|
|
|
break;
|
|
|
+ case 'LimbNode': // usually associated with a Bone, however if a Bone was not created we'll make a Group instead
|
|
|
+ case 'Null':
|
|
|
default:
|
|
|
model = new THREE.Group();
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ model.name = THREE.PropertyBinding.sanitizeNodeName( node.attrName );
|
|
|
+ model.ID = id;
|
|
|
|
|
|
- model.name = THREE.PropertyBinding.sanitizeNodeName( node.attrName );
|
|
|
- model.FBX_ID = id;
|
|
|
+ }
|
|
|
|
|
|
+ setModelTransforms( FBXTree, model, node );
|
|
|
modelMap.set( id, model );
|
|
|
|
|
|
}
|
|
@@ -1606,6 +1581,49 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function buildSkeleton( relationships, skeletons, id, name ) {
|
|
|
+
|
|
|
+ var bone = null;
|
|
|
+
|
|
|
+ relationships.parents.forEach( function ( parent ) {
|
|
|
+
|
|
|
+ for ( var ID in skeletons ) {
|
|
|
+
|
|
|
+ var skeleton = skeletons[ ID ];
|
|
|
+
|
|
|
+ skeleton.rawBones.forEach( function ( rawBone, i ) {
|
|
|
+
|
|
|
+ if ( rawBone.ID === parent.ID ) {
|
|
|
+
|
|
|
+ var subBone = bone;
|
|
|
+ bone = new THREE.Bone();
|
|
|
+
|
|
|
+ // set name and id here - otherwise in cases where "subBone" is created it will not have a name / id
|
|
|
+ bone.name = THREE.PropertyBinding.sanitizeNodeName( name );
|
|
|
+ bone.ID = id;
|
|
|
+
|
|
|
+ skeleton.bones[ i ] = bone;
|
|
|
+
|
|
|
+ // In cases where a bone is shared between multiple meshes
|
|
|
+ // duplicate the bone here and and it as a child of the first bone
|
|
|
+ if ( subBone !== null ) {
|
|
|
+
|
|
|
+ bone.add( subBone );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ return bone;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
// create a THREE.PerspectiveCamera or THREE.OrthographicCamera
|
|
|
function createCamera( FBXTree, relationships ) {
|
|
|
|
|
@@ -1924,8 +1942,46 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function setLookAtProperties( FBXTree, model, modelNode, connections, sceneGraph ) {
|
|
|
+
|
|
|
+ if ( 'LookAtProperty' in modelNode.properties ) {
|
|
|
+
|
|
|
+ var children = connections.get( model.ID ).children;
|
|
|
+
|
|
|
+ children.forEach( function ( child ) {
|
|
|
+
|
|
|
+ if ( child.relationship === 'LookAtProperty' ) {
|
|
|
+
|
|
|
+ var lookAtTarget = FBXTree.Objects.subNodes.Model[ child.ID ];
|
|
|
+
|
|
|
+ if ( 'Lcl_Translation' in lookAtTarget.properties ) {
|
|
|
+
|
|
|
+ var pos = lookAtTarget.properties.Lcl_Translation.value;
|
|
|
+
|
|
|
+ // DirectionalLight, SpotLight
|
|
|
+ if ( model.target !== undefined ) {
|
|
|
+
|
|
|
+ model.target.position.fromArray( pos );
|
|
|
+ sceneGraph.add( model.target );
|
|
|
+
|
|
|
+ } else { // Cameras and other Object3Ds
|
|
|
+
|
|
|
+ model.lookAt( new THREE.Vector3().fromArray( pos ) );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
// parse the model node for transform details and apply them to the model
|
|
|
- function setModelTransforms( FBXTree, model, modelNode, connections, sceneGraph ) {
|
|
|
+ function setModelTransforms( FBXTree, model, modelNode ) {
|
|
|
|
|
|
// http://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_euler_html
|
|
|
if ( 'RotationOrder' in modelNode.properties ) {
|
|
@@ -1991,43 +2047,9 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( 'LookAtProperty' in modelNode.properties ) {
|
|
|
-
|
|
|
- var children = connections.get( model.FBX_ID ).children;
|
|
|
-
|
|
|
- children.forEach( function ( child ) {
|
|
|
-
|
|
|
- if ( child.relationship === 'LookAtProperty' ) {
|
|
|
-
|
|
|
- var lookAtTarget = FBXTree.Objects.subNodes.Model[ child.ID ];
|
|
|
-
|
|
|
- if ( 'Lcl_Translation' in lookAtTarget.properties ) {
|
|
|
-
|
|
|
- var pos = lookAtTarget.properties.Lcl_Translation.value;
|
|
|
-
|
|
|
- // DirectionalLight, SpotLight
|
|
|
- if ( model.target !== undefined ) {
|
|
|
-
|
|
|
- model.target.position.fromArray( pos );
|
|
|
- sceneGraph.add( model.target );
|
|
|
-
|
|
|
- } else { // Cameras and other Object3Ds
|
|
|
-
|
|
|
- model.lookAt( new THREE.Vector3().fromArray( pos ) );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
}
|
|
|
|
|
|
- function bindSkeleton( FBXTree, deformers, geometryMap, modelMap, connections, sceneGraph ) {
|
|
|
+ function bindSkeleton( FBXTree, skeletons, geometryMap, modelMap, connections, sceneGraph ) {
|
|
|
|
|
|
// Now with the bones created, we can update the skeletons and bind them to the skinned meshes.
|
|
|
sceneGraph.updateMatrixWorld( true );
|
|
@@ -2067,47 +2089,45 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( var FBX_ID in deformers ) {
|
|
|
+ for ( var ID in skeletons ) {
|
|
|
|
|
|
- var deformer = deformers[ FBX_ID ];
|
|
|
- var subDeformers = deformer.map;
|
|
|
+ var skeleton = skeletons[ ID ];
|
|
|
|
|
|
- for ( var key in subDeformers ) {
|
|
|
+ skeleton.bones.forEach( function ( bone, i ) {
|
|
|
|
|
|
- var subDeformer = subDeformers[ key ];
|
|
|
- var subDeformerIndex = subDeformer.index;
|
|
|
+ // if the bone's initial transform is set in a poseNode, copy that
|
|
|
+ if ( worldMatrices.has( bone.ID ) ) {
|
|
|
|
|
|
- var bone = deformer.bones[ subDeformerIndex ];
|
|
|
- if ( ! worldMatrices.has( bone.FBX_ID ) ) {
|
|
|
+ var mat = worldMatrices.get( bone.ID );
|
|
|
+ bone.matrixWorld.copy( mat );
|
|
|
|
|
|
- break;
|
|
|
+ }
|
|
|
+ // otherwise use the transform from the rawBone
|
|
|
+ else {
|
|
|
+
|
|
|
+ bone.matrixWorld.copy( skeleton.rawBones[ i ].transformLink )
|
|
|
|
|
|
}
|
|
|
- var mat = worldMatrices.get( bone.FBX_ID );
|
|
|
- bone.matrixWorld.copy( mat );
|
|
|
|
|
|
- }
|
|
|
+ } );
|
|
|
|
|
|
// Now that skeleton is in bind pose, bind to model.
|
|
|
- deformer.skeleton = new THREE.Skeleton( deformer.bones );
|
|
|
-
|
|
|
- var relationships = connections.get( deformer.FBX_ID );
|
|
|
- var parents = relationships.parents;
|
|
|
+ var parents = connections.get( parseInt( skeleton.ID ) ).parents;
|
|
|
|
|
|
parents.forEach( function ( parent ) {
|
|
|
|
|
|
if ( geometryMap.has( parent.ID ) ) {
|
|
|
|
|
|
var geoID = parent.ID;
|
|
|
- var georelationships = connections.get( geoID );
|
|
|
+ var geoRelationships = connections.get( geoID );
|
|
|
|
|
|
- georelationships.parents.forEach( function ( geoConnParent ) {
|
|
|
+ geoRelationships.parents.forEach( function ( geoConnParent ) {
|
|
|
|
|
|
if ( modelMap.has( geoConnParent.ID ) ) {
|
|
|
|
|
|
var model = modelMap.get( geoConnParent.ID );
|
|
|
|
|
|
- model.bind( deformer.skeleton, model.matrixWorld );
|
|
|
+ model.bind( new THREE.Skeleton( skeleton.bones ), model.matrixWorld );
|
|
|
|
|
|
}
|
|
|
|