Forráskód Böngészése

Merge pull request #1806 from mesilliac/fbx_geometric_transforms_fix

FBX geometric transforms fix
Kim Kulling 7 éve
szülő
commit
c7dc63af8a
3 módosított fájl, 127 hozzáadás és 22 törlés
  1. 80 13
      code/FBXConverter.cpp
  2. 5 2
      code/FBXConverter.h
  3. 42 7
      tools/assimp_cmd/Info.cpp

+ 80 - 13
code/FBXConverter.cpp

@@ -142,6 +142,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
     nodes.reserve( conns.size() );
     nodes.reserve( conns.size() );
 
 
     std::vector<aiNode*> nodes_chain;
     std::vector<aiNode*> nodes_chain;
+    std::vector<aiNode*> post_nodes_chain;
 
 
     try {
     try {
         for( const Connection* con : conns ) {
         for( const Connection* con : conns ) {
@@ -161,6 +162,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
 
 
             if ( model ) {
             if ( model ) {
                 nodes_chain.clear();
                 nodes_chain.clear();
+                post_nodes_chain.clear();
 
 
                 aiMatrix4x4 new_abs_transform = parent_transform;
                 aiMatrix4x4 new_abs_transform = parent_transform;
 
 
@@ -168,7 +170,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
                 // assimp (or rather: the complicated transformation chain that
                 // assimp (or rather: the complicated transformation chain that
                 // is employed by fbx) means that we may need multiple aiNode's
                 // is employed by fbx) means that we may need multiple aiNode's
                 // to represent a fbx node's transformation.
                 // to represent a fbx node's transformation.
-                GenerateTransformationNodeChain( *model, nodes_chain );
+                GenerateTransformationNodeChain( *model, nodes_chain, post_nodes_chain );
 
 
                 ai_assert( nodes_chain.size() );
                 ai_assert( nodes_chain.size() );
 
 
@@ -213,8 +215,25 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
                 // attach geometry
                 // attach geometry
                 ConvertModel( *model, *nodes_chain.back(), new_abs_transform );
                 ConvertModel( *model, *nodes_chain.back(), new_abs_transform );
 
 
+                // now link the geometric transform inverse nodes,
+                // before we attach any child nodes
+                for( aiNode* postnode : post_nodes_chain ) {
+                    ai_assert( postnode );
+
+                    if ( last_parent != &parent ) {
+                        last_parent->mNumChildren = 1;
+                        last_parent->mChildren = new aiNode*[ 1 ];
+                        last_parent->mChildren[ 0 ] = postnode;
+                    }
+
+                    postnode->mParent = last_parent;
+                    last_parent = postnode;
+
+                    new_abs_transform *= postnode->mTransformation;
+                }
+
                 // attach sub-nodes
                 // attach sub-nodes
-                ConvertNodes( model->ID(), *nodes_chain.back(), new_abs_transform );
+                ConvertNodes( model->ID(), *last_parent, new_abs_transform );
 
 
                 if ( doc.Settings().readLights ) {
                 if ( doc.Settings().readLights ) {
                     ConvertLights( *model );
                     ConvertLights( *model );
@@ -396,6 +415,12 @@ const char* Converter::NameTransformationComp( TransformationComp comp )
         return "GeometricRotation";
         return "GeometricRotation";
     case TransformationComp_GeometricTranslation:
     case TransformationComp_GeometricTranslation:
         return "GeometricTranslation";
         return "GeometricTranslation";
+    case TransformationComp_GeometricScalingInverse:
+        return "GeometricScalingInverse";
+    case TransformationComp_GeometricRotationInverse:
+        return "GeometricRotationInverse";
+    case TransformationComp_GeometricTranslationInverse:
+        return "GeometricTranslationInverse";
     case TransformationComp_MAXIMUM: // this is to silence compiler warnings
     case TransformationComp_MAXIMUM: // this is to silence compiler warnings
     default:
     default:
         break;
         break;
@@ -437,6 +462,12 @@ const char* Converter::NameTransformationCompProperty( TransformationComp comp )
         return "GeometricRotation";
         return "GeometricRotation";
     case TransformationComp_GeometricTranslation:
     case TransformationComp_GeometricTranslation:
         return "GeometricTranslation";
         return "GeometricTranslation";
+    case TransformationComp_GeometricScalingInverse:
+        return "GeometricScalingInverse";
+    case TransformationComp_GeometricRotationInverse:
+        return "GeometricRotationInverse";
+    case TransformationComp_GeometricTranslationInverse:
+        return "GeometricTranslationInverse";
     case TransformationComp_MAXIMUM: // this is to silence compiler warnings
     case TransformationComp_MAXIMUM: // this is to silence compiler warnings
         break;
         break;
     }
     }
@@ -548,17 +579,25 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
     bool ok;
     bool ok;
 
 
     const float zero_epsilon = 1e-6f;
     const float zero_epsilon = 1e-6f;
+    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
     for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
     for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
         const TransformationComp comp = static_cast< TransformationComp >( i );
         const TransformationComp comp = static_cast< TransformationComp >( i );
 
 
-        if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ||
-                comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) {
+        if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ) {
             continue;
             continue;
         }
         }
 
 
+        bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling );
+
         const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
         const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
-        if ( ok && v.SquareLength() > zero_epsilon ) {
-            return true;
+        if ( ok && scale_compare ) {
+            if ( (v - all_ones).SquareLength() > zero_epsilon ) {
+                return true;
+            }
+        } else if ( ok ) {
+            if ( v.SquareLength() > zero_epsilon ) {
+                return true;
+            }
         }
         }
     }
     }
 
 
@@ -570,7 +609,7 @@ std::string Converter::NameTransformationChainNode( const std::string& name, Tra
     return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
     return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
 }
 }
 
 
