Skip to content

Commit

Permalink
update transform calculations to match FBX SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
looeee committed Sep 18, 2018
1 parent 3e5b0f2 commit 894a79d
Showing 1 changed file with 169 additions and 54 deletions.
223 changes: 169 additions & 54 deletions examples/js/loaders/FBXLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ THREE.FBXLoader = ( function () {
crossOrigin: 'anonymous',

load: function ( url, onLoad, onProgress, onError ) {

var self = this;

var resourceDirectory = THREE.LoaderUtils.extractUrlBase( url );
Expand All @@ -64,7 +65,8 @@ THREE.FBXLoader = ( function () {
}

}, onProgress, onError );
},

},

setCrossOrigin: function ( value ) {

Expand Down Expand Up @@ -99,7 +101,7 @@ THREE.FBXLoader = ( function () {

}

// console.log( fbxTree );
console.log( fbxTree );

var textureLoader = new THREE.TextureLoader( this.manager ).setPath( resourceDirectory ).setCrossOrigin( this.crossOrigin );

Expand Down Expand Up @@ -825,6 +827,25 @@ THREE.FBXLoader = ( function () {

sceneGraph.animations = animations;

sceneGraph.traverse( function ( node ) {

if ( node.userData.transformData ) {

if ( node.parent ) node.userData.transformData.parentMatrixWorld = node.parent.matrix;

var transform = generateTransform( node.userData.transformData );

// if ( node.parent ) transform = node.parent.matrix.getInverse( node.parent.matrix ).multiply( transform );

node.applyMatrix( transform );

// if ( node.parent )


}

} );

},

// parse nodes in FBXTree.Objects.Model
Expand Down Expand Up @@ -870,7 +891,7 @@ THREE.FBXLoader = ( function () {

}

this.setModelTransforms( model, node );
this.getTransformData( model, node );
modelMap.set( id, model );

}
Expand Down Expand Up @@ -1108,9 +1129,9 @@ THREE.FBXLoader = ( function () {
var penumbra = 0;
if ( lightAttribute.OuterAngle !== undefined ) {

// TODO: this is not correct - FBX calculates outer and inner angle in degrees
// with OuterAngle > InnerAngle && OuterAngle <= Math.PI
// while three.js uses a penumbra between (0, 1) to attenuate the inner angle
// TODO: this is not correct - FBX calculates outer and inner angle in degrees
// with OuterAngle > InnerAngle && OuterAngle <= Math.PI
// while three.js uses a penumbra between (0, 1) to attenuate the inner angle
penumbra = THREE.Math.degToRad( lightAttribute.OuterAngle.value );
penumbra = Math.max( penumbra, 1 );

Expand Down Expand Up @@ -1223,22 +1244,43 @@ THREE.FBXLoader = ( function () {

},

// parse the model node for transform details and apply them to the model
setModelTransforms: function ( model, modelNode ) {
// parse the model node for transform data
getTransformData: function ( model, modelNode ) {

var transformData = {};

// 0 = RrSs, 1 = RSrs, 2 = Rrs
// RrSs: Scaling of parent is applied in the child world after the local child rotation
// RrSs:= GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalSM(x)
// RSrs: Scaling of parent is applied in the parent world
// RSrs:= GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalRM(x) * LocalSM(x)
// Rrs: Scaling of parent does not affect the scaling of children
// Rrs:= GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * LocalSM(x)
if ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value );

// rotation order
if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = parseInt( modelNode.RotationOrder.value );

// translation
if ( 'Lcl_Translation' in modelNode ) transformData.translation = modelNode.Lcl_Translation.value;
if ( 'RotationOffset' in modelNode ) transformData.rotationOffset = modelNode.RotationOffset.value;
if ( 'Lcl_Rotation' in modelNode ) transformData.rotation = modelNode.Lcl_Rotation.value;

// rotation
if ( 'PreRotation' in modelNode ) transformData.preRotation = modelNode.PreRotation.value;
if ( 'Lcl_Rotation' in modelNode ) transformData.rotation = modelNode.Lcl_Rotation.value;
if ( 'PostRotation' in modelNode ) transformData.postRotation = modelNode.PostRotation.value;

// scaling
if ( 'Lcl_Scaling' in modelNode ) transformData.scale = modelNode.Lcl_Scaling.value;

var transform = generateTransform( transformData );

model.applyMatrix( transform );
// offset and pivot
if ( 'ScalingOffset' in modelNode ) transformData.scalingOffset = modelNode.ScalingOffset.value;
if ( 'ScalingPivot' in modelNode ) transformData.scalingPivot = modelNode.ScalingPivot.value;

if ( 'RotationOffset' in modelNode ) transformData.rotationOffset = modelNode.RotationOffset.value;
if ( 'RotationPivot' in modelNode ) transformData.rotationPivot = modelNode.RotationPivot.value;

model.userData.transformData = transformData;

},

Expand Down Expand Up @@ -1493,16 +1535,15 @@ THREE.FBXLoader = ( function () {

}, null );

// TODO: if there is more than one model associated with the geometry, AND the models have
// different geometric transforms, then this will cause problems
// if ( modelNodes.length > 1 ) { }

// For now just assume one model and get the preRotations from that
// Assume one model and get the preRotations from that
// if there is more than one model associated with the geometry this may cause problems
var modelNode = modelNodes[ 0 ];

var transformData = {};

if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = modelNode.RotationOrder.value;
if ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value );

if ( 'GeometricTranslation' in modelNode ) transformData.translation = modelNode.GeometricTranslation.value;
if ( 'GeometricRotation' in modelNode ) transformData.rotation = modelNode.GeometricRotation.value;
if ( 'GeometricScaling' in modelNode ) transformData.scale = modelNode.GeometricScaling.value;
Expand Down Expand Up @@ -2496,18 +2537,42 @@ THREE.FBXLoader = ( function () {

var transformData = {};

// if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = parseInt( modelNode.RotationOrder.value );

// if ( 'Lcl_Translation' in modelNode ) transformData.translation = modelNode.Lcl_Translation.value;
// if ( 'RotationOffset' in modelNode ) transformData.rotationOffset = modelNode.RotationOffset.value;

// if ( 'Lcl_Rotation' in modelNode ) transformData.rotation = modelNode.Lcl_Rotation.value;
// if ( 'PreRotation' in modelNode ) transformData.preRotation = modelNode.PreRotation.value;

// if ( 'PostRotation' in modelNode ) transformData.postRotation = modelNode.PostRotation.value;

// if ( 'Lcl_Scaling' in modelNode ) transformData.scale = modelNode.Lcl_Scaling.value;

if ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value );

// rotation order
if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = parseInt( modelNode.RotationOrder.value );

// translation
if ( 'Lcl_Translation' in modelNode ) transformData.translation = modelNode.Lcl_Translation.value;
if ( 'RotationOffset' in modelNode ) transformData.rotationOffset = modelNode.RotationOffset.value;

if ( 'Lcl_Rotation' in modelNode ) transformData.rotation = modelNode.Lcl_Rotation.value;
// rotation
if ( 'PreRotation' in modelNode ) transformData.preRotation = modelNode.PreRotation.value;

if ( 'Lcl_Rotation' in modelNode ) transformData.rotation = modelNode.Lcl_Rotation.value;
if ( 'PostRotation' in modelNode ) transformData.postRotation = modelNode.PostRotation.value;

// scaling
if ( 'Lcl_Scaling' in modelNode ) transformData.scale = modelNode.Lcl_Scaling.value;


// offset and pivot
if ( 'ScalingOffset' in modelNode ) transformData.scalingOffset = modelNode.ScalingOffset.value;
if ( 'ScalingPivot' in modelNode ) transformData.scalingPivot = modelNode.ScalingPivot.value;

if ( 'RotationOffset' in modelNode ) transformData.rotationOffset = modelNode.RotationOffset.value;
if ( 'RotationPivot' in modelNode ) transformData.rotationPivot = modelNode.RotationPivot.value;

return generateTransform( transformData );

},
Expand Down Expand Up @@ -2954,7 +3019,7 @@ THREE.FBXLoader = ( function () {
// if the subnode already exists, append it
if ( nodeName in currentNode ) {

// special case Pose needs PoseNodes as an array
// special case Pose needs PoseNodes as an array
if ( nodeName === 'PoseNode' ) {

currentNode.PoseNode.push( node );
Expand Down Expand Up @@ -3860,68 +3925,118 @@ THREE.FBXLoader = ( function () {
var tempMat = new THREE.Matrix4();
var tempEuler = new THREE.Euler();
var tempVec = new THREE.Vector3();
var translation = new THREE.Vector3();
var rotation = new THREE.Matrix4();

// generate transformation from FBX transform data
// ref: https://help.autodesk.com/view/FBX/2017/ENU/?guid=__files_GUID_10CDD63C_79C1_4F2D_BB28_AD2BE65A02ED_htm
// transformData = {
// eulerOrder: int,
// translation: [],
// rotationOffset: [],
// preRotation
// rotation
// postRotation
// scale
// }
// all entries are optional
// ref: http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/_transformations_2main_8cxx-example.html,topicNumber=cpp_ref__transformations_2main_8cxx_example_htmlfc10a1e1-b18d-4e72-9dc0-70d0f1959f5e
function generateTransform( transformData ) {

var transform = new THREE.Matrix4();
translation.set( 0, 0, 0 );
rotation.identity();
// console.log( 'transformData', transformData );

var order = ( transformData.eulerOrder ) ? getEulerOrder( transformData.eulerOrder ) : getEulerOrder( 0 );
var lTranslationM = new THREE.Matrix4();
var lPreRotationM = new THREE.Matrix4();
var lRotationM = new THREE.Matrix4();
var lPostRotationM = new THREE.Matrix4();
var lTransform = new THREE.Matrix4();

if ( transformData.translation ) translation.fromArray( transformData.translation );
if ( transformData.rotationOffset ) translation.add( tempVec.fromArray( transformData.rotationOffset ) );
var lScalingM = new THREE.Matrix4();
var lScalingPivotM = new THREE.Matrix4();
var lScalingOffsetM = new THREE.Matrix4();
var lRotationOffsetM = new THREE.Matrix4();
var lRotationPivotM = new THREE.Matrix4();

if ( transformData.rotation ) {
var lParentGX = new THREE.Matrix4();
var lGlobalT = new THREE.Matrix4();
var lGlobalRS = new THREE.Matrix4();

var array = transformData.rotation.map( THREE.Math.degToRad );
array.push( order );
rotation.makeRotationFromEuler( tempEuler.fromArray( array ) );
var order = ( transformData.eulerOrder ) ? getEulerOrder( transformData.eulerOrder ) : getEulerOrder( 0 );
var inheritType = ( transformData.inheritType ) ? transformData.inheritType : 0;

}
if ( transformData.translation ) lTranslationM.setPosition( tempVec.fromArray( transformData.translation ) );

if ( transformData.preRotation ) {

var array = transformData.preRotation.map( THREE.Math.degToRad );
array.push( order );
tempMat.makeRotationFromEuler( tempEuler.fromArray( array ) );
lPreRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );

}

rotation.premultiply( tempMat );
if ( transformData.rotation ) {

var array = transformData.rotation.map( THREE.Math.degToRad );
array.push( order );
lRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );

}

if ( transformData.postRotation ) {

var array = transformData.postRotation.map( THREE.Math.degToRad );
array.push( order );
tempMat.makeRotationFromEuler( tempEuler.fromArray( array ) );
lPostRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );

tempMat.getInverse( tempMat );
}

if ( transformData.scale ) lScalingM.scale( tempVec.fromArray( transformData.scale ) );

// Pivots and offsets
if ( transformData.scalingOffset ) lScalingOffsetM.setPosition( tempVec.fromArray( transformData.scalingOffset ) );
if ( transformData.scalingPivot ) lScalingPivotM.setPosition( tempVec.fromArray( transformData.scalingPivot ) );
if ( transformData.rotationOffset ) lRotationOffsetM.setPosition( tempVec.fromArray( transformData.rotationOffset ) );
if ( transformData.rotationPivot ) lRotationPivotM.setPosition( tempVec.fromArray( transformData.rotationPivot ) );

// parent transform
if ( transformData.parentMatrixWorld ) lParentGX = transformData.parentMatrixWorld;

// Global Rotation
var lLRM = lPreRotationM.multiply( lRotationM ).multiply( lPostRotationM );
var lParentGRM = new THREE.Matrix4();
lParentGX.extractRotation( lParentGRM );

// Global Shear*Scaling
var lLSM = new THREE.Matrix4();
var lParentGSM = new THREE.Matrix4();
var lParentGRSM = new THREE.Matrix4();
var lParentTM = new THREE.Matrix4();

lParentTM.copyPosition( lParentGX );
lParentGRSM = lParentTM.getInverse( lParentTM ).multiply( lParentGX );
lParentGSM = lParentGRM.getInverse( lParentGRM ).multiply( lParentGRSM );
lLSM = lScalingM;

if ( inheritType === 0 ) {

lGlobalRS = lParentGRM.multiply( lLRM ).multiply( lParentGSM ).multiply( lLSM );

rotation.multiply( tempMat );
} else if ( inheritType === 1 ) {

lGlobalRS = lParentGRM.multiply( lParentGSM ).multiply( lLRM ).multiply( lLSM );

} else {

var lParentLSM = new THREE.Matrix4().copy( lScalingM );

var lParentGSM_noLocal = lParentGSM.multiply( lParentLSM.getInverse( lParentLSM ) );

lGlobalRS = lParentGRM.multiply( lLRM ).multiply( lParentGSM_noLocal ).multiply( lLSM );

}

if ( transformData.scale ) transform.scale( tempVec.fromArray( transformData.scale ) );

transform.setPosition( translation );
transform.multiply( rotation );
// Calculate the local transform matrix
lTransform = lTranslationM.multiply( lRotationOffsetM ).multiply( lRotationPivotM ).multiply( lPreRotationM ).multiply( lRotationM ).multiply( lPostRotationM ).multiply( lRotationPivotM.getInverse( lRotationPivotM ) ).multiply( lScalingOffsetM ).multiply( lScalingPivotM ).multiply( lScalingM ).multiply( lScalingPivotM.getInverse( lScalingPivotM ) );

var lLocalTWithAllPivotAndOffsetInfo = new THREE.Matrix4().copyPosition( lTransform );

var lGlobalTranslation = lParentGX.multiply( lLocalTWithAllPivotAndOffsetInfo );
lGlobalT.copyPosition( lGlobalTranslation );

lTransform = lGlobalT.multiply( lGlobalRS );

return lTransform;

return transform;
// = new THREE.Matrix4();

}

Expand All @@ -3936,7 +4051,7 @@ THREE.FBXLoader = ( function () {
'ZXY', // -> YXZ extrinsic
'YXZ', // -> ZXY extrinsic
'XYZ', // -> ZYX extrinsic
//'SphericXYZ', // not possible to support
//'SphericXYZ', // not possible to support
];

if ( order === 6 ) {
Expand Down

0 comments on commit 894a79d

Please sign in to comment.