diff --git a/examples/osganimationhardware/osganimationhardware.cpp b/examples/osganimationhardware/osganimationhardware.cpp index 74aacb7ba..acc2bf2f8 100644 --- a/examples/osganimationhardware/osganimationhardware.cpp +++ b/examples/osganimationhardware/osganimationhardware.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -40,89 +42,126 @@ static unsigned int getRandomValueinRange(unsigned int v) } -osg::ref_ptr program; +//osg::ref_ptr program; // show how to override the default RigTransformHardware for customized usage struct MyRigTransformHardware : public osgAnimation::RigTransformHardware { - void operator()(osgAnimation::RigGeometry& geom) + virtual bool init(osgAnimation::RigGeometry& rig) { - if (_needInit) - if (!init(geom)) - return; - computeMatrixPaletteUniform(geom.getMatrixFromSkeletonToGeometry(), geom.getInvMatrixFromSkeletonToGeometry()); - } + if(!rig.getSkeleton() && !rig.getParents().empty()) + { + osgAnimation::RigGeometry::FindNearestParentSkeleton finder; + if(rig.getParents().size() > 1) + osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << rig.getName() << " )" << std::endl; + rig.getParents()[0]->accept(finder); - bool init(osgAnimation::RigGeometry& geom) - { - osg::Vec3Array* pos = dynamic_cast(geom.getVertexArray()); - if (!pos) { - osg::notify(osg::WARN) << "RigTransformHardware no vertex array in the geometry " << geom.getName() << std::endl; - return false; - } - - if (!geom.getSkeleton()) { - osg::notify(osg::WARN) << "RigTransformHardware no skeleting set in geometry " << geom.getName() << std::endl; - return false; - } - - osgAnimation::BoneMapVisitor mapVisitor; - geom.getSkeleton()->accept(mapVisitor); - osgAnimation::BoneMap bm = mapVisitor.getBoneMap(); - - if (!createPalette(pos->size(),bm, geom.getVertexInfluenceSet().getVertexToBoneList())) - return false; - - int attribIndex = 11; - int nbAttribs = getNumVertexAttrib(); - - // use a global program for all avatar - if (!program.valid()) { - program = new osg::Program; - program->setName("HardwareSkinning"); - if (!_shader.valid()) - _shader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"shaders/skinning.vert"); - - if (!_shader.valid()) { - osg::notify(osg::WARN) << "RigTransformHardware can't load VertexShader" << std::endl; + if(!finder._root.valid()) + { + osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << rig.getName() << " )" << std::endl; return false; } + rig.setSkeleton(finder._root.get()); + } + osgAnimation::BoneMapVisitor mapVisitor; + rig.getSkeleton()->accept(mapVisitor); + osgAnimation::BoneMap boneMap = mapVisitor.getBoneMap(); - // replace max matrix by the value from uniform + if (!buildPalette(boneMap,rig) ) + return false; + + osg::Geometry& source = *rig.getSourceGeometry(); + osg::Vec3Array* positionSrc = dynamic_cast(source.getVertexArray()); + if (!positionSrc) + { + OSG_WARN << "RigTransformHardware no vertex array in the geometry " << rig.getName() << std::endl; + return false; + } + + // copy shallow from source geometry to rig + rig.copyFrom(source); + + osg::ref_ptr program ; + osg::ref_ptr vertexshader; + osg::ref_ptr stateset = rig.getOrCreateStateSet(); + + //grab geom source program and vertex shader if _shader is not setted + if(!_shader.valid() && (program = (osg::Program*)stateset->getAttribute(osg::StateAttribute::PROGRAM))) + { + for(unsigned int i=0; igetNumShaders(); ++i) + if(program->getShader(i)->getType()==osg::Shader::VERTEX) + { + vertexshader=program->getShader(i); + program->removeShader(vertexshader); + + } + } + else + { + program = new osg::Program; + program->setName("HardwareSkinning"); + } + //set default source if _shader is not user setted + if (!vertexshader.valid()) + { + if (!_shader.valid()) + vertexshader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"shaders/skinning.vert"); + else vertexshader=_shader; + } + + + if (!vertexshader.valid()) + { + OSG_WARN << "RigTransformHardware can't load VertexShader" << std::endl; + return false; + } + + // replace max matrix by the value from uniform + { + std::string str = vertexshader->getShaderSource(); + std::string toreplace = std::string("MAX_MATRIX"); + std::size_t start = str.find(toreplace); + if (std::string::npos != start) { - std::string str = _shader->getShaderSource(); - std::string toreplace = std::string("MAX_MATRIX"); - std::size_t start = str.find(toreplace); std::stringstream ss; ss << getMatrixPaletteUniform()->getNumElements(); str.replace(start, toreplace.size(), ss.str()); - _shader->setShaderSource(str); - osg::notify(osg::INFO) << "Shader " << str << std::endl; + vertexshader->setShaderSource(str); } - - program->addShader(_shader.get()); - - for (int i = 0; i < nbAttribs; i++) + else { - std::stringstream ss; - ss << "boneWeight" << i; - program->addBindAttribLocation(ss.str(), attribIndex + i); - - osg::notify(osg::INFO) << "set vertex attrib " << ss.str() << std::endl; + OSG_INFO<< "MAX_MATRIX not found in Shader! " << str << std::endl; } + OSG_INFO << "Shader " << str << std::endl; } - for (int i = 0; i < nbAttribs; i++) + + unsigned int attribIndex = 11; + unsigned int nbAttribs = getNumVertexAttrib(); + if(nbAttribs==0) + OSG_WARN << "nbAttribs== " << nbAttribs << std::endl; + for (unsigned int i = 0; i < nbAttribs; i++) { std::stringstream ss; ss << "boneWeight" << i; - geom.setVertexAttribArray(attribIndex + i, getVertexAttrib(i)); + program->addBindAttribLocation(ss.str(), attribIndex + i); + + if(getVertexAttrib(i)->getNumElements()!=_nbVertexes) + OSG_WARN << "getVertexAttrib== " << getVertexAttrib(i)->getNumElements() << std::endl; + rig.setVertexAttribArray(attribIndex + i, getVertexAttrib(i)); + OSG_INFO << "set vertex attrib " << ss.str() << std::endl; } - osg::ref_ptr ss = new osg::StateSet; - ss->addUniform(getMatrixPaletteUniform()); - ss->addUniform(new osg::Uniform("nbBonesPerVertex", getNumBonesPerVertex())); - ss->setAttributeAndModes(program.get()); - geom.setStateSet(ss.get()); + + program->addShader(vertexshader.get()); + stateset->removeUniform("nbBonesPerVertex"); + stateset->addUniform(new osg::Uniform("nbBonesPerVertex",_bonesPerVertex)); + stateset->removeUniform("matrixPalette"); + stateset->addUniform(getMatrixPaletteUniform()); + + stateset->removeAttribute(osg::StateAttribute::PROGRAM); + if(!stateset->getAttribute(osg::StateAttribute::PROGRAM)) + stateset->setAttributeAndModes(program.get()); + _needInit = false; return true; } @@ -142,10 +181,14 @@ struct SetupRigGeometry : public osg::NodeVisitor } void apply(osg::Drawable& geom) { - if (_hardware) { + if (_hardware) + { osgAnimation::RigGeometry* rig = dynamic_cast(&geom); - if (rig) - rig->setRigTransformImplementation(new osgAnimation::RigTransformHardware); + if (rig){ + rig->setRigTransformImplementation(new MyRigTransformHardware); + osgAnimation::MorphGeometry *morph=dynamic_cast(rig->getSourceGeometry()); + if(morph)morph->setMorphTransformImplementation(new osgAnimation::MorphTransformHardware); + } } #if 0 @@ -169,7 +212,8 @@ osg::Group* createCharacterInstance(osg::Group* character, bool hardware) osgAnimation::BasicAnimationManager* anim = dynamic_cast(animationManager); const osgAnimation::AnimationList& list = animationManager->getAnimationList(); int v = getRandomValueinRange(list.size()); - if (list[v]->getName() == std::string("MatIpo_ipo")) { + if (list[v]->getName() == std::string("MatIpo_ipo")) + { anim->playAnimation(list[v].get()); v = (v + 1)%list.size(); } @@ -193,7 +237,10 @@ int main (int argc, char* argv[]) bool hardware = true; int maxChar = 10; - while (psr.read("--software")) { hardware = false; } + while (psr.read("--software")) + { + hardware = false; + } while (psr.read("--number", maxChar)) {} osg::ref_ptr node = osgDB::readRefNodeFiles(psr); @@ -243,8 +290,10 @@ int main (int argc, char* argv[]) double xChar = maxChar; double yChar = xChar * 9.0/16; - for (double i = 0.0; i < xChar; i++) { - for (double j = 0.0; j < yChar; j++) { + for (double i = 0.0; i < xChar; i++) + { + for (double j = 0.0; j < yChar; j++) + { osg::ref_ptr c = createCharacterInstance(root.get(), hardware); osg::MatrixTransform* tr = new osg::MatrixTransform; diff --git a/examples/osganimationskinning/osganimationskinning.cpp b/examples/osganimationskinning/osganimationskinning.cpp index bbf4614fb..2536353a6 100644 --- a/examples/osganimationskinning/osganimationskinning.cpp +++ b/examples/osganimationskinning/osganimationskinning.cpp @@ -134,23 +134,20 @@ void initVertexMap(osgAnimation::Bone* b0, osgAnimation::RigGeometry* geom, osg::Vec3Array* array) { - osgAnimation::VertexInfluenceSet vertexesInfluences; osgAnimation::VertexInfluenceMap* vim = new osgAnimation::VertexInfluenceMap; - (*vim)[b0->getName()].setName(b0->getName()); (*vim)[b1->getName()].setName(b1->getName()); (*vim)[b2->getName()].setName(b2->getName()); - for (int i = 0; i < (int)array->size(); i++) { float val = (*array)[i][0]; std::cout << val << std::endl; if (val >= -1.0f && val <= 0.0f) - (*vim)[b0->getName()].push_back(osgAnimation::IndexWeight(i,1.0f)); + (*vim)[b0->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f)); else if ( val > 0.0f && val <= 1.0f) - (*vim)[b1->getName()].push_back(osgAnimation::IndexWeight(i,1.0f)); + (*vim)[b1->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f)); else if ( val > 1.0f) - (*vim)[b2->getName()].push_back(osgAnimation::IndexWeight(i,1.0f)); + (*vim)[b2->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f)); } geom->setInfluenceMap(vim); diff --git a/include/osgAnimation/MorphGeometry b/include/osgAnimation/MorphGeometry index a1ec3f697..cf4b06228 100644 --- a/include/osgAnimation/MorphGeometry +++ b/include/osgAnimation/MorphGeometry @@ -61,25 +61,25 @@ namespace osgAnimation virtual const char* className() const { return "MorphGeometry"; } // set implementation of rig method - void setMorphTransformImplementation(MorphTransform*); - MorphTransform* getMorphTransformImplementation(); - const MorphTransform* getMorphTransformImplementation() const { return _rigTransformImplementation.get(); } + inline void setMorphTransformImplementation(MorphTransform*mt) { _morphTransformImplementation=mt; } + inline MorphTransform* getMorphTransformImplementation() { return _morphTransformImplementation.get(); } + inline const MorphTransform* getMorphTransformImplementation() const { return _morphTransformImplementation.get(); } /** Set the morphing method. */ - void setMethod(Method method) { _method = method; } + inline void setMethod(Method method) { _method = method; } /** Get the morphing method. */ inline Method getMethod() const { return _method; } /** Set flag for morphing normals. */ - void setMorphNormals(bool morphNormals) { _morphNormals = morphNormals; } + inline void setMorphNormals(bool morphNormals) { _morphNormals = morphNormals; } /** Get the flag for morphing normals. */ inline bool getMorphNormals() const { return _morphNormals; } /** Get the list of MorphTargets.*/ - const MorphTargetList& getMorphTargetList() const { return _morphTargets; } + inline const MorphTargetList& getMorphTargetList() const { return _morphTargets; } /** Get the list of MorphTargets. Warning if you modify this array you will have to call dirty() */ - MorphTargetList& getMorphTargetList() { return _morphTargets; } + inline MorphTargetList& getMorphTargetList() { return _morphTargets; } /** Return the \c MorphTarget at position \c i.*/ inline const MorphTarget& getMorphTarget( unsigned int i ) const { return _morphTargets[i]; } @@ -130,7 +130,7 @@ namespace osgAnimation } /** update a morph target at index setting its current weight to morphWeight */ - void setWeight(unsigned int index, float morphWeight) + inline void setWeight(unsigned int index, float morphWeight) { if (index < _morphTargets.size()) { @@ -144,10 +144,10 @@ namespace osgAnimation inline bool isDirty()const { return _dirty; } /** for retrocompatibility */ - virtual void transformSoftwareMethod(){ if (!_rigTransformImplementation.valid())_rigTransformImplementation = new MorphTransformSoftware();(*_rigTransformImplementation.get())(*this);} + void transformSoftwareMethod(){(*_morphTransformImplementation.get())(*this);} protected: - osg::ref_ptr _rigTransformImplementation; + osg::ref_ptr _morphTransformImplementation; /// Do we need to recalculate the morphed geometry? bool _dirty; diff --git a/include/osgAnimation/MorphTransformHardware b/include/osgAnimation/MorphTransformHardware index e75114a74..b061cccae 100644 --- a/include/osgAnimation/MorphTransformHardware +++ b/include/osgAnimation/MorphTransformHardware @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2009 Cedric Pinson + * Copyright (C) 2017 Julien Valentin * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -37,13 +37,14 @@ namespace osgAnimation META_Object(osgAnimation,MorphTransformHardware); - - - virtual void operator()(MorphGeometry&); - void setShader(osg::Shader*); + inline void setShader(osg::Shader*s){_shader=s;} + inline osg::Shader * getShader()const{return _shader;} + ///texture unit reserved for morphtarget TBO default is 7 + void setReservedTextureUnit(unsigned int t){_reservedTextureUnit=t;} + unsigned int getReservedTextureUnit() const {return _reservedTextureUnit;} protected: @@ -54,6 +55,7 @@ namespace osgAnimation osg::ref_ptr _shader; bool _needInit; + unsigned int _reservedTextureUnit; }; } diff --git a/include/osgAnimation/MorphTransformSoftware b/include/osgAnimation/MorphTransformSoftware index 8ac451b38..1130cdedc 100644 --- a/include/osgAnimation/MorphTransformSoftware +++ b/include/osgAnimation/MorphTransformSoftware @@ -36,6 +36,7 @@ namespace osgAnimation bool init(MorphGeometry&); virtual void operator()(MorphGeometry&); + protected: bool _needInit; diff --git a/include/osgAnimation/RigGeometry b/include/osgAnimation/RigGeometry index 31cda0179..805e9c779 100644 --- a/include/osgAnimation/RigGeometry +++ b/include/osgAnimation/RigGeometry @@ -69,14 +69,8 @@ namespace osgAnimation void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;} bool getNeedToComputeMatrix() const { return _needToComputeMatrix;} - - // this build the internal database about vertex influence and bones - void buildVertexInfluenceSet(); - inline const VertexInfluenceSet& getVertexInfluenceSet() const { return _vertexInfluenceSet;} - void computeMatrixFromRootSkeleton(); - // set implementation of rig method inline RigTransform* getRigTransformImplementation() { return _rigTransformImplementation.get(); } inline void setRigTransformImplementation(RigTransform* rig) { _rigTransformImplementation = rig; } @@ -84,10 +78,11 @@ namespace osgAnimation void update(); + void buildVertexInfluenceSet(){_rigTransformImplementation->prepareData(*this);} + const osg::Matrix& getMatrixFromSkeletonToGeometry() const; const osg::Matrix& getInvMatrixFromSkeletonToGeometry() const; - inline osg::Geometry* getSourceGeometry() { return _geometry.get(); } inline const osg::Geometry* getSourceGeometry() const { return _geometry.get(); } inline void setSourceGeometry(osg::Geometry* geometry) { _geometry = geometry; } @@ -112,7 +107,6 @@ namespace osgAnimation osg::ref_ptr _geometry; osg::ref_ptr _rigTransformImplementation; - VertexInfluenceSet _vertexInfluenceSet; osg::ref_ptr _vertexInfluenceMap; osg::Matrix _matrixFromSkeletonToGeometry; @@ -151,8 +145,9 @@ namespace osgAnimation osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )" << std::endl; return; } - geom->buildVertexInfluenceSet(); geom->setSkeleton(finder._root.get()); + + geom->getRigTransformImplementation()->prepareData(*geom); } if(!geom->getSkeleton()) diff --git a/include/osgAnimation/RigTransform b/include/osgAnimation/RigTransform index 7be592035..9a6a0e367 100644 --- a/include/osgAnimation/RigTransform +++ b/include/osgAnimation/RigTransform @@ -35,7 +35,7 @@ namespace osgAnimation /// to call manually when a skeleton is reacheable from the rig /// in order to prepare technic data before rendering - virtual bool prepareData(RigGeometry&){} + virtual bool prepareData(RigGeometry&){return true;} protected: virtual ~RigTransform() {} diff --git a/include/osgAnimation/RigTransformHardware b/include/osgAnimation/RigTransformHardware index 28330e87e..5469fb299 100644 --- a/include/osgAnimation/RigTransformHardware +++ b/include/osgAnimation/RigTransformHardware @@ -1,5 +1,6 @@ /* -*-c++-*- * Copyright (C) 2009 Cedric Pinson + * Copyright (C) 2017 Julien Valentin * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -37,48 +38,38 @@ namespace osgAnimation META_Object(osgAnimation,RigTransformHardware); - typedef osg::Matrix MatrixType; typedef std::vector > BoneWeightAttribList; typedef std::vector > BonePalette; typedef std::map BoneNamePaletteIndex; - typedef std::vector MatrixPalette; - struct IndexWeightEntry - { - IndexWeightEntry(unsigned int index=0, float weight=0.0f): _boneIndex(index), _boneWeight(weight){} - IndexWeightEntry(const IndexWeightEntry&o): _boneIndex(o._boneIndex), _boneWeight(o._boneWeight){} - bool operator <(const IndexWeightEntry &o)const{return (_boneIndex _shader; bool _needInit; + unsigned int _minAttribIndex; + bool buildPalette(const BoneMap& boneMap ,const RigGeometry& rig); + + //on first update + virtual bool init(RigGeometry& ); + }; } diff --git a/include/osgAnimation/RigTransformSoftware b/include/osgAnimation/RigTransformSoftware index 8492a215d..ac97f527a 100644 --- a/include/osgAnimation/RigTransformSoftware +++ b/include/osgAnimation/RigTransformSoftware @@ -1,5 +1,6 @@ /* -*-c++-*- * Copyright (C) 2009 Cedric Pinson + * Copyright (C) 2017 Julien Valentin * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -36,36 +37,43 @@ namespace osgAnimation META_Object(osgAnimation,RigTransformSoftware) virtual void operator()(RigGeometry&); + //to call when a skeleton is reacheable from the rig to prepare technic data + virtual bool prepareData(RigGeometry&); - class BonePtrWeight + class BonePtrWeight: std::pair< osg::observer_ptr< Bone >, float> { public: - BonePtrWeight(Bone* bone, float weight) : _bone(bone), _weight(weight) {} - const Bone* getBone() const { return _bone.get(); } - float getWeight() const { return _weight; } - void setWeight(float w) { _weight = w; } - protected: - osg::observer_ptr _bone; - float _weight; + BonePtrWeight(Bone*bone, float weight) :std::pair< osg::observer_ptr< Bone >, float>(bone,weight) {} + BonePtrWeight(const BonePtrWeight &bw2) : std::pair< osg::observer_ptr< Bone >, float>(bw2.first.get(),bw2.getWeight()) {} + + inline const Bone * getBonePtr() const {return first.get();} + inline void setBonePtr(Bone*b){first=b;} + inline const float & getWeight() const {return second;} + inline void setWeight(float b) {second=b;} + inline bool operator<(const BonePtrWeight &b1) const{ + if (second > b1.second)return true; + if (second < b1.second)return false; + return (first.get() > b1.first.get()); + } }; + typedef std::vector BonePtrWeightList; - typedef std::vector BonePtrWeightList; - typedef std::vector VertexList; - + /// map a set of boneinfluence to a list of vertex indices sharing this set class VertexGroup { public: - BonePtrWeightList& getBoneWeights() { return _boneweights; } - VertexList& getVertexes() { return _vertexes; } + inline BonePtrWeightList& getBoneWeights() { return _boneweights; } - void resetMatrix() + inline IndexList& getVertices() { return _vertexes; } + + inline void resetMatrix() { _result.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); } - void accummulateMatrix(const osg::Matrix& invBindMatrix, const osg::Matrix& matrix, osg::Matrix::value_type weight) + inline void accummulateMatrix(const osg::Matrix& invBindMatrix, const osg::Matrix& matrix, osg::Matrix::value_type weight) { osg::Matrix m = invBindMatrix * matrix; osg::Matrix::value_type* ptr = m.ptr(); @@ -86,7 +94,7 @@ namespace osgAnimation ptrresult[13] += ptr[13] * weight; ptrresult[14] += ptr[14] * weight; } - void computeMatrixForVertexSet() + inline void computeMatrixForVertexSet() { if (_boneweights.empty()) { @@ -98,7 +106,7 @@ namespace osgAnimation for(BonePtrWeightList::iterator bwit=_boneweights.begin();bwit!=_boneweights.end();++bwit ) { - const Bone* bone = bwit->getBone(); + const Bone* bone = bwit->getBonePtr(); if (!bone) { osg::notify(osg::WARN) << this << " RigTransformSoftware::computeMatrixForVertexSet Warning a bone is null, skip it" << std::endl; @@ -110,26 +118,25 @@ namespace osgAnimation accummulateMatrix(invBindMatrix, matrix, w); } } - const osg::Matrix& getMatrix() const { return _result;} + inline const osg::Matrix& getMatrix() const { return _result;} protected: BonePtrWeightList _boneweights; - VertexList _vertexes; + IndexList _vertexes; osg::Matrix _result; }; - - - template void compute(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst) + template + inline void compute(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst) { // the result of matrix mult should be cached to be used for vertexes transform and normal transform and maybe other computation - for(std::vector::iterator itvg=_uniqInfluenceSet2VertIDList.begin(); itvg!=_uniqInfluenceSet2VertIDList.end(); ++itvg) + for(VertexGroupList::iterator itvg=_uniqVertexGroupList.begin(); itvg!=_uniqVertexGroupList.end(); ++itvg) { VertexGroup& uniq = *itvg; uniq.computeMatrixForVertexSet(); osg::Matrix matrix = transform * uniq.getMatrix() * invTransform; - const VertexList& vertexes = uniq.getVertexes(); - for(VertexList::const_iterator vertIDit=vertexes.begin(); vertIDit!=vertexes.end(); ++vertIDit) + const IndexList& vertexes = uniq.getVertices(); + for(IndexList::const_iterator vertIDit=vertexes.begin(); vertIDit!=vertexes.end(); ++vertIDit) { dst[*vertIDit] = src[*vertIDit] * matrix; } @@ -138,16 +145,17 @@ namespace osgAnimation } - template void computeNormal(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst) + template + inline void computeNormal(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst) { - for(std::vector::iterator itvg=_uniqInfluenceSet2VertIDList.begin(); itvg!=_uniqInfluenceSet2VertIDList.end(); ++itvg) + for(VertexGroupList::iterator itvg=_uniqVertexGroupList.begin(); itvg!=_uniqVertexGroupList.end(); ++itvg) { VertexGroup& uniq = *itvg; uniq.computeMatrixForVertexSet(); osg::Matrix matrix = transform * uniq.getMatrix() * invTransform; - const VertexList& vertexes = uniq.getVertexes(); - for(VertexList::const_iterator vertIDit=vertexes.begin(); vertIDit!=vertexes.end(); ++vertIDit) + const IndexList& vertexes = uniq.getVertices(); + for(IndexList::const_iterator vertIDit=vertexes.begin(); vertIDit!=vertexes.end(); ++vertIDit) { dst[*vertIDit] = osg::Matrix::transform3x3(src[*vertIDit],matrix); } @@ -156,13 +164,15 @@ namespace osgAnimation protected: - bool init(RigGeometry&); - void initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexGroupList& influence); - std::vector _uniqInfluenceSet2VertIDList; - bool _needInit; std::map _invalidInfluence; + + typedef std::vector VertexGroupList; + + VertexGroupList _uniqVertexGroupList; + void buildMinimumUpdateSet(const BoneMap&boneMap,const RigGeometry&rig ); + }; } diff --git a/include/osgAnimation/VertexInfluence b/include/osgAnimation/VertexInfluence index 0b777e283..a521f13d7 100644 --- a/include/osgAnimation/VertexInfluence +++ b/include/osgAnimation/VertexInfluence @@ -23,11 +23,31 @@ namespace osgAnimation { + // first is bonename, and second the weight + struct BoneWeight: public std::pair + { + BoneWeight( std::string f,float s): + std::pair(f,s){} + inline const std::string& getBoneName()const{return first;} + inline void setBoneName(const std::string&s){first=s;} + inline const float &getWeight()const{return second;} + inline void setWeight(float i){second=i;} + }; + // first is vertex index, and second the weight + struct VertexIndexWeight: public std::pair + { + VertexIndexWeight( unsigned int f = 0xffffffff,float s = 0.0f): std::pair(f,s){} + inline const unsigned int& getIndex()const{return first;} + inline void setIndex(unsigned int i){first=i;} + inline const float &getWeight()const{return second;} + inline void setWeight(float i){second=i;} + }; + typedef std::vector IndexWeightList; + typedef std::vector BoneWeightList; + typedef std::vector IndexList; - // first is vertex index, and second the weight, the - typedef std::pair IndexWeight; - typedef std::vector VertexList; - class OSGANIMATION_EXPORT BoneInfluenceList : public VertexList + //Bone influence list + class OSGANIMATION_EXPORT VertexInfluence : public IndexWeightList { public: const std::string& getName() const { return _name;} @@ -38,72 +58,36 @@ namespace osgAnimation std::string _name; }; - class VertexInfluenceMap : public std::map , public osg::Object + class VertexInfluenceMap : public std::map , public osg::Object { public: META_Object(osgAnimation, VertexInfluenceMap); VertexInfluenceMap() {} VertexInfluenceMap(const osgAnimation::VertexInfluenceMap& org, const osg::CopyOp& copyop): - std::map(org), + std::map(org), osg::Object(org, copyop) {} - }; + ///normalize per vertex weights given numvert of the attached mesh + void normalize(unsigned int numvert); + ///remove weakest influences in order to fit targetted numbonepervertex + void cullInfluenceCountPerVertex(unsigned int maxnumbonepervertex, float minweight=0, bool renormalize=true); - // this class manage VertexInfluence database by mesh - // reference bones per vertex ... - class OSGANIMATION_EXPORT VertexInfluenceSet - { - public: - typedef std::vector BoneToVertexList; + //compute PerVertexInfluenceList + void computePerVertexInfluenceList(std::vector& perVertexInfluenceList, unsigned int numvert)const; - class BoneWeight + /// map a set of boneinfluence to a list of vertex indices sharing this set + class VertexGroup: public std::pair { public: - BoneWeight(const std::string& name, float weight) : _boneName(name), _weight(weight) {} - BoneWeight(const BoneWeight &bw2) : _boneName(bw2._boneName), _weight(bw2._weight) {} - const std::string& getBoneName() const { return _boneName; } - float getWeight() const { return _weight; } - void setWeight(float weight) { _weight = weight; } - bool operator==(const BoneWeight& b) const { return (_boneName == b.getBoneName() && _weight == b.getWeight()); } - - protected: - std::string _boneName; - float _weight; + inline const BoneWeightList& getBoneWeights()const { return first; } + inline void setBoneWeights( BoneWeightList& o ) { first=o; } + inline IndexList& vertIDs() { return second; } }; - typedef std::vector BoneWeightList; - typedef std::vector VertIDToBoneWeightList; - - class VertexGroup - { - public: - // set Influences of the VertexGroup - void setBones(BoneWeightList& bones) { _bones = bones;} - const BoneWeightList& getBones() const { return _bones;} - // set Vertex Indices of the VertexGroup - std::vector& getVertexes() { return _vertexes;} - const std::vector& getVertexes() const { return _vertexes;} - protected: - std::vector _vertexes; - BoneWeightList _bones; // here we could limit matrix operation by caching (weight * matrix) - }; - - typedef std::vector UniqVertexGroupList; - /** construct a vector of unique VertexGroups and their influences**/ - void buildUniqVertexGroupList(); - /** return a list of unique VertexGroups and their influences**/ - const UniqVertexGroupList& getUniqVertexGroupList() const { return _uniqVertexSetToBoneSet;} - void addVertexInfluence(const BoneInfluenceList& v); - void buildVertex2BoneList(unsigned int numvertices); - void clear(); - - const VertIDToBoneWeightList& getVertexToBoneList() const; - protected: - BoneToVertexList _bone2Vertexes; - VertIDToBoneWeightList _vertex2Bones; - UniqVertexGroupList _uniqVertexSetToBoneSet; + /// compute the minimal VertexGroup Set in which vertices shares the same influence set + void computeMinimalVertexGroupList(std::vector&uniqVertexGroupList, unsigned int numvert)const; }; } diff --git a/src/osgAnimation/MorphGeometry.cpp b/src/osgAnimation/MorphGeometry.cpp index f52c04c3a..07a86d1a6 100644 --- a/src/osgAnimation/MorphGeometry.cpp +++ b/src/osgAnimation/MorphGeometry.cpp @@ -29,6 +29,7 @@ MorphGeometry::MorphGeometry() : setUseDisplayList(false); setUpdateCallback(new UpdateMorphGeometry); setUseVertexBufferObjects(true); + _morphTransformImplementation = new MorphTransformSoftware(); } MorphGeometry::MorphGeometry(const osg::Geometry& g) : @@ -41,10 +42,12 @@ MorphGeometry::MorphGeometry(const osg::Geometry& g) : setUseDisplayList(false); setUpdateCallback(new UpdateMorphGeometry); setUseVertexBufferObjects(true); + _morphTransformImplementation = new MorphTransformSoftware(); } MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) : osg::Geometry(b,copyop), + _morphTransformImplementation((MorphTransform*)copyop(b._morphTransformImplementation)), _dirty(b._dirty), _method(b._method), _morphTargets(b._morphTargets), @@ -56,9 +59,6 @@ MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) setUseVertexBufferObjects(true); } -MorphTransform* MorphGeometry::getMorphTransformImplementation() { return _rigTransformImplementation.get(); } -void MorphGeometry::setMorphTransformImplementation(MorphTransform* rig) { _rigTransformImplementation = rig; } - UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) : osg::Object(apc, copyop), osg::Callback(apc, copyop), diff --git a/src/osgAnimation/MorphTransformHardware.cpp b/src/osgAnimation/MorphTransformHardware.cpp index be37a470a..f0915bbf1 100644 --- a/src/osgAnimation/MorphTransformHardware.cpp +++ b/src/osgAnimation/MorphTransformHardware.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyleft 2016 Valentin Julien + * Copyright (C) 2017 Julien Valentin * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -19,29 +19,23 @@ #include ///texture unit reserved for morphtarget TBO -#define MORPHTEXTUREUNIT 7 +#define DEFAULTMORPHTEXTUREUNIT 7 using namespace osgAnimation; -MorphTransformHardware::MorphTransformHardware() +MorphTransformHardware::MorphTransformHardware():_needInit(true),_reservedTextureUnit(DEFAULTMORPHTEXTUREUNIT) { - _needInit = true; - } MorphTransformHardware::MorphTransformHardware(const MorphTransformHardware& rth, const osg::CopyOp& copyop): MorphTransform(rth, copyop), _uniformTargetsWeight(rth._uniformTargetsWeight), _shader(rth._shader), - _needInit(rth._needInit) + _needInit(rth._needInit), + _reservedTextureUnit(rth._reservedTextureUnit) { } -void MorphTransformHardware::setShader(osg::Shader* shader) -{ - _shader = shader; -} - bool MorphTransformHardware::init(MorphGeometry& morphGeometry) { osg::Vec3Array* pos = dynamic_cast(morphGeometry.getVertexArray()); @@ -104,7 +98,7 @@ bool MorphTransformHardware::init(MorphGeometry& morphGeometry) //create TBO Texture handle osg::Uniform * morphTBOHandle=new osg::Uniform(osg::Uniform::SAMPLER_BUFFER,"morphTargets"); - morphTBOHandle->set(MORPHTEXTUREUNIT); + morphTBOHandle->set(_reservedTextureUnit); //create dynamic uniform for morphtargets animation weights _uniformTargetsWeight=new osg::Uniform(osg::Uniform::FLOAT,"morphWeights",morphlist.size()); @@ -174,7 +168,7 @@ bool MorphTransformHardware::init(MorphGeometry& morphGeometry) osg::ref_ptr ss = morphGeometry.getOrCreateStateSet(); ss->addUniform(_uniformTargetsWeight); - ss->setTextureAttribute(MORPHTEXTUREUNIT,morphTargetsTBO); + ss->setTextureAttribute(_reservedTextureUnit,morphTargetsTBO); ss->addUniform( morphTBOHandle); ss->addUniform(new osg::Uniform("nbMorphVertex", morphGeometry.getVertexArray()->getNumElements())); @@ -187,11 +181,14 @@ void MorphTransformHardware::operator()(MorphGeometry& geom) if (_needInit) if (!init(geom)) return; - - ///upload new morph weights each update via uniform - int curimorph=0; - MorphGeometry::MorphTargetList & morphlist=geom.getMorphTargetList(); - for(MorphGeometry::MorphTargetList::const_iterator curmorph=morphlist.begin(); curmorph!=morphlist.end(); ++curmorph) - _uniformTargetsWeight->setElement(curimorph++, curmorph->getWeight()); - _uniformTargetsWeight->dirty(); + if (geom.isDirty()) + { + ///upload new morph weights each update via uniform + int curimorph=0; + MorphGeometry::MorphTargetList & morphlist=geom.getMorphTargetList(); + for(MorphGeometry::MorphTargetList::const_iterator curmorph=morphlist.begin(); curmorph!=morphlist.end(); ++curmorph) + _uniformTargetsWeight->setElement(curimorph++, curmorph->getWeight()); + _uniformTargetsWeight->dirty(); + geom.dirty(false); + } } diff --git a/src/osgAnimation/RigGeometry.cpp b/src/osgAnimation/RigGeometry.cpp index b09c61966..c176cf9df 100644 --- a/src/osgAnimation/RigGeometry.cpp +++ b/src/osgAnimation/RigGeometry.cpp @@ -59,6 +59,7 @@ RigGeometry::RigGeometry() _matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity(); // disable the computation of boundingbox for the rig mesh setComputeBoundingBoxCallback(new RigComputeBoundingBoxCallback()); + _rigTransformImplementation = new osgAnimation::RigTransformSoftware; } @@ -66,7 +67,7 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) : osg::Geometry(b,copyop), _geometry(b._geometry), - _vertexInfluenceSet(b._vertexInfluenceSet), + _rigTransformImplementation((RigTransform*)copyop(b._rigTransformImplementation)), _vertexInfluenceMap(b._vertexInfluenceMap), _needToComputeMatrix(b._needToComputeMatrix) { @@ -84,23 +85,6 @@ RigGeometry::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) : const osg::Matrix& RigGeometry::getMatrixFromSkeletonToGeometry() const { return _matrixFromSkeletonToGeometry; } const osg::Matrix& RigGeometry::getInvMatrixFromSkeletonToGeometry() const { return _invMatrixFromSkeletonToGeometry;} -void RigGeometry::buildVertexInfluenceSet() -{ - if (!_vertexInfluenceMap.valid()) - { - OSG_WARN << "buildVertexInfluenceSet can't be called without VertexInfluence already set to the RigGeometry ( " << getName() << " ) " << std::endl; - return; - } - _vertexInfluenceSet.clear(); - for (osgAnimation::VertexInfluenceMap::iterator it = _vertexInfluenceMap->begin(); - it != _vertexInfluenceMap->end(); - ++it){ - _vertexInfluenceSet.addVertexInfluence(it->second); - } - _vertexInfluenceSet.buildVertex2BoneList(getSourceGeometry()->getVertexArray()->getNumElements()); - _vertexInfluenceSet.buildUniqVertexGroupList(); - OSG_DEBUG << "uniq groups " << _vertexInfluenceSet.getUniqVertexGroupList().size() << " for " << getName() << std::endl; -} void RigGeometry::computeMatrixFromRootSkeleton() { @@ -118,12 +102,7 @@ void RigGeometry::computeMatrixFromRootSkeleton() void RigGeometry::update() { - if (!getRigTransformImplementation()) - { - _rigTransformImplementation = new RigTransformSoftware; - } - - RigTransform& implementation = *getRigTransformImplementation(); + RigTransform& implementation = *_rigTransformImplementation; (implementation)(*this); } diff --git a/src/osgAnimation/RigTransformHardware.cpp b/src/osgAnimation/RigTransformHardware.cpp index ad15c31e6..85a32bdaa 100644 --- a/src/osgAnimation/RigTransformHardware.cpp +++ b/src/osgAnimation/RigTransformHardware.cpp @@ -1,5 +1,6 @@ /* -*-c++-*- * Copyright (C) 2009 Cedric Pinson + * Copyright (C) 2017 Julien Valentin * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -19,13 +20,13 @@ using namespace osgAnimation; - -RigTransformHardware::RigTransformHardware() -{ - _needInit = true; - _bonesPerVertex = 0; - _nbVertexes = 0; -} +#define DEFAULT_FIRST_VERTATTRIB_TARGETTED 11 +RigTransformHardware::RigTransformHardware(): + _bonesPerVertex (0), + _nbVertexes (0), + _needInit (true), + _minAttribIndex(DEFAULT_FIRST_VERTATTRIB_TARGETTED) + {} RigTransformHardware::RigTransformHardware(const RigTransformHardware& rth, const osg::CopyOp& copyop): RigTransform(rth, copyop), @@ -36,7 +37,8 @@ RigTransformHardware::RigTransformHardware(const RigTransformHardware& rth, cons _boneWeightAttribArrays(rth._boneWeightAttribArrays), _uniformMatrixPalette(rth._uniformMatrixPalette), _shader(rth._shader), - _needInit(rth._needInit) + _needInit(rth._needInit), + _minAttribIndex(rth._minAttribIndex) { } @@ -47,17 +49,6 @@ osg::Vec4Array* RigTransformHardware::getVertexAttrib(unsigned int index) return _boneWeightAttribArrays[index].get(); } -unsigned int RigTransformHardware::getNumVertexAttrib() -{ - return _boneWeightAttribArrays.size(); -} - -osg::Uniform* RigTransformHardware::getMatrixPaletteUniform() -{ - return _uniformMatrixPalette.get(); -} - - void RigTransformHardware::computeMatrixPaletteUniform(const osg::Matrix& transformFromSkeletonToGeometry, const osg::Matrix& invTransformFromSkeletonToGeometry) { for (unsigned int i = 0; i < _bonePalette.size(); i++) @@ -73,92 +64,7 @@ void RigTransformHardware::computeMatrixPaletteUniform(const osg::Matrix& transf } -unsigned int RigTransformHardware::getNumBonesPerVertex() const { return _bonesPerVertex;} -unsigned int RigTransformHardware::getNumVertexes() const { return _nbVertexes;} - -typedef std::vector > VertexIndexWeightList; -void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightList&_vertexIndexMatrixWeightList,RigTransformHardware::BoneWeightAttribList & boneWeightAttribArrays); - -bool RigTransformHardware::createPalette(unsigned int nbVertexes, const BoneMap &boneMap, const VertexInfluenceSet::VertIDToBoneWeightList& vertexIndexToBoneWeightMap) -{ - _nbVertexes = nbVertexes; - typedef std::map BoneNameCountMap; - _bonePalette.clear(); - _boneNameToPalette.clear(); - BoneNameCountMap boneNameCountMap; - // init vertex attribute data - VertexIndexWeightList vertexIndexWeight; - vertexIndexWeight.resize(nbVertexes); - - unsigned int maxBonePerVertex = 0; - if(vertexIndexToBoneWeightMap.size()!=nbVertexes) { - OSG_WARN << "RigTransformHardware::some vertex has no transform " < 1e-4) // don't use bone with weight too small - { - if ((boneName2PaletteIndex= _boneNameToPalette.find(bw.getBoneName())) != _boneNameToPalette.end()) - { - boneNameCountMap[bw.getBoneName()]++; - bonesForThisVertex++; // count max number of bones per vertexes - vertexIndexWeight[vertexID].push_back(IndexWeightEntry(boneName2PaletteIndex->second,bw.getWeight())); - } - else - { - BoneMap::const_iterator bonebyname; - if ((bonebyname=boneMap.find(bw.getBoneName())) == boneMap.end()) - { - OSG_WARN << "RigTransformHardware::createPalette can't find bone " << bw.getBoneName() << "in skeleton bonemap: skip this influence" << std::endl; - continue; - } - boneNameCountMap[bw.getBoneName()] = 1; // for stats - bonesForThisVertex++; - - _boneNameToPalette[bw.getBoneName()] = _bonePalette.size() ; - vertexIndexWeight[vertexID].push_back(IndexWeightEntry(_bonePalette.size(),bw.getWeight())); - _bonePalette.push_back(bonebyname->second); - } - } - else - { - OSG_WARN << "RigTransformHardware::createPalette Bone " << bw.getBoneName() << " has a weight " << bw.getWeight() << " for vertex " << vertexID << " this bone will not be in the palette" << std::endl; - } - } - if(bonesForThisVertex==0) { - OSG_WARN << "RigTransformHardware::no transform for vertex " << vertexID << " this will induce a bug in vertex shader" << std::endl; - } - maxBonePerVertex = osg::maximum(maxBonePerVertex, bonesForThisVertex); - } - OSG_INFO << "RigTransformHardware::createPalette maximum number of bone per vertex is " << maxBonePerVertex << std::endl; - OSG_INFO << "RigTransformHardware::createPalette matrix palette has " << boneNameCountMap.size() << " entries" << std::endl; - - for (BoneNameCountMap::iterator it = boneNameCountMap.begin(); it != boneNameCountMap.end(); ++it) - { - OSG_INFO << "RigTransformHardware::createPalette Bone " << it->first << " is used " << it->second << " times" << std::endl; - } - - OSG_INFO << "RigTransformHardware::createPalette will use " << boneNameCountMap.size() * 4 << " uniforms" << std::endl; - - - _bonesPerVertex = maxBonePerVertex; - for (int i = 0 ; i < (int)vertexIndexWeight.size(); i++) - vertexIndexWeight[i].resize(maxBonePerVertex); - - _uniformMatrixPalette = createVertexUniform(); - createVertexAttribList(*this,vertexIndexWeight,this->_boneWeightAttribArrays); - return true; -} - +void createVertexAttribList(RigTransformHardware& rig,const std::vector > &perVertexInfluences,RigTransformHardware::BoneWeightAttribList & boneWeightAttribArrays); // // create vertex attribute by 2 bones @@ -168,11 +74,16 @@ bool RigTransformHardware::createPalette(unsigned int nbVertexes, const BoneMap // the idea is to use this format to have a granularity smaller // than the 4 bones using two vertex attributes // -void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightList& _vertexIndexMatrixWeightList, RigTransformHardware::BoneWeightAttribList& boneWeightAttribArrays) + +typedef std::vector > PerVertexInfList; +void createVertexAttribList(RigTransformHardware& rig, + const PerVertexInfList & perVertexInfluences, + RigTransformHardware::BoneWeightAttribList& boneWeightAttribArrays) { unsigned int nbVertices= rig.getNumVertexes(); unsigned int maxbonepervertex=rig.getNumBonesPerVertex(); unsigned int nbArray = static_cast(ceilf( ((float)maxbonepervertex) * 0.5f)); + if (!nbArray) return ; @@ -184,7 +95,6 @@ void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightLis array->resize( nbVertices); for (unsigned int j = 0; j < nbVertices; j++) { - for (unsigned int b = 0; b < 2; b++) { // the granularity is 2 so if we have only one bone @@ -193,10 +103,10 @@ void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightLis unsigned int boneIndexInVec4 = b*2; (*array)[j][0 + boneIndexInVec4] = 0; (*array)[j][1 + boneIndexInVec4] = 0; - if (boneIndexInList < maxbonepervertex) + if (boneIndexInList < perVertexInfluences[j].size()) { - float boneIndex = static_cast(_vertexIndexMatrixWeightList[j][boneIndexInList].getBoneIndex()); - float boneWeight = _vertexIndexMatrixWeightList[j][boneIndexInList].getWeight(); + float boneIndex = static_cast(perVertexInfluences[j][boneIndexInList].getIndex()); + float boneWeight = perVertexInfluences[j][boneIndexInList].getWeight(); // fill the vec4 (*array)[j][0 + boneIndexInVec4] = boneIndex; (*array)[j][1 + boneIndexInVec4] = boneWeight; @@ -204,127 +114,234 @@ void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightLis } } } - return ; + return; } -osg::Uniform* RigTransformHardware::createVertexUniform() +bool RigTransformHardware::prepareData(RigGeometry& rig) { - osg::Uniform* uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size()); - return uniform; -} - - -void RigTransformHardware::setShader(osg::Shader* shader) -{ - _shader = shader; -} - -bool RigTransformHardware::init(RigGeometry& geom) -{ - if (!geom.getSkeleton()) + if(!rig.getSkeleton() && !rig.getParents().empty()) { - OSG_WARN << "RigTransformHardware no skeleton set in geometry " << geom.getName() << std::endl; - return false; + RigGeometry::FindNearestParentSkeleton finder; + if(rig.getParents().size() > 1) + osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << rig.getName() << " )" << std::endl; + rig.getParents()[0]->accept(finder); + + if(!finder._root.valid()) + { + osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << rig.getName() << " )" << std::endl; + return false; + } + rig.setSkeleton(finder._root.get()); } BoneMapVisitor mapVisitor; - geom.getSkeleton()->accept(mapVisitor); - BoneMap bm = mapVisitor.getBoneMap(); + rig.getSkeleton()->accept(mapVisitor); + BoneMap boneMap = mapVisitor.getBoneMap(); - osg::Geometry& source = *geom.getSourceGeometry(); + if (!buildPalette(boneMap,rig) ) + return false; + + osg::Geometry& source = *rig.getSourceGeometry(); osg::Vec3Array* positionSrc = dynamic_cast(source.getVertexArray()); if (!positionSrc) { - OSG_WARN << "RigTransformHardware no vertex array in the geometry " << geom.getName() << std::endl; + OSG_WARN << "RigTransformHardware no vertex array in the geometry " << rig.getName() << std::endl; return false; } // copy shallow from source geometry to rig - geom.copyFrom(source); + rig.copyFrom(source); - if (!createPalette(positionSrc->size(),bm,geom.getVertexInfluenceSet().getVertexToBoneList())) - return false; - - osg::ref_ptr program ; - osg::ref_ptr vertexshader; - osg::ref_ptr stateset = geom.getOrCreateStateSet(); - - //grab geom source program and vertex shader if _shader is not setted - if(!_shader.valid() && (program = (osg::Program*)stateset->getAttribute(osg::StateAttribute::PROGRAM))) - { - for(unsigned int i=0;igetNumShaders();++i) - if(program->getShader(i)->getType()==osg::Shader::VERTEX){ - vertexshader=program->getShader(i); - program->removeShader(vertexshader); - - } - }else { - program = new osg::Program; - program->setName("HardwareSkinning"); - } - //set default source if _shader is not user setted - if (!vertexshader.valid()){ - if (!_shader.valid()) - vertexshader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"skinning.vert"); - else vertexshader=_shader; - } - - - if (!vertexshader.valid()) { - OSG_WARN << "RigTransformHardware can't load VertexShader" << std::endl; - return false; - } - - // replace max matrix by the value from uniform - { - std::string str = vertexshader->getShaderSource(); - std::string toreplace = std::string("MAX_MATRIX"); - std::size_t start = str.find(toreplace); - - if (std::string::npos != start) { - std::stringstream ss; - ss << getMatrixPaletteUniform()->getNumElements(); - str.replace(start, toreplace.size(), ss.str()); - vertexshader->setShaderSource(str); - } - else - { - OSG_INFO<< "MAX_MATRIX not found in Shader! " << str << std::endl; - } - OSG_INFO << "Shader " << str << std::endl; - } - - unsigned int attribIndex = 11; - unsigned int nbAttribs = getNumVertexAttrib(); - if(nbAttribs==0) - OSG_WARN << "nbAttribs== " << nbAttribs << std::endl; - for (unsigned int i = 0; i < nbAttribs; i++) - { - std::stringstream ss; - ss << "boneWeight" << i; - program->addBindAttribLocation(ss.str(), attribIndex + i); - - if(getVertexAttrib(i)->getNumElements()!=_nbVertexes) - OSG_WARN << "getVertexAttrib== " << getVertexAttrib(i)->getNumElements() << std::endl; - geom.setVertexAttribArray(attribIndex + i, getVertexAttrib(i)); - OSG_INFO << "set vertex attrib " << ss.str() << std::endl; - } - - program->addShader(vertexshader.get()); - - stateset->removeUniform("matrixPalette"); - stateset->addUniform(getMatrixPaletteUniform()); - - stateset->removeUniform("nbBonesPerVertex"); - stateset->addUniform(new osg::Uniform("nbBonesPerVertex",_bonesPerVertex)); - - stateset->removeAttribute(osg::StateAttribute::PROGRAM); - if(!stateset->getAttribute(osg::StateAttribute::PROGRAM)) - stateset->setAttributeAndModes(program.get()); - - _needInit = false; return true; } +bool RigTransformHardware::buildPalette(const BoneMap&boneMap ,const RigGeometry&rig) { + + typedef std::map BoneNameCountMap; + _nbVertexes = rig.getVertexArray()->getNumElements(); + _boneWeightAttribArrays.resize(0); + _bonePalette.clear(); + _boneNameToPalette.clear(); + + IndexWeightList::size_type maxBonePerVertex=0; + BoneNameCountMap boneNameCountMap; + + const VertexInfluenceMap &vertexInfluenceMap=*rig.getInfluenceMap(); + BoneNamePaletteIndex::iterator boneName2PaletteIndex; + + // init temp vertex attribute data + std::vector perVertexInfluences; + perVertexInfluences.resize(_nbVertexes); + + unsigned int paletteindex; + for (osgAnimation::VertexInfluenceMap::const_iterator boneinflistit = vertexInfluenceMap.begin(); + boneinflistit != vertexInfluenceMap.end(); + ++boneinflistit) + { + const IndexWeightList& boneinflist = boneinflistit->second; + const std::string& bonename = boneinflistit->first; + BoneMap::const_iterator bonebyname; + if ((bonebyname=boneMap.find(bonename)) == boneMap.end()) + { + OSG_WARN << "RigTransformHardware::buildPalette can't find bone " << bonename << "in skeleton bonemap: skip this influence" << std::endl; + continue; + } + if ((boneName2PaletteIndex= _boneNameToPalette.find(bonename)) != _boneNameToPalette.end()) + { + boneNameCountMap[bonename]++; + paletteindex= boneName2PaletteIndex->second ; + } + else + { + boneNameCountMap[bonename] = 1; // for stats + _boneNameToPalette[bonename] = _bonePalette.size() ; + paletteindex= _bonePalette.size() ; + _bonePalette.push_back(bonebyname->second); + + } + for(IndexWeightList::const_iterator infit = boneinflist.begin(); infit!=boneinflist.end(); ++infit) + { + const VertexIndexWeight& iw = *infit; + const unsigned int &index = iw.getIndex(); + const float &weight = iw.getWeight(); + IndexWeightList & iwlist=perVertexInfluences[index]; + + if(fabs(weight) > 1e-4) // don't use bone with weight too small + { + iwlist.push_back(VertexIndexWeight(paletteindex,weight)); + } + else + { + OSG_WARN << "RigTransformHardware::buildPalette Bone " << bonename << " has a weight " << weight << " for vertex " << index << " this bone will not be in the palette" << std::endl; + } + maxBonePerVertex = osg::maximum(maxBonePerVertex, iwlist.size()); + + } + OSG_INFO << "RigTransformHardware::buildPalette maximum number of bone per vertex is " << maxBonePerVertex << std::endl; + OSG_INFO << "RigTransformHardware::buildPalette matrix palette has " << boneNameCountMap.size() << " entries" << std::endl; + + for (BoneNameCountMap::iterator it = boneNameCountMap.begin(); it != boneNameCountMap.end(); ++it) + { + OSG_INFO << "RigTransformHardware::buildPalette Bone " << it->first << " is used " << it->second << " times" << std::endl; + } + + OSG_INFO << "RigTransformHardware::buildPalette will use " << boneNameCountMap.size() * 4 << " uniforms" << std::endl; + + } + + ///normalize + unsigned int vertid=0; + for(PerVertexInfList::iterator vertinfit=perVertexInfluences.begin(); vertinfit != perVertexInfluences.end(); ++vertinfit,++vertid) + { + float sum=0; + for(IndexWeightList::iterator iwit = vertinfit->begin(); iwit != vertinfit->end(); ++iwit) + sum+=iwit->second; + + if(sum< 1e-4){ + OSG_WARN << "RigTransformHardware::buildPalette Warning: vertex with zero sum weights: " <begin();iwit!=vertinfit->end();++iwit) + iwit->second*=sum; + } + } + + _uniformMatrixPalette = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size()); + + _bonesPerVertex = maxBonePerVertex; + + createVertexAttribList(*this,perVertexInfluences,this->_boneWeightAttribArrays); + +return true; +} + +bool RigTransformHardware::init(RigGeometry& rig){ + if(_bonesPerVertex>0){ + ///data seams prepared + osg::ref_ptr program ; + osg::ref_ptr vertexshader; + osg::ref_ptr stateset = rig.getOrCreateStateSet(); + + //grab geom source program and vertex shader if _shader is not setted + if(!_shader.valid() && (program = (osg::Program*)stateset->getAttribute(osg::StateAttribute::PROGRAM))) + { + for(unsigned int i=0; igetNumShaders(); ++i) + if(program->getShader(i)->getType()==osg::Shader::VERTEX) { + vertexshader=program->getShader(i); + program->removeShader(vertexshader); + + } + } else { + program = new osg::Program; + program->setName("HardwareSkinning"); + } + //set default source if _shader is not user setted + if (!vertexshader.valid()) { + if (!_shader.valid()) + vertexshader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"skinning.vert"); + else vertexshader=_shader; + } + + + if (!vertexshader.valid()) { + OSG_WARN << "RigTransformHardware can't load VertexShader" << std::endl; + return false; + } + + // replace max matrix by the value from uniform + { + std::string str = vertexshader->getShaderSource(); + std::string toreplace = std::string("MAX_MATRIX"); + std::size_t start = str.find(toreplace); + if (std::string::npos != start) { + std::stringstream ss; + ss << getMatrixPaletteUniform()->getNumElements(); + str.replace(start, toreplace.size(), ss.str()); + vertexshader->setShaderSource(str); + } + else + { + OSG_INFO<< "MAX_MATRIX not found in Shader! " << str << std::endl; + } + OSG_INFO << "Shader " << str << std::endl; + } + + unsigned int attribIndex = _minAttribIndex; + unsigned int nbAttribs = getNumVertexAttrib(); + if(nbAttribs==0) + OSG_WARN << "nbAttribs== " << nbAttribs << std::endl; + for (unsigned int i = 0; i < nbAttribs; i++) + { + std::stringstream ss; + ss << "boneWeight" << i; + program->addBindAttribLocation(ss.str(), attribIndex + i); + + if(getVertexAttrib(i)->getNumElements()!=_nbVertexes) + OSG_WARN << "getVertexAttrib== " << getVertexAttrib(i)->getNumElements() << std::endl; + rig.setVertexAttribArray(attribIndex + i, getVertexAttrib(i)); + OSG_INFO << "set vertex attrib " << ss.str() << std::endl; + } + + + program->addShader(vertexshader.get()); + + stateset->removeUniform("nbBonesPerVertex"); + stateset->addUniform(new osg::Uniform("nbBonesPerVertex",_bonesPerVertex)); + + stateset->removeUniform("matrixPalette"); + stateset->addUniform(_uniformMatrixPalette); + + stateset->removeAttribute(osg::StateAttribute::PROGRAM); + if(!stateset->getAttribute(osg::StateAttribute::PROGRAM)) + stateset->setAttributeAndModes(program.get()); + + _needInit = false; + return false; + } + else prepareData(rig); + return false; +} void RigTransformHardware::operator()(RigGeometry& geom) { if (_needInit) diff --git a/src/osgAnimation/RigTransformSoftware.cpp b/src/osgAnimation/RigTransformSoftware.cpp index 4ab524cdb..403033da3 100644 --- a/src/osgAnimation/RigTransformSoftware.cpp +++ b/src/osgAnimation/RigTransformSoftware.cpp @@ -1,5 +1,6 @@ /* -*-c++-*- * Copyright (C) 2009 Cedric Pinson + * Copyright (C) 2017 Julien Valentin * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -19,6 +20,7 @@ #include #include + using namespace osgAnimation; RigTransformSoftware::RigTransformSoftware() @@ -34,40 +36,141 @@ RigTransformSoftware::RigTransformSoftware(const RigTransformSoftware& rts,const } -bool RigTransformSoftware::init(RigGeometry& geom) -{ - if (!geom.getSkeleton()) - return false; +typedef std::vector BonePtrWeightList; +void RigTransformSoftware::buildMinimumUpdateSet( const BoneMap&boneMap, const RigGeometry&rig ){ + + ///1 Create Index2Vec + const VertexInfluenceMap &vertexInfluenceMap=*rig.getInfluenceMap(); + std::vector perVertexInfluences; + perVertexInfluences.resize(rig.getSourceGeometry()->getVertexArray()->getNumElements()); + + for (osgAnimation::VertexInfluenceMap::const_iterator perBoneinfit = vertexInfluenceMap.begin(); + perBoneinfit != vertexInfluenceMap.end(); + ++perBoneinfit) + { + const IndexWeightList& inflist = perBoneinfit->second; + const std::string& bonename = perBoneinfit->first; + + if (bonename.empty()) { + OSG_WARN << "RigTransformSoftware::VertexInfluenceMap contains unamed bone IndexWeightList" << std::endl; + } + BoneMap::const_iterator bmit = boneMap.find(bonename); + if (bmit == boneMap.end() ) + { + if (_invalidInfluence.find(bonename) != _invalidInfluence.end()) { + _invalidInfluence[bonename] = true; + OSG_WARN << "RigTransformSoftware Bone " << bonename << " not found, skip the influence group " << std::endl; + } + continue; + } + Bone* bone = bmit->second.get(); + for(IndexWeightList::const_iterator infit=inflist.begin(); infit!=inflist.end(); ++infit) + { + const VertexIndexWeight &iw = *infit; + const unsigned int &index = iw.getIndex(); + float weight = iw.getWeight(); + perVertexInfluences[index].push_back(BonePtrWeight(bone, weight)); + } + } + + // normalize _vertex2Bones weight per vertex + unsigned vertexID=0; + for (std::vector::iterator it = perVertexInfluences.begin(); it != perVertexInfluences.end(); ++it, ++vertexID) + { + BonePtrWeightList& bones = *it; + float sum = 0; + for(BonePtrWeightList::iterator bwit=bones.begin();bwit!=bones.end();++bwit) + sum += bwit->getWeight(); + if (sum < 1e-4) + { + OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << vertexID << " seems to have 0 weight, skip normalize for this vertex" << std::endl; + } + else + { + float mult = 1.0/sum; + for(BonePtrWeightList::iterator bwit=bones.begin();bwit!=bones.end();++bwit) + bwit->setWeight(bwit->getWeight() * mult); + } + } + + ///2 Create inverse mapping Vec2Vec from previous built Index2Vec + ///in order to minimize weighted matrices computation on update + _uniqVertexGroupList.clear(); + + typedef std::map UnifyBoneGroup; + UnifyBoneGroup unifyBuffer; + vertexID=0; + for (std::vector::iterator perVertinfit = perVertexInfluences.begin(); perVertinfit!=perVertexInfluences.end(); ++perVertinfit,++vertexID) + { + BonePtrWeightList &boneinfs = *perVertinfit; + // sort the vector to have a consistent key + std::sort(boneinfs.begin(), boneinfs.end() ); + // we use the vector as key to differentiate group + UnifyBoneGroup::iterator result = unifyBuffer.find(boneinfs); + if (result != unifyBuffer.end()) + result->second.getVertices().push_back(vertexID); + else + { + VertexGroup& vg = unifyBuffer[boneinfs]; + vg.getBoneWeights() = boneinfs; + vg.getVertices().push_back(vertexID); + } + } + _uniqVertexGroupList.reserve(unifyBuffer.size()); + for (UnifyBoneGroup::const_iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it) + _uniqVertexGroupList.push_back(it->second); + OSG_INFO << "uniq groups " << _uniqVertexGroupList.size() << " for " << rig.getName() << std::endl; +} + +bool RigTransformSoftware::prepareData(RigGeometry&rig) { + ///find skeleton if not set + if(!rig.getSkeleton() && !rig.getParents().empty()) + { + RigGeometry::FindNearestParentSkeleton finder; + if(rig.getParents().size() > 1) + osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << rig.getName() << " )" << std::endl; + rig.getParents()[0]->accept(finder); + + if(!finder._root.valid()) + { + osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << rig.getName() << " )" << std::endl; + return false; + } + rig.setSkeleton(finder._root.get()); + } + ///get bonemap from skeleton BoneMapVisitor mapVisitor; - geom.getSkeleton()->accept(mapVisitor); - BoneMap bm = mapVisitor.getBoneMap(); - initVertexSetFromBones(bm, geom.getVertexInfluenceSet().getUniqVertexGroupList()); + rig.getSkeleton()->accept(mapVisitor); + BoneMap boneMap = mapVisitor.getBoneMap(); - if (geom.getSourceGeometry()) - geom.copyFrom(*geom.getSourceGeometry()); + /// build minimal set of VertexGroup + buildMinimumUpdateSet(boneMap,rig); + + ///set geom as it source + if (rig.getSourceGeometry()) + rig.copyFrom(*rig.getSourceGeometry()); - osg::Vec3Array* normalSrc = dynamic_cast(geom.getSourceGeometry()->getNormalArray()); - osg::Vec3Array* positionSrc = dynamic_cast(geom.getSourceGeometry()->getVertexArray()); + osg::Vec3Array* normalSrc = dynamic_cast(rig.getSourceGeometry()->getNormalArray()); + osg::Vec3Array* positionSrc = dynamic_cast(rig.getSourceGeometry()->getVertexArray()); if(!(positionSrc) || positionSrc->empty() ) return false; if(normalSrc&& normalSrc->size()!=positionSrc->size()) return false; - - geom.setVertexArray(new osg::Vec3Array); + /// setup Vertex and Normal arrays with copy of sources + rig.setVertexArray(new osg::Vec3Array); osg::Vec3Array* positionDst =new osg::Vec3Array; - geom.setVertexArray(positionDst); + rig.setVertexArray(positionDst); *positionDst=*positionSrc; positionDst->setDataVariance(osg::Object::DYNAMIC); - - if(normalSrc){ + if(normalSrc) { osg::Vec3Array* normalDst =new osg::Vec3Array; *normalDst=*normalSrc; - geom.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX); + rig.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX); normalDst->setDataVariance(osg::Object::DYNAMIC); } @@ -78,7 +181,7 @@ bool RigTransformSoftware::init(RigGeometry& geom) void RigTransformSoftware::operator()(RigGeometry& geom) { if (_needInit) - if (!init(geom)) + if (!prepareData(geom)) return; if (!geom.getSourceGeometry()) { @@ -112,48 +215,3 @@ void RigTransformSoftware::operator()(RigGeometry& geom) } } - -///convert BoneWeight to BonePtrWeight using bonemap -void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexGroupList& vertexgroups) -{ - _uniqInfluenceSet2VertIDList.clear(); - - int size = vertexgroups.size(); - _uniqInfluenceSet2VertIDList.resize(size); - //for (VertexInfluenceSet::UniqVertexGroupList::const_iterator vgit=vertexgroups.begin(); vgit!=vertexgroups.end();vgit++) - for(int i = 0; i < size; i++) - { - const VertexInfluenceSet::VertexGroup& vg = vertexgroups[i]; - int nbBones = vg.getBones().size(); - BonePtrWeightList& boneList = _uniqInfluenceSet2VertIDList[i].getBoneWeights(); - - double sumOfWeight = 0; - for (int b = 0; b < nbBones; b++) - { - const std::string& bname = vg.getBones()[b].getBoneName(); - float weight = vg.getBones()[b].getWeight(); - BoneMap::const_iterator it = map.find(bname); - if (it == map.end() ) - { - if (_invalidInfluence.find(bname) != _invalidInfluence.end()) { - _invalidInfluence[bname] = true; - OSG_WARN << "RigTransformSoftware Bone " << bname << " not found, skip the influence group " <second.get(); - boneList.push_back(BonePtrWeight(bone, weight)); - sumOfWeight += weight; - } - // if a bone referenced by a vertexinfluence is missed it can make the sum less than 1.0 - // so we check it and renormalize the all weight bone - const double threshold = 1e-4; - if (!vg.getBones().empty() && - (sumOfWeight < 1.0 - threshold || sumOfWeight > 1.0 + threshold)) - { - for (int b = 0; b < (int)boneList.size(); b++) - boneList[b].setWeight(boneList[b].getWeight() / sumOfWeight); - } - _uniqInfluenceSet2VertIDList[i].getVertexes() = vg.getVertexes(); - } -} diff --git a/src/osgAnimation/VertexInfluence.cpp b/src/osgAnimation/VertexInfluence.cpp index b1b10fa26..d0bba7599 100644 --- a/src/osgAnimation/VertexInfluence.cpp +++ b/src/osgAnimation/VertexInfluence.cpp @@ -20,77 +20,130 @@ using namespace osgAnimation; -void VertexInfluenceSet::addVertexInfluence(const BoneInfluenceList& v) { _bone2Vertexes.push_back(v); } -const VertexInfluenceSet::VertIDToBoneWeightList& VertexInfluenceSet::getVertexToBoneList() const { return _vertex2Bones;} -// this class manage VertexInfluence database by mesh -// reference bones per vertex ... - -void VertexInfluenceSet::buildVertex2BoneList(unsigned int numvertices) +struct invweight_ordered { - _vertex2Bones.clear(); - _vertex2Bones.reserve(numvertices); - _vertex2Bones.resize(numvertices); - - for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); ++it) + inline bool operator() (const BoneWeight& bw1, const BoneWeight& bw2) { - const BoneInfluenceList& vi = (*it); - int size = vi.size(); - for (int i = 0; i < size; i++) - { - IndexWeight viw = vi[i]; - int index = viw.first; - float weight = viw.second; - if (vi.getName().empty()){ - OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning vertex " << index << " is not assigned to a bone" << std::endl; - } - _vertex2Bones[index].push_back(BoneWeight(vi.getName(), weight)); + if (bw1.getWeight() > bw2.getWeight())return true; + if (bw1.getWeight() < bw2.getWeight())return false; + return(bw1.getBoneName() > PerVertWeights; + std::vector localstore; + localstore.resize(numvert); + for(VertexInfluenceMap::iterator mapit=this->begin(); mapit!=this->end(); ++mapit) { + IndexWeightList &curvecinf=mapit->second; + 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); + } } - - // normalize weight per vertex unsigned int vertid=0; - for (VertIDToBoneWeightList::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it,++vertid) - { - BoneWeightList& bones =*it; - int size = bones.size(); - float sum = 0; - for (int i = 0; i < size; i++) - sum += bones[i].getWeight(); - if (sum < 1e-4) + for(std::vector::iterator itvert=localstore.begin(); itvert!=localstore.end(); ++itvert, ++vertid) { + PerVertWeights & weights=*itvert; + if(weights.first< 1e-4) { - OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " <::iterator itf =weights.second.begin(); itf!=weights.second.end(); ++itf) + **itf*=mult; + } + } + +} +///remove weakest influences in order to fit targetted numbonepervertex +void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize) { + + 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) { + VertexIndexWeight& inf=*curinf; + if( bonename.empty()) { + OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList 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) { + BoneWeightOrdered& bwset=mapit->second; + unsigned int newsize=numbonepervertexnewsize)bwset.erase(*bwset.rbegin()); + if(renormalize){ + for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) + sum+=bwit->getWeight(); + if(sum>1e-4){ + sum=1.0f/sum; + for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) { + VertexInfluence & inf= (*this)[bwit->getBoneName()]; + inf.push_back(VertexIndexWeight(mapit->first, bwit->getWeight()*sum)); + inf.setName(bwit->getBoneName()); + } + } + }else{ + for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) { + VertexInfluence & inf= (*this)[bwit->getBoneName()]; + inf.push_back(VertexIndexWeight(mapit->first,bwit->getWeight())); + inf.setName(bwit->getBoneName()); + } + } } } - +void VertexInfluenceMap::computePerVertexInfluenceList(std::vector& vertex2Bones,unsigned int numvert)const +{ + vertex2Bones.resize(numvert); + for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); + it != end(); + ++it) + { + const IndexWeightList& inflist = it->second; + 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) + { + const VertexIndexWeight &iw = *infit; + const unsigned int &index = iw.getIndex(); + float weight = iw.getWeight(); + vertex2Bones[index].push_back(BoneWeight(it->first, weight));; + } + } +} // sort by name and weight -struct SortByNameAndWeight : public std::less +struct SortByNameAndWeight : public std::less { - bool operator()(const VertexInfluenceSet::BoneWeight& b0, - const VertexInfluenceSet::BoneWeight& b1) const + bool operator()(const BoneWeight& b0, + const BoneWeight& b1) const { if (b0.getBoneName() < b1.getBoneName()) return true; else if (b0.getBoneName() > b1.getBoneName()) return false; - if (b0.getWeight() < b1.getWeight()) - return true; - return false; + return (b0.getWeight() < b1.getWeight()); } }; -struct SortByBoneWeightList : public std::less +struct SortByBoneWeightList : public std::less { - bool operator()(const VertexInfluenceSet::BoneWeightList& b0, - const VertexInfluenceSet::BoneWeightList& b1) const + bool operator()(const BoneWeightList& b0, + const BoneWeightList& b1) const { if (b0.size() < b1.size()) return true; @@ -100,8 +153,7 @@ struct SortByBoneWeightList : public std::less&uniqVertexGroupList,unsigned int numvert)const { - _bone2Vertexes.clear(); - _uniqVertexSetToBoneSet.clear(); -} - -void VertexInfluenceSet::buildUniqVertexGroupList() -{ - _uniqVertexSetToBoneSet.clear(); - + uniqVertexGroupList.clear(); + std::vector vertex2Bones; + computePerVertexInfluenceList(vertex2Bones,numvert); typedef std::map UnifyBoneGroup; UnifyBoneGroup unifyBuffer; unsigned int vertexID=0; - for (VertIDToBoneWeightList::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it,++vertexID) + for (std::vector::iterator it = vertex2Bones.begin(); it != vertex2Bones.end(); ++it,++vertexID) { - BoneWeightList bones = *it; - + BoneWeightList &boneweightlist = *it; // sort the vector to have a consistent key - std::sort(bones.begin(), bones.end(), SortByNameAndWeight()); - + std::sort(boneweightlist.begin(), boneweightlist.end(), SortByNameAndWeight()); // we use the vector as key to differentiate group - UnifyBoneGroup::iterator result = unifyBuffer.find(bones); + UnifyBoneGroup::iterator result = unifyBuffer.find(boneweightlist); if (result == unifyBuffer.end()) - unifyBuffer[bones].setBones(bones); - unifyBuffer[bones].getVertexes().push_back(vertexID); + unifyBuffer[boneweightlist].setBoneWeights(boneweightlist); + unifyBuffer[boneweightlist].vertIDs().push_back(vertexID); } - - _uniqVertexSetToBoneSet.reserve(unifyBuffer.size()); - - + if(vertex2Bones.size()==unifyBuffer.size()) { + OSG_WARN << "VertexInfluenceSet::buildmap is useless no duplicate VertexGroup" << std::endl; + } + uniqVertexGroupList.reserve(unifyBuffer.size()); for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it) { - _uniqVertexSetToBoneSet.push_back(it->second); + uniqVertexGroupList.push_back(it->second); } } - diff --git a/src/osgPlugins/gles/AABBonBoneVisitor.cpp b/src/osgPlugins/gles/AABBonBoneVisitor.cpp index 5b3fc99dd..0ea5302f7 100644 --- a/src/osgPlugins/gles/AABBonBoneVisitor.cpp +++ b/src/osgPlugins/gles/AABBonBoneVisitor.cpp @@ -51,7 +51,7 @@ void ComputeAABBOnBoneVisitor::computeBoundingBoxOnBones() { osg::Vec3Array *vertices = dynamic_cast(rigGeometry->getVertexArray()); if(!vertices) continue; - osgAnimation::BoneInfluenceList vxtInf = (*itMap).second; + osgAnimation::VertexInfluence vxtInf = (*itMap).second; //Expand the boundingBox with each vertex for(unsigned int j = 0; j < vxtInf.size(); j++) { diff --git a/src/osgPlugins/gles/MostInfluencedGeometryByBone b/src/osgPlugins/gles/MostInfluencedGeometryByBone index a5e8c5e97..024d87ddb 100644 --- a/src/osgPlugins/gles/MostInfluencedGeometryByBone +++ b/src/osgPlugins/gles/MostInfluencedGeometryByBone @@ -200,9 +200,9 @@ protected: BoneNameBoneMap::iterator bone_it = boneMap.find(vertexInfluencePair->first); if(bone_it == boneMap.end()) continue; osg::ref_ptr bone = bone_it->second; - const osgAnimation::BoneInfluenceList& vertexInfluence = (*vertexInfluencePair).second; + const osgAnimation::VertexInfluence& vertexInfluence = (*vertexInfluencePair).second; - for(osgAnimation::BoneInfluenceList::const_iterator vertexIndexWeight = vertexInfluence.begin(); vertexIndexWeight != vertexInfluence.end(); ++vertexIndexWeight) { + for(osgAnimation::VertexInfluence::const_iterator vertexIndexWeight = vertexInfluence.begin(); vertexIndexWeight != vertexInfluence.end(); ++vertexIndexWeight) { rigGeometryInfluenceByBoneMap[bone.get()][*rigGeometry].addWeight((*vertexIndexWeight).second); } } diff --git a/src/osgWrappers/deprecated-dotosg/osgAnimation/ReaderWriter.cpp b/src/osgWrappers/deprecated-dotosg/osgAnimation/ReaderWriter.cpp index 78824ad7c..add7f50fd 100644 --- a/src/osgWrappers/deprecated-dotosg/osgAnimation/ReaderWriter.cpp +++ b/src/osgWrappers/deprecated-dotosg/osgAnimation/ReaderWriter.cpp @@ -813,7 +813,7 @@ bool RigGeometry_readLocalData(Object& obj, Input& fr) iteratorAdvanced = true; } - osgAnimation::BoneInfluenceList vi; + osgAnimation::VertexInfluence vi; vi.setName(name); vi.reserve(nbVertexes); for (int j = 0; j < nbVertexes; j++) @@ -827,7 +827,7 @@ bool RigGeometry_readLocalData(Object& obj, Input& fr) fr += 2; iteratorAdvanced = true; } - vi.push_back(osgAnimation::IndexWeight(index, weight)); + vi.push_back(osgAnimation::VertexIndexWeight(index, weight)); } if (fr.matchSequence("}")) { @@ -863,8 +863,8 @@ bool RigGeometry_writeLocalData(const Object& obj, Output& fw) name = "Empty"; fw.indent() << "osgAnimation::VertexInfluence \"" << name << "\" " << it->second.size() << " {" << std::endl; fw.moveIn(); - const osgAnimation::BoneInfluenceList& vi = it->second; - for (osgAnimation::BoneInfluenceList::const_iterator itv = vi.begin(); itv != vi.end(); itv++) + const osgAnimation::VertexInfluence& vi = it->second; + for (osgAnimation::VertexInfluence::const_iterator itv = vi.begin(); itv != vi.end(); itv++) { fw.indent() << itv->first << " " << itv->second << std::endl; } diff --git a/src/osgWrappers/serializers/osgAnimation/RigGeometry.cpp b/src/osgWrappers/serializers/osgAnimation/RigGeometry.cpp index 5259d1e95..10b14d0f1 100644 --- a/src/osgWrappers/serializers/osgAnimation/RigGeometry.cpp +++ b/src/osgWrappers/serializers/osgAnimation/RigGeometry.cpp @@ -14,23 +14,22 @@ static bool readInfluenceMap( osgDB::InputStream& is, osgAnimation::RigGeometry& unsigned int size = is.readSize(); is >> is.BEGIN_BRACKET; for ( unsigned int i=0; i> is.PROPERTY("VertexInfluence"); - is.readWrappedString(name); + is.readWrappedString(bonename); viSize = is.readSize(); is >> is.BEGIN_BRACKET; - - osgAnimation::BoneInfluenceList vi; - vi.setName( name ); + osgAnimation::VertexInfluence vi; + vi.setName( bonename ); vi.reserve( viSize ); for ( unsigned int j=0; j> index >> weight; - vi.push_back( osgAnimation::IndexWeight(index, weight) ); + vi.push_back( osgAnimation::VertexIndexWeight(index, weight) ); } - (*map)[name] = vi; + (*map)[bonename] = vi; is >> is.END_BRACKET; } is >> is.END_BRACKET; @@ -47,14 +46,14 @@ static bool writeInfluenceMap( osgDB::OutputStream& os, const osgAnimation::RigG itr!=map->end(); ++itr ) { std::string name = itr->first; - const osgAnimation::BoneInfluenceList& vi = itr->second; + const osgAnimation::VertexInfluence& vi = itr->second; if ( name.empty() ) name = "Empty"; os << os.PROPERTY("VertexInfluence"); os.writeWrappedString(name); os.writeSize(vi.size()) ; os << os.BEGIN_BRACKET << std::endl; - for ( osgAnimation::BoneInfluenceList::const_iterator vitr=vi.begin(); + for ( osgAnimation::VertexInfluence::const_iterator vitr=vi.begin(); vitr != vi.end(); ++vitr ) { os << vitr->first << vitr->second << std::endl;