-void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes )
+void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes )
 {
 {
     const PropertyTable& props = model.Props();
     const PropertyTable& props = model.Props();
     const Model::RotOrder rot = model.RotationOrder();
     const Model::RotOrder rot = model.RotationOrder();
@@ -582,6 +621,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
 
 
     // generate transformation matrices for all the different transformation components
     // generate transformation matrices for all the different transformation components
     const float zero_epsilon = 1e-6f;
     const float zero_epsilon = 1e-6f;
+    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
     bool is_complex = false;
     bool is_complex = false;
 
 
     const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
     const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
@@ -634,7 +674,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
     }
     }
 
 
     const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
     const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
-    if ( ok && std::fabs( Scaling.SquareLength() - 1.0f ) > zero_epsilon ) {
+    if ( ok && (Scaling - all_ones).SquareLength() > zero_epsilon ) {
         aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
         aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
     }
     }
 
 
@@ -644,18 +684,38 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
     }
     }
 
 
     const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
     const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
-    if ( ok && std::fabs( GeometricScaling.SquareLength() - 1.0f ) > zero_epsilon ) {
+    if ( ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon ) {
+        is_complex = true;
         aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
         aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
+        aiVector3D GeometricScalingInverse = GeometricScaling;
+        bool canscale = true;
+        for (size_t i = 0; i < 3; ++i) {
+            if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) {
+                GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
+            } else {
+                FBXImporter::LogError( "cannot invert geometric scaling matrix with a 0.0 scale component" );
+                canscale = false;
+                break;
+            }
+        }
+        if (canscale) {
+            aiMatrix4x4::Scaling( GeometricScalingInverse, chain[ TransformationComp_GeometricScalingInverse ] );
+        }
     }
     }
 
 
     const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
     const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
     if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
     if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
+        is_complex = true;
         GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
         GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
+        GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] );
+        chain[ TransformationComp_GeometricRotationInverse ].Inverse();
     }
     }
 
 
     const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
     const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
     if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
     if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
+        is_complex = true;
         aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
         aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
+        aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] );
     }
     }
 
 
     // is_complex needs to be consistent with NeedsComplexTransformationChain()
     // is_complex needs to be consistent with NeedsComplexTransformationChain()
@@ -690,10 +750,18 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
             }
             }
 
 
             aiNode* nd = new aiNode();
             aiNode* nd = new aiNode();
-            output_nodes.push_back( nd );
-
             nd->mName.Set( NameTransformationChainNode( name, comp ) );
             nd->mName.Set( NameTransformationChainNode( name, comp ) );
             nd->mTransformation = chain[ i ];
             nd->mTransformation = chain[ i ];
+
+            // geometric inverses go in a post-node chain
+            if ( comp == TransformationComp_GeometricScalingInverse ||
+                 comp == TransformationComp_GeometricRotationInverse ||
+                 comp == TransformationComp_GeometricTranslationInverse
+            ) {
+                post_output_nodes.push_back( nd );
+            } else {
+                output_nodes.push_back( nd );
+            }
         }
         }
 
 
         ai_assert( output_nodes.size() );
         ai_assert( output_nodes.size() );
@@ -2209,8 +2277,7 @@ void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
 
 
             has_any = true;
             has_any = true;
 
 
-            if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation &&
-                comp != TransformationComp_GeometricScaling && comp != TransformationComp_GeometricRotation && comp != TransformationComp_GeometricTranslation )
+            if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation )
             {
             {
                 has_complex = true;
                 has_complex = true;
             }
             }

+ 5 - 2
code/FBXConverter.h

