From 3efaccb2980eeb7302f403d63b17e11f570ddb11 Mon Sep 17 00:00:00 2001 From: Julien Valentin Date: Mon, 28 Aug 2017 15:41:14 +0200 Subject: [PATCH] add prepareData for RigTransformHW --- include/osgAnimation/RigTransformHardware | 9 +- src/osgAnimation/RigTransformHardware.cpp | 284 +++++++++++++++++++++- 2 files changed, 285 insertions(+), 8 deletions(-) diff --git a/include/osgAnimation/RigTransformHardware b/include/osgAnimation/RigTransformHardware index 28330e87e..4c2aa1875 100644 --- a/include/osgAnimation/RigTransformHardware +++ b/include/osgAnimation/RigTransformHardware @@ -43,7 +43,7 @@ namespace osgAnimation typedef std::map BoneNamePaletteIndex; typedef std::vector MatrixPalette; - struct IndexWeightEntry + /*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){} @@ -52,7 +52,7 @@ namespace osgAnimation const float &getWeight() const { return _boneWeight; } unsigned int _boneIndex; float _boneWeight; - }; + };*/ osg::Vec4Array* getVertexAttrib(unsigned int index); @@ -68,6 +68,8 @@ namespace osgAnimation virtual void operator()(RigGeometry&); + virtual bool prepareData(RigGeometry& ); + void setShader(osg::Shader*); const BoneNamePaletteIndex& getBoneNameToPalette() { @@ -89,6 +91,9 @@ namespace osgAnimation osg::ref_ptr _shader; bool _needInit; + + bool buildPalette(BoneMap&boneMap ,RigGeometry&rig); + }; } diff --git a/src/osgAnimation/RigTransformHardware.cpp b/src/osgAnimation/RigTransformHardware.cpp index ad15c31e6..dc67533ae 100644 --- a/src/osgAnimation/RigTransformHardware.cpp +++ b/src/osgAnimation/RigTransformHardware.cpp @@ -76,7 +76,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; +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) @@ -111,7 +111,7 @@ bool RigTransformHardware::createPalette(unsigned int nbVertexes, const BoneMap { boneNameCountMap[bw.getBoneName()]++; bonesForThisVertex++; // count max number of bones per vertexes - vertexIndexWeight[vertexID].push_back(IndexWeightEntry(boneName2PaletteIndex->second,bw.getWeight())); + vertexIndexWeight[vertexID].push_back(IndexWeight(boneName2PaletteIndex->second,bw.getWeight())); } else { @@ -125,7 +125,7 @@ bool RigTransformHardware::createPalette(unsigned int nbVertexes, const BoneMap bonesForThisVertex++; _boneNameToPalette[bw.getBoneName()] = _bonePalette.size() ; - vertexIndexWeight[vertexID].push_back(IndexWeightEntry(_bonePalette.size(),bw.getWeight())); + vertexIndexWeight[vertexID].push_back(IndexWeight(_bonePalette.size(),bw.getWeight())); _bonePalette.push_back(bonebyname->second); } } @@ -168,8 +168,12 @@ 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) { + +//void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightList& _vertexIndexMatrixWeightList, RigTransformHardware::BoneWeightAttribList& boneWeightAttribArrays) +//{ unsigned int nbVertices= rig.getNumVertexes(); unsigned int maxbonepervertex=rig.getNumBonesPerVertex(); unsigned int nbArray = static_cast(ceilf( ((float)maxbonepervertex) * 0.5f)); @@ -195,7 +199,7 @@ void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightLis (*array)[j][1 + boneIndexInVec4] = 0; if (boneIndexInList < maxbonepervertex) { - float boneIndex = static_cast(_vertexIndexMatrixWeightList[j][boneIndexInList].getBoneIndex()); + float boneIndex = static_cast(_vertexIndexMatrixWeightList[j][boneIndexInList].getIndex()); float boneWeight = _vertexIndexMatrixWeightList[j][boneIndexInList].getWeight(); // fill the vec4 (*array)[j][0 + boneIndexInVec4] = boneIndex; @@ -219,6 +223,274 @@ void RigTransformHardware::setShader(osg::Shader* shader) _shader = shader; } +bool RigTransformHardware::prepareData(RigGeometry& rig) +{ + 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()); + } + BoneMapVisitor mapVisitor; + rig.getSkeleton()->accept(mapVisitor); + BoneMap boneMap = mapVisitor.getBoneMap(); + + 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); + + //if (!createPalette(positionSrc->size(),bm,geom.getVertexInfluenceSet().getVertexToBoneWeightList())) return false; + + 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) { + ///perhaps remanance from previous init (if saved after init) so reload shader + /* OSG_WARN << str << std::endl; + vertexshader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"skinning.vert"); + if (!vertexshader.valid()) { + OSG_WARN << "RigTransformHardware can't load VertexShader" << std::endl; + return false; + } + str = vertexshader->getShaderSource(); + start = str.find(toreplace); + // _uniformMatrixPalette=stateset->getUniform("matrixPalette"); + 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; + } + _needInit = false; + return true;*/ + } + 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; + 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(getMatrixPaletteUniform()); + + stateset->removeAttribute(osg::StateAttribute::PROGRAM); + if(!stateset->getAttribute(osg::StateAttribute::PROGRAM)) + stateset->setAttributeAndModes(program.get()); + + _needInit = false; + return true; +} +void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightList&_vertexIndexMatrixWeightList,RigTransformHardware::BoneWeightAttribList & boneWeightAttribArrays); + +bool RigTransformHardware::buildPalette(BoneMap&boneMap ,RigGeometry&rig) { + + _nbVertexes = rig.getVertexArray()->getNumElements(); + unsigned int maxBonePerVertex=0; + + typedef std::pair FloatInt; + std::vector< FloatInt > sums;///stat totalweight nbref + sums.resize(_nbVertexes); + + typedef std::map BoneNameCountMap; + _bonePalette.clear(); + _boneNameToPalette.clear(); + BoneNameCountMap boneNameCountMap; + + VertexInfluenceMap *vertexInfluenceMap=rig.getInfluenceMap(); + BoneNamePaletteIndex::iterator boneName2PaletteIndex; + _boneWeightAttribArrays.resize(0); + + // init temp vertex attribute data + VertexIndexWeightList vertexIndexWeight; + vertexIndexWeight.resize(_nbVertexes); + + for (osgAnimation::VertexInfluenceMap::iterator it = vertexInfluenceMap->begin(); + it != vertexInfluenceMap->end(); + ++it) + { + const BoneInfluenceList& boneinflist = it->second; + for(BoneInfluenceList::const_iterator infit = boneinflist.begin(); infit!=boneinflist.end(); ++infit) + { + const IndexWeight& iw = *infit; + const unsigned int &index = iw.getIndex(); + const float &weight = iw.getWeight(); + + FloatInt &sum=sums[index]; + unsigned int arrayid=sum.second/2; + unsigned short inx=2*(sum.second&1); + + if (boneinflist.getBoneName().empty()) { + OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning vertex " << index << " is not assigned to a bone" << std::endl; + } + + //_vertex2Bones[index].push_back(VertexInfluenceSet::BoneWeight(vi.getName(), weight));; + + if(fabs(weight) > 1e-4) // don't use bone with weight too small + { + if ((boneName2PaletteIndex= _boneNameToPalette.find(boneinflist.getBoneName())) != _boneNameToPalette.end()) + { + boneNameCountMap[boneinflist.getBoneName()]++; + vertexIndexWeight[index].push_back(IndexWeight(boneName2PaletteIndex->second,weight)); + } + else + { + BoneMap::const_iterator bonebyname; + if ((bonebyname=boneMap.find(boneinflist.getBoneName())) == boneMap.end()) + { + OSG_WARN << "RigTransformHardware::createPalette can't find bone " << boneinflist.getBoneName() << "in skeleton bonemap: skip this influence" << std::endl; + continue; + } + boneNameCountMap[boneinflist.getBoneName()] = 1; // for stats + + _boneNameToPalette[boneinflist.getBoneName()] = _bonePalette.size() ; + vertexIndexWeight[index].push_back(IndexWeight(_bonePalette.size(),weight)); + _bonePalette.push_back(bonebyname->second); + sum.first+=weight; + ++sum.second; + } + } + else + { + OSG_WARN << "RigTransformHardware::createPalette Bone " << boneinflist.getBoneName() << " has a weight " << weight << " for vertex " << index << " this bone will not be in the palette" << std::endl; + } + maxBonePerVertex = osg::maximum(maxBonePerVertex, sum.second); + + } + 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; + _uniformMatrixPalette = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size()); + + createVertexAttribList(*this,vertexIndexWeight,this->_boneWeightAttribArrays); + // normalize weight per vertex +///..assume not sum=0 + + /* for(BoneWeightAttribList::iterator attribit=_boneWeightAttribArrays.begin();attribit!=_boneWeightAttribArrays.end();++attribit){ + std::vector< std::pair >::iterator countit=sums.begin(); + for(osg::Vec4Array::iterator vert=attribit->get()->begin();vert!=attribit->get()->end();++vert,++countit){ + osg::Vec4& v=*vert; + v[1]/=countit->first; + v[3]/=countit->first; + } + + } + */ + /* unsigned int vertexID=0; + for (VertIDToBoneWeightList::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it,++vertexID) + { + BoneWeightList& bones = *it; + int size = bones.size(); + if (sums[vertexID].first < 1e-4) + { + OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << it->first << " seems to have 0 weight, skip normalize for this vertex" << std::endl; + } + else + { + float mult = 1.0/sums[vertexID].first ; + for (int i = 0; i < size; i++) + bones[i].setWeight(bones[i].getWeight() * mult); + } + } + */ +return true; +} bool RigTransformHardware::init(RigGeometry& geom) { if (!geom.getSkeleton()) @@ -310,13 +582,13 @@ bool RigTransformHardware::init(RigGeometry& geom) } 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());