diff --git a/include/osg/BoundingSphere b/include/osg/BoundingSphere index 0b62c2cdd..4502e4595 100644 --- a/include/osg/BoundingSphere +++ b/include/osg/BoundingSphere @@ -64,7 +64,7 @@ class BoundingSphereImpl inline bool valid() const { return _radius>=0.0; } inline bool operator == (const BoundingSphereImpl& rhs) const { return _center==rhs._center && _radius==rhs._radius; } - inline bool operator != (const BoundingSphereImpl& rhs) const { return _center!=rhs._center || _radius==rhs._radius; } + inline bool operator != (const BoundingSphereImpl& rhs) const { return _center!=rhs._center || _radius!=rhs._radius; } /** Set the bounding sphere to the given center/radius using floats. */ inline void set(const vec_type& center,value_type radius) diff --git a/include/osgAnimation/MorphTransformHardware b/include/osgAnimation/MorphTransformHardware index b061cccae..650f62efd 100644 --- a/include/osgAnimation/MorphTransformHardware +++ b/include/osgAnimation/MorphTransformHardware @@ -22,6 +22,9 @@ #include #include +///texture unit reserved for morphtarget TBO +#define MORPHTRANSHW_DEFAULTMORPHTEXTUREUNIT 7 + namespace osgAnimation { class MorphGeometry; @@ -39,12 +42,13 @@ namespace osgAnimation virtual void operator()(MorphGeometry&); - inline void setShader(osg::Shader*s){_shader=s;} - inline osg::Shader * getShader()const{return _shader;} + inline void setShader( osg::Shader*s ) { _shader=s; } + inline const osg::Shader * getShader() const{ return _shader; } + inline osg::Shader * getShader() { return _shader; } ///texture unit reserved for morphtarget TBO default is 7 - void setReservedTextureUnit(unsigned int t){_reservedTextureUnit=t;} - unsigned int getReservedTextureUnit() const {return _reservedTextureUnit;} + void setReservedTextureUnit(unsigned int t) { _reservedTextureUnit=t; } + unsigned int getReservedTextureUnit() const { return _reservedTextureUnit;} protected: diff --git a/include/osgAnimation/RigGeometry b/include/osgAnimation/RigGeometry index 805e9c779..dc96c98f4 100644 --- a/include/osgAnimation/RigGeometry +++ b/include/osgAnimation/RigGeometry @@ -145,9 +145,8 @@ namespace osgAnimation osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )" << std::endl; return; } - geom->setSkeleton(finder._root.get()); - geom->getRigTransformImplementation()->prepareData(*geom); + geom->setSkeleton(finder._root.get()); } if(!geom->getSkeleton()) diff --git a/include/osgAnimation/RigTransformHardware b/include/osgAnimation/RigTransformHardware index 2f7ea868b..cf506580f 100644 --- a/include/osgAnimation/RigTransformHardware +++ b/include/osgAnimation/RigTransformHardware @@ -23,6 +23,8 @@ #include #include +#define RIGTRANSHW_DEFAULT_FIRST_VERTATTRIB_TARGETTED 11 + namespace osgAnimation { class RigGeometry; @@ -48,7 +50,8 @@ namespace osgAnimation unsigned int getFirstVertexAttributeTarget()const { return _minAttribIndex;} void setShader(osg::Shader* shader) { _shader = shader; } - osg::Shader* getShader() const { return _shader; } + const osg::Shader* getShader() const { return _shader; } + osg::Shader* getShader() { return _shader; } osg::Vec4Array* getVertexAttrib(unsigned int index); unsigned int getNumVertexAttrib() const {return _boneWeightAttribArrays.size();} @@ -86,6 +89,7 @@ namespace osgAnimation //on first update virtual bool init(RigGeometry& ); + std::vector _perVertexInfluences; }; } diff --git a/include/osgAnimation/RigTransformSoftware b/include/osgAnimation/RigTransformSoftware index ac97f527a..109bf5b85 100644 --- a/include/osgAnimation/RigTransformSoftware +++ b/include/osgAnimation/RigTransformSoftware @@ -40,22 +40,28 @@ namespace osgAnimation //to call when a skeleton is reacheable from the rig to prepare technic data virtual bool prepareData(RigGeometry&); - class BonePtrWeight: std::pair< osg::observer_ptr< Bone >, float> + typedef std::pair LocalBoneIDWeight; + class BonePtrWeight: LocalBoneIDWeight { public: - 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;} + BonePtrWeight(unsigned int id,float weight, Bone*bone=0 ): LocalBoneIDWeight(id,weight), _boneptr(bone){} + BonePtrWeight(const BonePtrWeight &bw2): LocalBoneIDWeight(bw2.getBoneID(),bw2.getWeight()), _boneptr(bw2._boneptr.get()){} inline const float & getWeight() const {return second;} inline void setWeight(float b) {second=b;} + inline const unsigned int & getBoneID() const {return first;} + inline void setBoneID(unsigned int b) {first=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()); + return (first > b1.first); } + ///set Bone pointer + inline const Bone * getBonePtr() const {return _boneptr.get();} + inline void setBonePtr(Bone*b){_boneptr=b;} + protected: + osg::observer_ptr< Bone > _boneptr; }; + typedef std::vector BonePtrWeightList; /// map a set of boneinfluence to a list of vertex indices sharing this set @@ -144,7 +150,6 @@ namespace osgAnimation } } - template inline void computeNormal(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst) { @@ -166,12 +171,14 @@ namespace osgAnimation bool _needInit; + virtual bool init(RigGeometry&); + std::map _invalidInfluence; typedef std::vector VertexGroupList; - VertexGroupList _uniqVertexGroupList; - void buildMinimumUpdateSet(const BoneMap&boneMap,const RigGeometry&rig ); + + void buildMinimumUpdateSet(const RigGeometry&rig ); }; } 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/osg/Program.cpp b/src/osg/Program.cpp index 7092a565a..85c49a37d 100644 --- a/src/osg/Program.cpp +++ b/src/osg/Program.cpp @@ -517,9 +517,10 @@ void Program::apply( osg::State& state ) const // for shader debugging: to minimize performance impact, // optionally validate based on notify level. // TODO: enable this using notify level, or perhaps its own getenv()? +#ifndef __APPLE__ if( osg::isNotifyEnabled(osg::INFO) ) pcp->validateProgram(); - +#endif pcp->useProgram(); state.setLastAppliedProgramObject(pcp); } diff --git a/src/osgAnimation/MorphTransformHardware.cpp b/src/osgAnimation/MorphTransformHardware.cpp index 48119c813..a275d5680 100644 --- a/src/osgAnimation/MorphTransformHardware.cpp +++ b/src/osgAnimation/MorphTransformHardware.cpp @@ -18,14 +18,11 @@ #include #include -///texture unit reserved for morphtarget TBO -#define DEFAULTMORPHTEXTUREUNIT 7 - using namespace osgAnimation; MorphTransformHardware::MorphTransformHardware(): _needInit(true), - _reservedTextureUnit(DEFAULTMORPHTEXTUREUNIT) + _reservedTextureUnit(MORPHTRANSHW_DEFAULTMORPHTEXTUREUNIT) { } diff --git a/src/osgAnimation/RigTransformHardware.cpp b/src/osgAnimation/RigTransformHardware.cpp index c34ec2831..38d592a55 100644 --- a/src/osgAnimation/RigTransformHardware.cpp +++ b/src/osgAnimation/RigTransformHardware.cpp @@ -20,13 +20,11 @@ using namespace osgAnimation; -#define DEFAULT_FIRST_VERTATTRIB_TARGETTED 11 - RigTransformHardware::RigTransformHardware(): _bonesPerVertex (0), _nbVertices (0), _needInit (true), - _minAttribIndex(DEFAULT_FIRST_VERTATTRIB_TARGETTED) + _minAttribIndex(RIGTRANSHW_DEFAULT_FIRST_VERTATTRIB_TARGETTED) {} RigTransformHardware::RigTransformHardware(const RigTransformHardware& rth, const osg::CopyOp& copyop): @@ -77,10 +75,11 @@ typedef std::vector > PerVertexInfList; ///create normalized a set of Vertex Attribs given a PerVertexInfList and return the max num bone per vertex unsigned int createVertexAttribList(const PerVertexInfList & perVertexInfluences, - RigTransformHardware::BoneWeightAttribList& boneWeightAttribArrays){ + RigTransformHardware::BoneWeightAttribList& boneWeightAttribArrays) +{ short boneIndexInVec4; unsigned int vertid = 0, - boneIndexInList; + boneIndexInList; IndexWeightList::size_type maxBonePerVertex = 0; ///build vertex attrib arrays //get maxBonePerVertex @@ -95,32 +94,37 @@ unsigned int createVertexAttribList(const PerVertexInfList & perVertexInfluences return 0; ///create vertex attrib arrays + boneWeightAttribArrays.reserve(nbArray); boneWeightAttribArrays.resize(nbArray); - for(unsigned int j=0; j< nbArray; ++j) + for(unsigned int j = 0; j< nbArray; ++j) { - boneWeightAttribArrays[j] = new osg::Vec4Array(osg::Array::BIND_PER_VERTEX); - boneWeightAttribArrays[j]->resize(perVertexInfluences.size()); + osg::Vec4Array* vecattr = new osg::Vec4Array(osg::Array::BIND_PER_VERTEX); + vecattr->reserve(perVertexInfluences.size()); + vecattr->resize(perVertexInfluences.size()); + boneWeightAttribArrays[j] = vecattr; } ///populate vertex attrib arrays - for(PerVertexInfList::const_iterator vertinfit=perVertexInfluences.begin(); vertinfit != perVertexInfluences.end(); ++vertinfit,++vertid) + for(PerVertexInfList::const_iterator vertinfit = perVertexInfluences.begin(); + vertinfit != perVertexInfluences.end(); + ++vertinfit, ++vertid) { //sum for normalization - float sum=0; + float sum = 0; for(IndexWeightList::const_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: " < 1) - osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << rig.getName() << " )" << std::endl; - rig.getParents()[0]->accept(finder); + _nbVertices = rig.getSourceGeometry()->getVertexArray()->getNumElements(); + const VertexInfluenceMap &vertexInfluenceMap = *rig.getInfluenceMap(); + _perVertexInfluences.reserve(_nbVertices); + _perVertexInfluences.resize(_nbVertices); - if(!finder._root.valid()) + unsigned int localboneid = 0; + for (VertexInfluenceMap::const_iterator boneinflistit = vertexInfluenceMap.begin(); + boneinflistit != vertexInfluenceMap.end(); + ++boneinflistit, ++localboneid) + { + const IndexWeightList& boneinflist = boneinflistit->second; + const std::string& bonename = boneinflistit->first; + + for(IndexWeightList::const_iterator infit = boneinflist.begin(); infit!=boneinflist.end(); ++infit) { - osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << rig.getName() << " )" << std::endl; - return false; + const VertexIndexWeight& iw = *infit; + const unsigned int &index = iw.first; + const float &weight = iw.second; + IndexWeightList & iwlist = _perVertexInfluences[index]; + + if(fabs(weight) > 1e-4) // don't use bone with weight too small + { + iwlist.push_back(VertexIndexWeight(localboneid,weight)); + } + else + { + OSG_WARN << "RigTransformHardware::prepareData Bone " << bonename << " has a weight " << weight << " for vertex " << index << " this bone will not be in the palette" << std::endl; + } } - rig.setSkeleton(finder._root.get()); + } + return true; +} + + +bool RigTransformHardware::buildPalette(const BoneMap& boneMap, const RigGeometry& rig) +{ + + typedef std::map BoneNameCountMap; + _boneWeightAttribArrays.resize(0); + _bonePalette.clear(); + _boneNameToPalette.clear(); + + IndexWeightList::size_type maxBonePerVertex = 0; + BoneNameCountMap boneNameCountMap; + + const VertexInfluenceMap &vertexInfluenceMap = *rig.getInfluenceMap(); + BoneNamePaletteIndex::iterator boneName2PaletteIndex; + + ///create local boneid to paletteindex + unsigned int paletteindex; + std::vector localid2bone; + localid2bone.reserve(vertexInfluenceMap.size()); + for (osgAnimation::VertexInfluenceMap::const_iterator perBoneinfit = vertexInfluenceMap.begin(); + perBoneinfit != vertexInfluenceMap.end(); + ++perBoneinfit) + { + const std::string& bonename = perBoneinfit->first; + + if (bonename.empty()) + { + OSG_WARN << "RigTransformHardware::VertexInfluenceMap contains unamed bone IndexWeightList" << std::endl; + } + BoneMap::const_iterator bmit = boneMap.find(bonename); + if (bmit == boneMap.end() ) + { + OSG_WARN << "RigTransformHardware Bone " << bonename << " not found, skip the influence group " << std::endl; + localid2bone.push_back(-1); + 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(bmit->second); + } + localid2bone.push_back(paletteindex); + } + 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; + + ///set paletteindices + for( std::vector::iterator idwlistit = _perVertexInfluences.begin(); idwlistit!=_perVertexInfluences.end(); ++idwlistit) + { + for( IndexWeightList::iterator idwit = idwlistit->begin(); idwit!=idwlistit->end();) + { + if(localid2bone[idwit->first]<0) + idwit = idwlistit->erase(idwit); + else + { + idwit->first = localid2bone[idwit->first]; + ++idwit; + } + } + } + if( (_bonesPerVertex = createVertexAttribList(_perVertexInfluences, _boneWeightAttribArrays) ) < 1 ) + return false; + + _uniformMatrixPalette = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size()); + + _needInit = true; + return true; +} + +bool RigTransformHardware::init(RigGeometry& rig) +{ + if(_perVertexInfluences.empty()) + { + prepareData(rig); + return false; } if(!rig.getSkeleton()) return false; + BoneMapVisitor mapVisitor; rig.getSkeleton()->accept(mapVisitor); BoneMap boneMap = mapVisitor.getBoneMap(); @@ -172,6 +283,7 @@ bool RigTransformHardware::prepareData(RigGeometry& rig) 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; @@ -181,178 +293,82 @@ bool RigTransformHardware::prepareData(RigGeometry& rig) // copy shallow from source geometry to rig rig.copyFrom(source); - return true; -} + osg::ref_ptr program ; + osg::ref_ptr vertexshader; + osg::ref_ptr stateset = rig.getOrCreateStateSet(); - -bool RigTransformHardware::buildPalette(const BoneMap&boneMap,const RigGeometry&rig) -{ - - typedef std::map BoneNameCountMap; - _nbVertices = 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(_nbVertices); - - unsigned int paletteindex; - for (VertexInfluenceMap::const_iterator boneinflistit = vertexInfluenceMap.begin(); - boneinflistit != vertexInfluenceMap.end(); - ++boneinflistit) + //grab geom source program and vertex shader if _shader is not setted + if(!_shader.valid() && (program = (osg::Program*)stateset->getAttribute(osg::StateAttribute::PROGRAM))) { - 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.first; - const float &weight = iw.second; - IndexWeightList & iwlist = perVertexInfluences[index]; - - if(fabs(weight) > 1e-4) // don't use bone with weight too small + for(unsigned int i = 0; igetNumShaders(); ++i) + if(program->getShader(i)->getType() == osg::Shader::VERTEX) { - iwlist.push_back(VertexIndexWeight(paletteindex,weight)); + vertexshader = program->getShader(i); + program->removeShader(vertexshader); } - else - { - OSG_WARN << "RigTransformHardware::buildPalette Bone " << bonename << " has a weight " << weight << " for vertex " << index << " this bone will not be in the palette" << 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; - + } + 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( (_bonesPerVertex = createVertexAttribList(perVertexInfluences, _boneWeightAttribArrays) ) < 1 ) - return false; - - _uniformMatrixPalette = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size()); - - _needInit = true; - - return true; -} - -bool RigTransformHardware::init(RigGeometry& rig) -{ - //if animdata seams prepared - if(_uniformMatrixPalette.valid()) + if (!vertexshader.valid()) { - osg::ref_ptr program ; - osg::ref_ptr vertexshader; - osg::ref_ptr stateset = rig.getOrCreateStateSet(); + OSG_WARN << "RigTransformHardware can't load VertexShader" << std::endl; + return false; + } - //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_WARN<< "MAX_MATRIX not found in Shader! " << str << std::endl; - } - OSG_INFO << "Shader " << str << std::endl; - } - - unsigned int nbAttribs = getNumVertexAttrib(); - for (unsigned int i = 0; i < nbAttribs; i++) + // 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 << "boneWeight" << i; - program->addBindAttribLocation(ss.str(), _minAttribIndex + i); - rig.setVertexAttribArray(_minAttribIndex + i, getVertexAttrib(i)); - OSG_INFO << "set vertex attrib " << ss.str() << std::endl; + ss << getMatrixPaletteUniform()->getNumElements(); + str.replace(start, toreplace.size(), ss.str()); + vertexshader->setShaderSource(str); } - - program->addShader(vertexshader.get()); - - stateset->removeUniform("nbBonesPerVertex"); - stateset->addUniform(new osg::Uniform("nbBonesPerVertex",_bonesPerVertex)); - - stateset->removeUniform("matrixPalette"); - stateset->addUniform(_uniformMatrixPalette); - - stateset->setAttribute(program.get()); - - _needInit = false; - return true; + else + { + OSG_WARN<< "MAX_MATRIX not found in Shader! " << str << std::endl; + } + OSG_INFO << "Shader " << str << std::endl; } - else prepareData(rig); - return false; + + unsigned int nbAttribs = getNumVertexAttrib(); + for (unsigned int i = 0; i < nbAttribs; i++) + { + std::stringstream ss; + ss << "boneWeight" << i; + program->addBindAttribLocation(ss.str(), _minAttribIndex + i); + rig.setVertexAttribArray(_minAttribIndex + 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->setAttribute(program.get()); + + _needInit = false; + return true; } + void RigTransformHardware::operator()(RigGeometry& geom) { if (_needInit) diff --git a/src/osgAnimation/RigTransformSoftware.cpp b/src/osgAnimation/RigTransformSoftware.cpp index ccb1a0a11..955f42424 100644 --- a/src/osgAnimation/RigTransformSoftware.cpp +++ b/src/osgAnimation/RigTransformSoftware.cpp @@ -36,51 +36,45 @@ RigTransformSoftware::RigTransformSoftware(const RigTransformSoftware& rts,const } -typedef std::vector BonePtrWeightList; - -void RigTransformSoftware::buildMinimumUpdateSet( const BoneMap&boneMap, const RigGeometry&rig ){ - +void RigTransformSoftware::buildMinimumUpdateSet( const RigGeometry&rig ) +{ ///1 Create Index2Vec - const VertexInfluenceMap &vertexInfluenceMap=*rig.getInfluenceMap(); + unsigned int nbVertices=rig.getSourceGeometry()->getVertexArray()->getNumElements(); + const VertexInfluenceMap &vertexInfluenceMap = *rig.getInfluenceMap(); std::vector perVertexInfluences; - perVertexInfluences.resize(rig.getSourceGeometry()->getVertexArray()->getNumElements()); + perVertexInfluences.reserve(nbVertices); + perVertexInfluences.resize(nbVertices); + unsigned int vimapBoneID = 0; for (osgAnimation::VertexInfluenceMap::const_iterator perBoneinfit = vertexInfluenceMap.begin(); perBoneinfit != vertexInfluenceMap.end(); - ++perBoneinfit) + ++perBoneinfit,++vimapBoneID) { const IndexWeightList& inflist = perBoneinfit->second; const std::string& bonename = perBoneinfit->first; - if (bonename.empty()) { + 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) + for(IndexWeightList::const_iterator infit = inflist.begin(); infit!=inflist.end(); ++infit) { const VertexIndexWeight &iw = *infit; const unsigned int &index = iw.first; float weight = iw.second; - perVertexInfluences[index].push_back(BonePtrWeight(bone, weight)); + perVertexInfluences[index].push_back(BonePtrWeight(vimapBoneID, weight)); } } // normalize _vertex2Bones weight per vertex - unsigned vertexID=0; - for (std::vector::iterator it = perVertexInfluences.begin(); it != perVertexInfluences.end(); ++it, ++vertexID) + 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) + for(BonePtrWeightList::iterator bwit = bones.begin(); bwit!=bones.end(); ++bwit) sum += bwit->getWeight(); if (sum < 1e-4) { @@ -89,7 +83,7 @@ void RigTransformSoftware::buildMinimumUpdateSet( const BoneMap&boneMap, const R else { float mult = 1.0/sum; - for(BonePtrWeightList::iterator bwit=bones.begin();bwit!=bones.end();++bwit) + for(BonePtrWeightList::iterator bwit = bones.begin(); bwit != bones.end(); ++bwit) bwit->setWeight(bwit->getWeight() * mult); } } @@ -100,8 +94,10 @@ void RigTransformSoftware::buildMinimumUpdateSet( const BoneMap&boneMap, const R typedef std::map UnifyBoneGroup; UnifyBoneGroup unifyBuffer; - vertexID=0; - for (std::vector::iterator perVertinfit = perVertexInfluences.begin(); perVertinfit!=perVertexInfluences.end(); ++perVertinfit,++vertexID) + 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 @@ -123,70 +119,114 @@ void RigTransformSoftware::buildMinimumUpdateSet( const BoneMap&boneMap, const R 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()); - } - if(!rig.getSkeleton()) - return false; - ///get bonemap from skeleton - BoneMapVisitor mapVisitor; - rig.getSkeleton()->accept(mapVisitor); - BoneMap boneMap = mapVisitor.getBoneMap(); - - /// build minimal set of VertexGroup - buildMinimumUpdateSet(boneMap,rig); +bool RigTransformSoftware::prepareData(RigGeometry&rig) +{ ///set geom as it source if (rig.getSourceGeometry()) rig.copyFrom(*rig.getSourceGeometry()); - 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()) + if(normalSrc && normalSrc->size() != positionSrc->size()) return false; /// setup Vertex and Normal arrays with copy of sources rig.setVertexArray(new osg::Vec3Array); - osg::Vec3Array* positionDst =new osg::Vec3Array; + osg::Vec3Array* positionDst = new osg::Vec3Array; rig.setVertexArray(positionDst); - *positionDst=*positionSrc; + *positionDst = *positionSrc; positionDst->setDataVariance(osg::Object::DYNAMIC); - if(normalSrc) { - osg::Vec3Array* normalDst =new osg::Vec3Array; - *normalDst=*normalSrc; + if(normalSrc) + { + osg::Vec3Array* normalDst = new osg::Vec3Array; + *normalDst = *normalSrc; rig.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX); normalDst->setDataVariance(osg::Object::DYNAMIC); } - _needInit = false; + /// build minimal set of VertexGroup + buildMinimumUpdateSet(rig); + return true; } +bool RigTransformSoftware::init(RigGeometry&rig) +{ + ///test if dataprepared + if(_uniqVertexGroupList.empty()) + { + prepareData(rig); + return false; + } + + if(!rig.getSkeleton()) + return false; + ///get bonemap from skeleton + BoneMapVisitor mapVisitor; + rig.getSkeleton()->accept(mapVisitor); + BoneMap boneMap = mapVisitor.getBoneMap(); + VertexInfluenceMap & vertexInfluenceMap = *rig.getInfluenceMap(); + + ///create local bonemap + std::vector localid2bone; + localid2bone.reserve(vertexInfluenceMap.size()); + for (osgAnimation::VertexInfluenceMap::const_iterator perBoneinfit = vertexInfluenceMap.begin(); + perBoneinfit != vertexInfluenceMap.end(); + ++perBoneinfit) + { + 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; + } + + localid2bone.push_back(0); + continue; + } + Bone* bone = bmit->second.get(); + localid2bone.push_back(bone); + } + + ///fill bone ptr in the _uniqVertexGroupList + for(VertexGroupList::iterator itvg = _uniqVertexGroupList.begin(); itvg != _uniqVertexGroupList.end(); ++itvg) + { + VertexGroup& uniq = *itvg; + for(BonePtrWeightList::iterator bwit= uniq.getBoneWeights().begin(); bwit != uniq.getBoneWeights().end(); ) + { + Bone * b = localid2bone[bwit->getBoneID()]; + if(!b) + bwit = uniq.getBoneWeights().erase(bwit); + else + bwit++->setBonePtr(b); + } + } + + _needInit = false; + + return true; +} void RigTransformSoftware::operator()(RigGeometry& geom) { if (_needInit) - if (!prepareData(geom)) + if (!init(geom)) return; - if (!geom.getSourceGeometry()) { + if (!geom.getSourceGeometry()) + { OSG_WARN << this << " RigTransformSoftware no source geometry found on RigGeometry" << std::endl; return; } @@ -209,11 +249,11 @@ void RigTransformSoftware::operator()(RigGeometry& geom) if (normalSrc ) { - computeNormal(geom.getMatrixFromSkeletonToGeometry(), - geom.getInvMatrixFromSkeletonToGeometry(), - &normalSrc->front(), - &normalDst->front()); - normalDst->dirty(); + computeNormal(geom.getMatrixFromSkeletonToGeometry(), + geom.getInvMatrixFromSkeletonToGeometry(), + &normalSrc->front(), + &normalDst->front()); + normalDst->dirty(); } } diff --git a/src/osgAnimation/VertexInfluence.cpp b/src/osgAnimation/VertexInfluence.cpp index 3c2c50c42..42ca1f254 100644 --- a/src/osgAnimation/VertexInfluence.cpp +++ b/src/osgAnimation/VertexInfluence.cpp @@ -14,6 +14,8 @@ */ #include +#include +#include #include #include #include @@ -27,27 +29,33 @@ struct invweight_ordered { if (bw1.second > bw2.second)return true; if (bw1.second < bw2.second)return false; - return(bw1.first > 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; + 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); } } - unsigned int vertid=0; - for(std::vector::iterator itvert=localstore.begin(); itvert!=localstore.end(); ++itvert, ++vertid) { - PerVertWeights & weights=*itvert; + unsigned int vertid = 0; + for(std::vector::iterator itvert = localstore.begin(); + itvert != localstore.end(); + ++itvert, ++vertid) + { + PerVertWeights & weights = *itvert; if(weights.first< 1e-4) { OSG_WARN << "VertexInfluenceMap::normalize warning the vertex " <::iterator itf =weights.second.begin(); itf!=weights.second.end(); ++itf) - **itf*=mult; + for (std::vector::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) { +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) + 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()) { + 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::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) { - BoneWeightOrdered& bwset=mapit->second; - unsigned int newsize=numbonepervertex::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->second; - if(sum>1e-4){ - sum=1.0f/sum; - for(BoneWeightOrdered::iterator bwit=bwset.begin(); bwit!=bwset.end(); ++bwit) { - VertexInfluence & inf= (*this)[bwit->first]; + if(renormalize) + { + for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit) + sum += bwit->second; + if(sum > 1e-4) + { + sum = 1.0f/sum; + 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) { - VertexInfluence & inf= (*this)[bwit->first]; + } + 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,16 +126,15 @@ 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(); - it != end(); - ++it) + 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) + for(IndexWeightList::const_iterator infit = inflist.begin(); infit != inflist.end(); ++infit) { const VertexIndexWeight &iw = *infit; const unsigned int &index = iw.first; @@ -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); } @@ -162,7 +179,7 @@ struct SortByBoneWeightList : public std::less return false; } }; -void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector& uniqVertexGroupList, unsigned int numvert)const +void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector& uniqVertexGroupList, unsigned int numvert) const { uniqVertexGroupList.clear(); std::vector vertex2Bones; @@ -170,7 +187,7 @@ void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector& typedef std::map UnifyBoneGroup; UnifyBoneGroup unifyBuffer; - unsigned int vertexID=0; + unsigned int vertexID = 0; for (std::vector::iterator it = vertex2Bones.begin(); it != vertex2Bones.end(); ++it,++vertexID) { BoneWeightList &boneweightlist = *it; @@ -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; numchild < bone2rm->getNumChildren(); 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; + } + +} diff --git a/src/osgWrappers/serializers/osgAnimation/RigTransform.cpp b/src/osgWrappers/serializers/osgAnimation/RigTransform.cpp index 8b1197f83..5b69cdcd1 100644 --- a/src/osgWrappers/serializers/osgAnimation/RigTransform.cpp +++ b/src/osgWrappers/serializers/osgAnimation/RigTransform.cpp @@ -2,7 +2,8 @@ #include #include #include -#include + #include + #include #include #include @@ -22,7 +23,13 @@ namespace wrap_osgAnimationRigTransformHardWare{ REGISTER_OBJECT_WRAPPER( osgAnimation_RigTransformHardware, new osgAnimation::RigTransformHardware, osgAnimation::RigTransformHardware, - "osg::Object osgAnimation::RigTransform osgAnimation::RigTransformHardware" ){} + "osg::Object osgAnimation::RigTransform osgAnimation::RigTransformHardware" ){ + { + UPDATE_TO_VERSION_SCOPED(150) + ADD_OBJECT_SERIALIZER(Shader, osg::Shader, NULL); + ADD_UINT_SERIALIZER(FirstVertexAttributeTarget, RIGTRANSHW_DEFAULT_FIRST_VERTATTRIB_TARGETTED); + } + } } namespace wrap_osgAnimationMorphTransform{ @@ -37,3 +44,15 @@ namespace wrap_osgAnimationMorphTransformSoftWare{ osgAnimation::MorphTransformSoftware, "osg::Object osgAnimation::MorphTransform osgAnimation::MorphTransformSoftware" ){} } +namespace wrap_osgAnimationMorphTransformHardware{ + REGISTER_OBJECT_WRAPPER( osgAnimation_MorphTransformHardware, + new osgAnimation::MorphTransformHardware, + osgAnimation::MorphTransformHardware, + "osg::Object osgAnimation::MorphTransform osgAnimation::MorphTransformHardware" ){ + { + UPDATE_TO_VERSION_SCOPED(150) + ADD_OBJECT_SERIALIZER(Shader, osg::Shader, NULL); + ADD_UINT_SERIALIZER(ReservedTextureUnit, MORPHTRANSHW_DEFAULTMORPHTEXTUREUNIT); + } + } +}