@@ -82,7 +82,10 @@ public:
     *  The different parts that make up the final local transformation of a fbx-node
     *  The different parts that make up the final local transformation of a fbx-node
     */
     */
     enum TransformationComp {
     enum TransformationComp {
-        TransformationComp_Translation = 0,
+        TransformationComp_GeometricScalingInverse = 0,
+        TransformationComp_GeometricRotationInverse,
+        TransformationComp_GeometricTranslationInverse,
+        TransformationComp_Translation,
         TransformationComp_RotationOffset,
         TransformationComp_RotationOffset,
         TransformationComp_RotationPivot,
         TransformationComp_RotationPivot,
         TransformationComp_PreRotation,
         TransformationComp_PreRotation,
@@ -153,7 +156,7 @@ private:
     /**
     /**
     *  note: memory for output_nodes will be managed by the caller
     *  note: memory for output_nodes will be managed by the caller
     */
     */
-    void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes);
+    void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     void SetupNodeMetadata(const Model& model, aiNode& nd);
     void SetupNodeMetadata(const Model& model, aiNode& nd);

+ 42 - 7
tools/assimp_cmd/Info.cpp

@@ -47,9 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "Main.h"
 #include "Main.h"
 
 
 const char* AICMD_MSG_INFO_HELP_E =
 const char* AICMD_MSG_INFO_HELP_E =
-"assimp info <file> [-r]\n"
+"assimp info <file> [-r] [-v]\n"
 "\tPrint basic structure of a 3D model\n"
 "\tPrint basic structure of a 3D model\n"
-"\t-r,--raw: No postprocessing, do a raw import\n";
+"\t-r,--raw: No postprocessing, do a raw import\n"
+"\t-v,--verbose: Print verbose info such as node transform data\n";
 
 
 
 
 // -----------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------
@@ -184,7 +185,7 @@ std::string FindPTypes(const aiScene* scene)
 
 
 // -----------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------
 void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxline,
 void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxline,
-					unsigned int cline, unsigned int cnest=0)
+					unsigned int cline, bool verbose, unsigned int cnest=0)
 {
 {
 	if (cline++ >= maxline || cnest >= maxnest) {
 	if (cline++ >= maxline || cnest >= maxnest) {
 		return;
 		return;
@@ -194,8 +195,29 @@ void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxli
 		printf("-- ");
 		printf("-- ");
 	}
 	}
 	printf("\'%s\', meshes: %u\n",root->mName.data,root->mNumMeshes);
 	printf("\'%s\', meshes: %u\n",root->mName.data,root->mNumMeshes);
+
+	if (verbose) {
+		// print the actual transform
+		//printf(",");
+		aiVector3D s, r, t;
+		root->mTransformation.Decompose(s, r, t);
+		if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
+			for(unsigned int i = 0; i < cnest; ++i) { printf("   "); }
+			printf("      S:[%f %f %f]\n", s.x, s.y, s.z);
+		}
+		if (r.x || r.y || r.z) {
+			for(unsigned int i = 0; i < cnest; ++i) { printf("   "); }
+			printf("      R:[%f %f %f]\n", r.x, r.y, r.z);
+		}
+		if (t.x || t.y || t.z) {
+			for(unsigned int i = 0; i < cnest; ++i) { printf("   "); }
+			printf("      T:[%f %f %f]\n", t.x, t.y, t.z);
+		}
+	}
+	//printf("\n");
+
 	for (unsigned int i = 0; i < root->mNumChildren; ++i ) {
 	for (unsigned int i = 0; i < root->mNumChildren; ++i ) {
-		PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,cnest+1);
+		PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,verbose,cnest+1);
 		if(i == root->mNumChildren-1) {
 		if(i == root->mNumChildren-1) {
 			for(unsigned int i = 0; i < cnest; ++i) {
 			for(unsigned int i = 0; i < cnest; ++i) {
 				printf("   ");
 				printf("   ");
@@ -230,10 +252,23 @@ int Assimp_Info (const char* const* params, unsigned int num)
 
 
 	const std::string in  = std::string(params[0]);
 	const std::string in  = std::string(params[0]);
 
 
+	// get -r and -v arguments
+	bool raw = false;
+	bool verbose = false;
+	for(unsigned int i = 1; i < num; ++i) {
+		if (!strcmp(params[i],"--raw")||!strcmp(params[i],"-r")) {
+			raw = true;
+		}
+		if (!strcmp(params[i],"--verbose")||!strcmp(params[i],"-v")) {
+			verbose = true;
+		}
+	}
+
 	// do maximum post-processing unless -r was specified
 	// do maximum post-processing unless -r was specified
 	ImportData import;
 	ImportData import;
-	import.ppFlags = num>1&&(!strcmp(params[1],"--raw")||!strcmp(params[1],"-r")) ? 0
-		: aiProcessPreset_TargetRealtime_MaxQuality;
+	if (!raw) {
+		import.ppFlags = aiProcessPreset_TargetRealtime_MaxQuality;
+	}
 
 
 	// import the main model
 	// import the main model
 	const aiScene* scene = ImportModel(import,in);
 	const aiScene* scene = ImportModel(import,in);
@@ -346,7 +381,7 @@ int Assimp_Info (const char* const* params, unsigned int num)
 
 
 	printf("\nNode hierarchy:\n");
 	printf("\nNode hierarchy:\n");
 	unsigned int cline=0;
 	unsigned int cline=0;
-	PrintHierarchy(scene->mRootNode,20,1000,cline);
+	PrintHierarchy(scene->mRootNode,20,1000,cline,verbose);
 
 
 	printf("\n");
 	printf("\n");
 	return 0;
 	return 0;