From 78dd81a8b4ffcd2e92125eb04d448c7d1c13647b Mon Sep 17 00:00:00 2001 From: Julien Valentin Date: Fri, 1 Sep 2017 17:48:28 +0200 Subject: [PATCH] add void InfluenceMap::removeUnexpressedBones(Skeleton &skel) const; a bit experimental but work well without further process on my test set --- include/osgAnimation/VertexInfluence | 5 + src/osgAnimation/VertexInfluence.cpp | 147 +++++++++++++++++++++++---- 2 files changed, 132 insertions(+), 20 deletions(-) diff --git a/include/osgAnimation/VertexInfluence b/include/osgAnimation/VertexInfluence index 2ddd39ebe..eb2956b72 100644 --- a/include/osgAnimation/VertexInfluence +++ b/include/osgAnimation/VertexInfluence @@ -24,6 +24,8 @@ namespace osgAnimation { + class Skeleton; + // first is bonename, and second the weight typedef std::pair BoneWeight; // first is vertex index, and second the weight @@ -77,6 +79,9 @@ namespace osgAnimation /// compute the minimal VertexGroup Set in which vertices shares the same influence set void computeMinimalVertexGroupList(std::vector&uniqVertexGroupList, unsigned int numvert)const; + + //Experimental removal of unexpressed bone from the skeleton + void removeUnexpressedBones(Skeleton &skel) const; }; } diff --git a/src/osgAnimation/VertexInfluence.cpp b/src/osgAnimation/VertexInfluence.cpp index 3c2c50c42..2548d6ed9 100644 --- a/src/osgAnimation/VertexInfluence.cpp +++ b/src/osgAnimation/VertexInfluence.cpp @@ -14,6 +14,8 @@ */ #include +#include +#include #include #include #include @@ -31,14 +33,17 @@ struct invweight_ordered } }; -void VertexInfluenceMap::normalize(unsigned int numvert) { +void VertexInfluenceMap::normalize(unsigned int numvert) +{ typedef std::pair > PerVertWeights; std::vector localstore; localstore.resize(numvert); - for(VertexInfluenceMap::iterator mapit=this->begin(); mapit!=this->end(); ++mapit) { + for(VertexInfluenceMap::iterator mapit=this->begin(); mapit!=this->end(); ++mapit) + { IndexWeightList &curvecinf=mapit->second; - for(IndexWeightList::iterator curinf=curvecinf.begin(); curinf!=curvecinf.end(); ++curinf) { + for(IndexWeightList::iterator curinf=curvecinf.begin(); curinf!=curvecinf.end(); ++curinf) + { VertexIndexWeight& inf=*curinf; localstore[inf.first].first+=inf.second; localstore[inf.first].second.push_back(&inf.second); @@ -46,7 +51,8 @@ void VertexInfluenceMap::normalize(unsigned int numvert) { } } unsigned int vertid=0; - for(std::vector::iterator itvert=localstore.begin(); itvert!=localstore.end(); ++itvert, ++vertid) { + for(std::vector::iterator itvert=localstore.begin(); itvert!=localstore.end(); ++itvert, ++vertid) + { PerVertWeights & weights=*itvert; if(weights.first< 1e-4) { @@ -62,41 +68,51 @@ void VertexInfluenceMap::normalize(unsigned int numvert) { } ///remove weakest influences in order to fit targetted numbonepervertex -void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize) { +void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize) +{ - typedef std::set BoneWeightOrdered; - std::map tempVec2Bones; + typedef std::set BoneWeightOrdered; + std::map tempVec2Bones; for(VertexInfluenceMap::iterator mapit=this->begin(); mapit!=this->end(); ++mapit) { const std::string& bonename=mapit->first; IndexWeightList &curvecinf=mapit->second; - for(IndexWeightList::iterator curinf=curvecinf.begin(); curinf!=curvecinf.end(); ++curinf) { + for(IndexWeightList::iterator curinf=curvecinf.begin(); curinf!=curvecinf.end(); ++curinf) + { VertexIndexWeight& inf=*curinf; - if( bonename.empty()) { + if( bonename.empty()) + { OSG_WARN << "VertexInfluenceSet::cullInfluenceCountPerVertex warning vertex " << inf.first << " is not assigned to a bone" << std::endl; } else if(inf.second>minweight)tempVec2Bones[inf.first].insert(BoneWeight(bonename, inf.second)); } } this->clear(); - for( std::map::iterator mapit=tempVec2Bones.begin(); mapit!=tempVec2Bones.end(); ++mapit) { + for( std::map::iterator mapit=tempVec2Bones.begin(); mapit!=tempVec2Bones.end(); ++mapit) + { BoneWeightOrdered& bwset=mapit->second; unsigned int newsize=numbonepervertexnewsize)bwset.erase(*bwset.rbegin()); - if(renormalize){ + if(renormalize) + { for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) sum+=bwit->second; - if(sum>1e-4){ + if(sum>1e-4) + { sum=1.0f/sum; - for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) { + for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) + { VertexInfluence & inf= (*this)[bwit->first]; inf.push_back(VertexIndexWeight(mapit->first, bwit->second*sum)); inf.setName(bwit->first); } } - }else{ - for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) { + } + else + { + for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) + { VertexInfluence & inf= (*this)[bwit->first]; inf.push_back(VertexIndexWeight(mapit->first,bwit->second)); inf.setName(bwit->first); @@ -108,13 +124,14 @@ void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervert void VertexInfluenceMap::computePerVertexInfluenceList(std::vector& vertex2Bones,unsigned int numvert)const { - vertex2Bones.resize(numvert); - for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); + vertex2Bones.resize(numvert); + for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); it != end(); ++it) { const IndexWeightList& inflist = it->second; - if (it->first.empty()) { + if (it->first.empty()) + { OSG_WARN << "VertexInfluenceMap::computePerVertexInfluenceList contains unamed bone IndexWeightList" << std::endl; } for(IndexWeightList::const_iterator infit=inflist.begin(); infit!=inflist.end(); ++infit) @@ -135,7 +152,7 @@ struct SortByNameAndWeight : public std::less { if (b0.first < b1.first) return true; - else if (b0.first> b1.first) + else if (b0.first > b1.first) return false; return (b0.second < b1.second); } @@ -182,7 +199,8 @@ void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector& unifyBuffer[boneweightlist].setBoneWeights(boneweightlist); unifyBuffer[boneweightlist].vertIDs().push_back(vertexID); } - if(vertex2Bones.size()==unifyBuffer.size()) { + if(vertex2Bones.size()==unifyBuffer.size()) + { OSG_WARN << "VertexInfluenceMap::computeMinimalVertexGroupList is useless no duplicate VertexGroup" << std::endl; } uniqVertexGroupList.reserve(unifyBuffer.size()); @@ -191,3 +209,92 @@ void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector& uniqVertexGroupList.push_back(it->second); } } + + +//Expermental +typedef std::vector RigList; +class CollectRigVisitor : public osg::NodeVisitor +{ +public: + META_NodeVisitor(osgAnimation, CollectRigVisitor) + CollectRigVisitor(); + + //void apply(osg::Node&); + void apply(osg::Geometry& node); + const RigList& getRigList() const; + +protected: + RigList _map; +}; +CollectRigVisitor::CollectRigVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + +//void CollectRigVisitor::apply(osg::Node&) { return; } +void CollectRigVisitor::apply(osg::Geometry& node) +{ + RigGeometry* bone = dynamic_cast(&node); + if (bone) + { + _map.push_back( bone); + traverse(node); + } + Skeleton* skeleton = dynamic_cast(&node); + if (skeleton) + traverse(node); +} + +const RigList& CollectRigVisitor::getRigList() const +{ + return _map; +} + +void VertexInfluenceMap::removeUnexpressedBones(Skeleton &skel) const +{ + BoneMapVisitor mapVisitor; + skel.accept(mapVisitor); + + CollectRigVisitor rigvis; + skel.accept(rigvis); + + RigList rigs=rigvis.getRigList(); + BoneMap boneMap = mapVisitor.getBoneMap(); + Bone* child,*par; + + for(BoneMap::iterator bmit=boneMap.begin(); bmit!=boneMap.end();) + { + if( this->find(bmit->first) == this->end()) + { + bool isusless=true; + for(RigList::iterator rigit=rigs.begin(); rigit != rigs.end(); ++rigit) + { + if( ((*rigit)->getInfluenceMap()->find(bmit->first) !=(*rigit)->getInfluenceMap()->end())) + { + isusless=false; + break; + } + } + if(!isusless||!(par=bmit->second->getBoneParent())) + { + ++bmit; + continue; + } + + ///Bone can be removed + Bone * bone2rm=bmit->second; + for(unsigned int numchild=0; numchildgetNumChildren(); numchild++) + { + if( (child = dynamic_cast(bone2rm->getChild(numchild))) ) + { + par->addChild(child); + bone2rm->removeChild(child); + } + } + par->removeChild(bone2rm); + ///rebuild bonemap after bone removal + skel.accept(mapVisitor); + boneMap = mapVisitor.getBoneMap(); + bmit=boneMap.begin(); + } + else ++bmit; + } + +}