diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 6929e5c33..746777d65 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -142,6 +142,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa nodes.reserve( conns.size() ); std::vector nodes_chain; + std::vector post_nodes_chain; try { for( const Connection* con : conns ) { @@ -161,6 +162,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa if ( model ) { nodes_chain.clear(); + post_nodes_chain.clear(); 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 // is employed by fbx) means that we may need multiple aiNode's // to represent a fbx node's transformation. - GenerateTransformationNodeChain( *model, nodes_chain ); + GenerateTransformationNodeChain( *model, nodes_chain, post_nodes_chain ); ai_assert( nodes_chain.size() ); @@ -213,8 +215,25 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa // attach geometry 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 - ConvertNodes( model->ID(), *nodes_chain.back(), new_abs_transform ); + ConvertNodes( model->ID(), *last_parent, new_abs_transform ); if ( doc.Settings().readLights ) { ConvertLights( *model ); @@ -396,6 +415,12 @@ const char* Converter::NameTransformationComp( TransformationComp comp ) return "GeometricRotation"; case TransformationComp_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 default: break; @@ -437,6 +462,12 @@ const char* Converter::NameTransformationCompProperty( TransformationComp comp ) return "GeometricRotation"; case TransformationComp_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 break; } @@ -548,17 +579,25 @@ bool Converter::NeedsComplexTransformationChain( const Model& model ) bool ok; 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 ) { 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; } + bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling ); + const aiVector3D& v = PropertyGet( 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 ); } -void Converter::GenerateTransformationNodeChain( const Model& model, std::vector& output_nodes ) +void Converter::GenerateTransformationNodeChain( const Model& model, std::vector& output_nodes, std::vector& post_output_nodes ) { const PropertyTable& props = model.Props(); 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 const float zero_epsilon = 1e-6f; + const aiVector3D all_ones(1.0f, 1.0f, 1.0f); bool is_complex = false; const aiVector3D& PreRotation = PropertyGet( props, "PreRotation", ok ); @@ -634,7 +674,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector } const aiVector3D& Scaling = PropertyGet( 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 ] ); } @@ -644,18 +684,38 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector } const aiVector3D& GeometricScaling = PropertyGet( 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 ] ); + 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( props, "GeometricRotation", ok ); if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) { + is_complex = true; GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] ); + GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] ); + chain[ TransformationComp_GeometricRotationInverse ].Inverse(); } const aiVector3D& GeometricTranslation = PropertyGet( props, "GeometricTranslation", ok ); if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) { + is_complex = true; aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] ); + aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] ); } // is_complex needs to be consistent with NeedsComplexTransformationChain() @@ -690,10 +750,18 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector } aiNode* nd = new aiNode(); - output_nodes.push_back( nd ); - nd->mName.Set( NameTransformationChainNode( name, comp ) ); 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() ); @@ -2209,8 +2277,7 @@ void Converter::GenerateNodeAnimations( std::vector& node_anims, 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; } diff --git a/code/FBXConverter.h b/code/FBXConverter.h index c882e9326..06a6f07a7 100644 --- a/code/FBXConverter.h +++ b/code/FBXConverter.h @@ -82,7 +82,10 @@ public: * The different parts that make up the final local transformation of a fbx-node */ enum TransformationComp { - TransformationComp_Translation = 0, + TransformationComp_GeometricScalingInverse = 0, + TransformationComp_GeometricRotationInverse, + TransformationComp_GeometricTranslationInverse, + TransformationComp_Translation, TransformationComp_RotationOffset, TransformationComp_RotationPivot, TransformationComp_PreRotation, @@ -153,7 +156,7 @@ private: /** * note: memory for output_nodes will be managed by the caller */ - void GenerateTransformationNodeChain(const Model& model, std::vector& output_nodes); + void GenerateTransformationNodeChain(const Model& model, std::vector& output_nodes, std::vector& post_output_nodes); // ------------------------------------------------------------------------------------------------ void SetupNodeMetadata(const Model& model, aiNode& nd); diff --git a/tools/assimp_cmd/Info.cpp b/tools/assimp_cmd/Info.cpp index e19746db6..a9f66eb1f 100644 --- a/tools/assimp_cmd/Info.cpp +++ b/tools/assimp_cmd/Info.cpp @@ -47,9 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Main.h" const char* AICMD_MSG_INFO_HELP_E = -"assimp info [-r]\n" +"assimp info [-r] [-v]\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, - unsigned int cline, unsigned int cnest=0) + unsigned int cline, bool verbose, unsigned int cnest=0) { if (cline++ >= maxline || cnest >= maxnest) { return; @@ -194,8 +195,29 @@ void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxli printf("-- "); } 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 ) { - PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,cnest+1); + PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,verbose,cnest+1); if(i == root->mNumChildren-1) { for(unsigned int i = 0; i < cnest; ++i) { printf(" "); @@ -230,10 +252,23 @@ int Assimp_Info (const char* const* params, unsigned int num) 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 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 const aiScene* scene = ImportModel(import,in); @@ -346,7 +381,7 @@ int Assimp_Info (const char* const* params, unsigned int num) printf("\nNode hierarchy:\n"); unsigned int cline=0; - PrintHierarchy(scene->mRootNode,20,1000,cline); + PrintHierarchy(scene->mRootNode,20,1000,cline,verbose); printf("\n"); return 0;