From 6d3c8b3bc778d456f64b846b785e1897067733ef Mon Sep 17 00:00:00 2001 From: ulfjorensen Date: Sun, 10 Jan 2010 10:38:52 +0000 Subject: [PATCH] Bugfix: Collada loader now translates bone names to proper node names so that users should be able to associate the correct nodes to bones, equal what addressing scheme was used in the Collada file git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@526 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/ColladaHelper.h | 1 + code/ColladaLoader.cpp | 75 +++++++++++++++++++++++++++++++----------- code/ColladaLoader.h | 7 +++- code/ColladaParser.cpp | 7 ++-- 4 files changed, 68 insertions(+), 22 deletions(-) diff --git a/code/ColladaHelper.h b/code/ColladaHelper.h index a0e47a8f2..a43a7b0e0 100644 --- a/code/ColladaHelper.h +++ b/code/ColladaHelper.h @@ -225,6 +225,7 @@ struct Node { std::string mName; std::string mID; + std::string mSID; Node* mParent; std::vector mChildren; diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index 9e9a98e62..669b37ffd 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -178,23 +178,9 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla // create a node for it aiNode* node = new aiNode(); - // now setup the name of the node. We take the name if not empty, otherwise the collada ID - // FIX: Workaround for XSI calling the instanced visual scene 'untitled' by default. - if (!pNode->mName.empty() && pNode->mName != "untitled") - node->mName.Set(pNode->mName); - else if (!pNode->mID.empty()) - node->mName.Set(pNode->mID); - else - { - // No need to worry. Unnamed nodes are no problem at all, except - // if cameras or lights need to be assigned to them. - if (!pNode->mLights.empty() || !pNode->mCameras.empty()) { - - ::strcpy(node->mName.data,"$ColladaAutoName$_"); - node->mName.length = 17 + ASSIMP_itoa10(node->mName.data+18,MAXLEN-18,(uint32_t)clock()); - } - } - + // find a name for the new node. It's more complicated than you might think + node->mName.Set( FindNameForNode( pNode)); + // calculate the transformation matrix for it node->mTransformation = pParser.CalculateResultTransform( pNode->mTransforms); @@ -690,7 +676,21 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: bone->mWeights = new aiVertexWeight[bone->mNumWeights]; std::copy( dstBones[a].begin(), dstBones[a].end(), bone->mWeights); - // and insert bone + // HACK: (thom) Some exporters address the bone nodes by SID, others address them by ID or even name. + // Therefore I added a little name replacement here: I search for the bone's node by either name, ID or SID, + // and replace the bone's name by the node's name so that the user can use the standard + // find-by-name method to associate nodes with bones. + const Collada::Node* bnode = FindNode( pParser.mRootNode, bone->mName.data); + if( !bnode) + bnode = FindNodeBySID( pParser.mRootNode, bone->mName.data); + + // assign the name that we would have assigned for the source node + if( bnode) + bone->mName.Set( FindNameForNode( bnode)); + else + DefaultLogger::get()->warn( boost::str( boost::format( "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"%s\".") % bone->mName.data)); + + // and insert bone dstMesh->mBones[boneCount++] = bone; } } @@ -1351,7 +1351,7 @@ void ColladaLoader::CollectNodes( const aiNode* pNode, std::vectormName == pName || pNode->mID == pName) return pNode; @@ -1366,4 +1366,41 @@ const Collada::Node* ColladaLoader::FindNode( const Collada::Node* pNode, const return NULL; } +// ------------------------------------------------------------------------------------------------ +// Finds a node in the collada scene by the given SID +const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const +{ + if( pNode->mSID == pSID) + return pNode; + + for( size_t a = 0; a < pNode->mChildren.size(); ++a) + { + const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID); + if( node) + return node; + } + + return NULL; +} + +// ------------------------------------------------------------------------------------------------ +// Finds a proper name for a node derived from the collada-node's properties +std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode) const +{ + // now setup the name of the node. We take the name if not empty, otherwise the collada ID + // FIX: Workaround for XSI calling the instanced visual scene 'untitled' by default. + if (!pNode->mName.empty() && pNode->mName != "untitled") + return pNode->mName; + else if (!pNode->mID.empty()) + return pNode->mID; + else if (!pNode->mSID.empty()) + return pNode->mSID; + else + { + // No need to worry. Unnamed nodes are no problem at all, except + // if cameras or lights need to be assigned to them. + return boost::str( boost::format( "$ColladaAutoName$_%d") % clock()); + } +} + #endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER diff --git a/code/ColladaLoader.h b/code/ColladaLoader.h index 5cf7713c6..10c7754c8 100644 --- a/code/ColladaLoader.h +++ b/code/ColladaLoader.h @@ -200,7 +200,12 @@ protected: void CollectNodes( const aiNode* pNode, std::vector& poNodes) const; /** Finds a node in the collada scene by the given name */ - const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName); + const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const; + /** Finds a node in the collada scene by the given SID */ + const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const; + + /** Finds a proper name for a node derived from the collada-node's properties */ + std::string FindNameForNode( const Collada::Node* pNode) const; protected: /** Filename, for a verbose error message */ diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index 1638c200c..9080fa233 100644 --- a/code/ColladaParser.cpp +++ b/code/ColladaParser.cpp @@ -1705,8 +1705,8 @@ void ColladaParser::ReadAccessor( const std::string& pID) /* Generic extra data, interpreted as UV data, too*/ else if( name == "U") acc.mSubOffset[0] = acc.mParams.size(); else if( name == "V") acc.mSubOffset[1] = acc.mParams.size(); - else - DefaultLogger::get()->warn( boost::str( boost::format( "Unknown accessor parameter \"%s\". Ignoring data channel.") % name)); + //else + // DefaultLogger::get()->warn( boost::str( boost::format( "Unknown accessor parameter \"%s\". Ignoring data channel.") % name)); } acc.mParams.push_back( name); @@ -2216,6 +2216,9 @@ void ColladaParser::ReadSceneNode( Node* pNode) int attrID = TestAttribute( "id"); if( attrID > -1) child->mID = mReader->getAttributeValue( attrID); + int attrSID = TestAttribute( "sid"); + if( attrSID > -1) + child->mSID = mReader->getAttributeValue( attrSID); int attrName = TestAttribute( "name"); if( attrName > -1)