make preparedata skeleton independant (as it was with the Rig::buildInfluenceSet)

no more divergence with master i think
This commit is contained in:
Julien Valentin 2017-09-03 17:37:06 +02:00
parent 381c2150d4
commit 041a2a6e72
5 changed files with 290 additions and 236 deletions

View File

@ -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())

View File

@ -89,6 +89,7 @@ namespace osgAnimation
//on first update
virtual bool init(RigGeometry& );
std::vector<IndexWeightList> _perVertexInfluences;
};
}

View File

@ -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<unsigned int, float> 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<BonePtrWeight> BonePtrWeightList;
/// map a set of boneinfluence to a list of vertex indices sharing this set
@ -144,7 +150,6 @@ namespace osgAnimation
}
}
template <class V>
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<std::string,bool> _invalidInfluence;
typedef std::vector<VertexGroup> VertexGroupList;
VertexGroupList _uniqVertexGroupList;
void buildMinimumUpdateSet(const BoneMap&boneMap,const RigGeometry&rig );
void buildMinimumUpdateSet(const RigGeometry&rig );
};
}

View File

@ -75,7 +75,8 @@ typedef std::vector<std::vector<VertexIndexWeight> > 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;
@ -110,7 +111,7 @@ unsigned int createVertexAttribList(const PerVertexInfList & perVertexInfluences
if(sum< 1e-4)
{
OSG_WARN << "RigTransformHardware::buildPalette Warning: vertex with zero sum weights: " <<vertid<< std::endl;
OSG_WARN << "RigTransformHardware::createVertexAttribList Warning: vertex with zero sum weights: " <<vertid<< std::endl;
return false;
}
else
@ -145,22 +146,128 @@ unsigned int createVertexAttribList(const PerVertexInfList & perVertexInfluences
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);
_nbVertices = rig.getSourceGeometry()->getVertexArray()->getNumElements();
const VertexInfluenceMap &vertexInfluenceMap = *rig.getInfluenceMap();
_perVertexInfluences.resize(_nbVertices);
if(!finder._root.valid())
unsigned int localboneid=0;
for (VertexInfluenceMap::const_iterator boneinflistit = vertexInfluenceMap.begin();
boneinflistit != vertexInfluenceMap.end();
++boneinflistit, ++localboneid)
{
osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << rig.getName() << " )" << std::endl;
return false;
const IndexWeightList& boneinflist = boneinflistit->second;
const std::string& bonename = boneinflistit->first;
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
{
iwlist.push_back(VertexIndexWeight(localboneid,weight));
}
rig.setSkeleton(finder._root.get());
else
{
OSG_WARN << "RigTransformHardware::prepareData Bone " << bonename << " has a weight " << weight << " for vertex " << index << " this bone will not be in the palette" << std::endl;
}
}
}
return true;
}
bool RigTransformHardware::buildPalette(const BoneMap&boneMap,const RigGeometry&rig)
{
typedef std::map<std::string, int> 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<int> 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<IndexWeightList>::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();
@ -179,99 +286,6 @@ bool RigTransformHardware::prepareData(RigGeometry& rig)
// copy shallow from source geometry to rig
rig.copyFrom(source);
return true;
}
bool RigTransformHardware::buildPalette(const BoneMap&boneMap,const RigGeometry&rig)
{
typedef std::map<std::string, int> 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<IndexWeightList > perVertexInfluences;
perVertexInfluences.resize(_nbVertices);
unsigned int paletteindex;
for (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.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(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;
}
}
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;
}
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())
{
osg::ref_ptr<osg::Program> program ;
osg::ref_ptr<osg::Shader> vertexshader;
osg::ref_ptr<osg::StateSet> stateset = rig.getOrCreateStateSet();
@ -299,7 +313,6 @@ bool RigTransformHardware::init(RigGeometry& rig)
else vertexshader=_shader;
}
if (!vertexshader.valid())
{
OSG_WARN << "RigTransformHardware can't load VertexShader" << std::endl;
@ -348,9 +361,7 @@ bool RigTransformHardware::init(RigGeometry& rig)
_needInit = false;
return true;
}
else prepareData(rig);
return false;
}
void RigTransformHardware::operator()(RigGeometry& geom)
{
if (_needInit)

View File

@ -38,39 +38,31 @@ RigTransformSoftware::RigTransformSoftware(const RigTransformSoftware& rts,const
typedef std::vector<RigTransformSoftware::BonePtrWeight> BonePtrWeightList;
void RigTransformSoftware::buildMinimumUpdateSet( const BoneMap&boneMap, const RigGeometry&rig ){
void RigTransformSoftware::buildMinimumUpdateSet( const RigGeometry&rig )
{
///1 Create Index2Vec<BoneWeight>
const VertexInfluenceMap &vertexInfluenceMap=*rig.getInfluenceMap();
std::vector<BonePtrWeightList> perVertexInfluences;
perVertexInfluences.resize(rig.getSourceGeometry()->getVertexArray()->getNumElements());
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)
{
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));
}
}
@ -123,37 +115,13 @@ 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())
bool RigTransformSoftware::prepareData(RigGeometry&rig)
{
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);
///set geom as it source
if (rig.getSourceGeometry())
rig.copyFrom(*rig.getSourceGeometry());
osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(rig.getSourceGeometry()->getNormalArray());
osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(rig.getSourceGeometry()->getVertexArray());
@ -169,24 +137,92 @@ bool RigTransformSoftware::prepareData(RigGeometry&rig) {
*positionDst=*positionSrc;
positionDst->setDataVariance(osg::Object::DYNAMIC);
if(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<Bone*> 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;
}