diff --git a/include/osgAnimation/AnimationManagerBase b/include/osgAnimation/AnimationManagerBase index bdc0c5c89..15b4617ab 100644 --- a/include/osgAnimation/AnimationManagerBase +++ b/include/osgAnimation/AnimationManagerBase @@ -42,6 +42,16 @@ namespace osgAnimation const AnimationList& getAnimationList() const { return _animations;} AnimationList& getAnimationList() { return _animations;} + //uniformisation of the API + inline Animation * getRegisteredAnimation(unsigned int i){return _animations[i].get();} + inline unsigned int getNumRegisteredAnimations()const{return _animations.size();} + inline void addRegisteredAnimation(Animation* animation){ + _needToLink = true; + _animations.push_back(animation); + buildTargetReference(); + } + void removeRegisteredAnimation(Animation* animation); + /** Callback method called by the NodeVisitor when visiting a node.*/ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); diff --git a/include/osgAnimation/MorphGeometry b/include/osgAnimation/MorphGeometry index 1a242efd7..e8c89d22d 100644 --- a/include/osgAnimation/MorphGeometry +++ b/include/osgAnimation/MorphGeometry @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -59,7 +60,10 @@ namespace osgAnimation virtual const char* libraryName() const { return "osgAnimation"; } virtual const char* className() const { return "MorphGeometry"; } - virtual void transformSoftwareMethod(); + // set implementation of rig method + void setMorphTransformImplementation(MorphTransform*); + MorphTransform* getMorphTransformImplementation(); + const MorphTransform* getMorphTransformImplementation() const { return _rigTransformImplementation.get(); } /** Set the morphing method. */ void setMethod(Method method) { _method = method; } @@ -71,6 +75,30 @@ namespace osgAnimation /** Get the flag for morphing normals. */ inline bool getMorphNormals() const { return _morphNormals; } + /** Get the list of MorphTargets.*/ + 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; } + + /** Return the \c MorphTarget at position \c i.*/ + inline const MorphTarget& getMorphTarget( unsigned int i ) const { return _morphTargets[i]; } + + /** Return the \c MorphTarget at position \c i.*/ + inline MorphTarget& getMorphTarget( unsigned int i ) { return _morphTargets[i]; } + + /** Set source of vertices for this morph geometry */ + inline void setVertexSource(osg::Vec3Array *v){ _positionSource=v;} + + /** Get source of vertices for this morph geometry */ + inline osg::Vec3Array * getVertexSource()const{return _positionSource;} + + /** Set source of normals for this morph geometry */ + inline void setNormalSource(osg::Vec3Array *n){ _normalSource=n;} + + /** Get source of normals for this morph geometry */ + inline osg::Vec3Array * getNormalSource()const{return _normalSource;} + /** Add a \c MorphTarget to the \c MorphGeometry. * If \c MorphTarget is not \c NULL and is not contained in the \c MorphGeometry * then increment its reference count, add it to the MorphTargets list and @@ -101,6 +129,7 @@ namespace osgAnimation } + /** update a morph target at index setting its current weight to morphWeight */ void setWeight(unsigned int index, float morphWeight) { if (index < _morphTargets.size()) @@ -111,29 +140,20 @@ namespace osgAnimation } /** Set the MorphGeometry dirty.*/ - void dirty() { _dirty = true; } + inline void dirty(bool b=true) { _dirty = b; } + inline bool isDirty()const { return _dirty; } - /** Get the list of MorphTargets.*/ - 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; } - - /** Return the \c MorphTarget at position \c i.*/ - inline const MorphTarget& getMorphTarget( unsigned int i ) const { return _morphTargets[i]; } - - /** Return the \c MorphTarget at position \c i.*/ - inline MorphTarget& getMorphTarget( unsigned int i ) { return _morphTargets[i]; } protected: + osg::ref_ptr _rigTransformImplementation; /// Do we need to recalculate the morphed geometry? bool _dirty; Method _method; MorphTargetList _morphTargets; - std::vector _positionSource; - std::vector _normalSource; + osg::ref_ptr _positionSource; + osg::ref_ptr _normalSource; /// Do we also morph between normals? bool _morphNormals; @@ -195,7 +215,13 @@ namespace osgAnimation if (!geom) return; - geom->transformSoftwareMethod(); + if (!geom->getMorphTransformImplementation()) + { + geom->setMorphTransformImplementation( new MorphTransformSoftware); + } + + MorphTransform& implementation = *geom->getMorphTransformImplementation(); + (implementation)(*geom); } }; diff --git a/include/osgAnimation/MorphTransformSoftware b/include/osgAnimation/MorphTransformSoftware new file mode 100644 index 000000000..8ac451b38 --- /dev/null +++ b/include/osgAnimation/MorphTransformSoftware @@ -0,0 +1,45 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. + */ + +#ifndef OSGANIMATION_MORPHTRANSFORM_SOFTWARE +#define OSGANIMATION_MORPHTRANSFORM_SOFTWARE 1 + +#include +#include +#include +#include + +namespace osgAnimation +{ + + class MorphGeometry; + + /// This class manage format for software morphing + class OSGANIMATION_EXPORT MorphTransformSoftware : public MorphTransform + { + public: + MorphTransformSoftware():_needInit(true){} + MorphTransformSoftware(const MorphTransformSoftware& rts,const osg::CopyOp& copyop): MorphTransform(rts, copyop), _needInit(true){} + + META_Object(osgAnimation,MorphTransformSoftware) + + bool init(MorphGeometry&); + virtual void operator()(MorphGeometry&); + protected: + bool _needInit; + + }; +} + +#endif diff --git a/include/osgAnimation/RigGeometry b/include/osgAnimation/RigGeometry index 74a5cf00f..31cda0179 100644 --- a/include/osgAnimation/RigGeometry +++ b/include/osgAnimation/RigGeometry @@ -57,14 +57,14 @@ namespace osgAnimation META_Object(osgAnimation, RigGeometry); - void setInfluenceMap(VertexInfluenceMap* vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; } - const VertexInfluenceMap* getInfluenceMap() const { return _vertexInfluenceMap.get();} - VertexInfluenceMap* getInfluenceMap() { return _vertexInfluenceMap.get();} + inline void setInfluenceMap(VertexInfluenceMap* vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; } + inline const VertexInfluenceMap* getInfluenceMap() const { return _vertexInfluenceMap.get();} + inline VertexInfluenceMap* getInfluenceMap() { return _vertexInfluenceMap.get();} - const Skeleton* getSkeleton() const; - Skeleton* getSkeleton(); + inline const Skeleton* getSkeleton() const { return _root.get(); } + inline Skeleton* getSkeleton() { return _root.get(); } // will be used by the update callback to init correctly the rig mesh - void setSkeleton(Skeleton*); + inline void setSkeleton(Skeleton* root){ _root = root;} void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;} bool getNeedToComputeMatrix() const { return _needToComputeMatrix;} @@ -72,25 +72,25 @@ namespace osgAnimation // this build the internal database about vertex influence and bones void buildVertexInfluenceSet(); - const VertexInfluenceSet& getVertexInfluenceSet() const; + inline const VertexInfluenceSet& getVertexInfluenceSet() const { return _vertexInfluenceSet;} void computeMatrixFromRootSkeleton(); // set implementation of rig method - void setRigTransformImplementation(RigTransform*); - RigTransform* getRigTransformImplementation(); - const RigTransform* getRigTransformImplementation() const { return _rigTransformImplementation.get(); } + inline RigTransform* getRigTransformImplementation() { return _rigTransformImplementation.get(); } + inline void setRigTransformImplementation(RigTransform* rig) { _rigTransformImplementation = rig; } + inline const RigTransform* getRigTransformImplementation() const { return _rigTransformImplementation.get(); } - virtual void drawImplementation(osg::RenderInfo& renderInfo) const; void update(); const osg::Matrix& getMatrixFromSkeletonToGeometry() const; const osg::Matrix& getInvMatrixFromSkeletonToGeometry() const; - osg::Geometry* getSourceGeometry(); - const osg::Geometry* getSourceGeometry() const; - void setSourceGeometry(osg::Geometry* geometry); + + inline osg::Geometry* getSourceGeometry() { return _geometry.get(); } + inline const osg::Geometry* getSourceGeometry() const { return _geometry.get(); } + inline void setSourceGeometry(osg::Geometry* geometry) { _geometry = geometry; } void copyFrom(osg::Geometry& from); diff --git a/include/osgAnimation/RigTransform b/include/osgAnimation/RigTransform index 66ae0a219..184cdae0c 100644 --- a/include/osgAnimation/RigTransform +++ b/include/osgAnimation/RigTransform @@ -37,6 +37,23 @@ namespace osgAnimation virtual ~RigTransform() {} }; + class MorphGeometry; + + class MorphTransform : public osg::Object + { + public: + MorphTransform() {} + MorphTransform(const MorphTransform& org, const osg::CopyOp& copyop): + osg::Object(org, copyop) {} + + META_Object(osgAnimation,MorphTransform) + + virtual void operator()(MorphGeometry&) {} + + protected: + virtual ~MorphTransform() {} + + }; } diff --git a/include/osgAnimation/RigTransformHardware b/include/osgAnimation/RigTransformHardware index ce9006ddd..28330e87e 100644 --- a/include/osgAnimation/RigTransformHardware +++ b/include/osgAnimation/RigTransformHardware @@ -38,37 +38,36 @@ namespace osgAnimation META_Object(osgAnimation,RigTransformHardware); typedef osg::Matrix MatrixType; - typedef osgAnimation::Bone BoneType; typedef std::vector > BoneWeightAttribList; - typedef std::vector > BonePalette; - typedef std::map BoneNamePaletteIndex; + typedef std::vector > BonePalette; + typedef std::map BoneNamePaletteIndex; typedef std::vector MatrixPalette; struct IndexWeightEntry { - int _boneIndex; + 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 > VertexIndexWeightList; - - osg::Vec4Array* getVertexAttrib(int index); - int getNumVertexAttrib(); + osg::Vec4Array* getVertexAttrib(unsigned int index); + unsigned int getNumVertexAttrib(); osg::Uniform* getMatrixPaletteUniform(); void computeMatrixPaletteUniform(const osg::Matrix& transformFromSkeletonToGeometry, const osg::Matrix& invTransformFromSkeletonToGeometry); - int getNumBonesPerVertex() const; - int getNumVertexes() const; + unsigned int getNumBonesPerVertex() const; + unsigned int getNumVertexes() const; - bool createPalette(int nbVertexes, BoneMap boneMap, const VertexInfluenceSet::VertexIndexToBoneWeightMap& vertexIndexToBoneWeightMap); + bool createPalette(unsigned int nbVertexes,const BoneMap& boneMap, const VertexInfluenceSet::VertIDToBoneWeightList& vertexIndexToBoneWeightMap); virtual void operator()(RigGeometry&); + void setShader(osg::Shader*); const BoneNamePaletteIndex& getBoneNameToPalette() { @@ -78,13 +77,11 @@ namespace osgAnimation protected: bool init(RigGeometry&); + osg::Uniform* createVertexUniform(); - BoneWeightAttribList createVertexAttribList(); - osg::Uniform* createVertexUniform(); + unsigned int _bonesPerVertex; + unsigned int _nbVertexes; - int _bonesPerVertex; - int _nbVertexes; - VertexIndexWeightList _vertexIndexMatrixWeightList; BonePalette _bonePalette; BoneNamePaletteIndex _boneNameToPalette; BoneWeightAttribList _boneWeightAttribArrays; diff --git a/include/osgAnimation/RigTransformSoftware b/include/osgAnimation/RigTransformSoftware index 300e513fd..8492a215d 100644 --- a/include/osgAnimation/RigTransformSoftware +++ b/include/osgAnimation/RigTransformSoftware @@ -37,10 +37,10 @@ namespace osgAnimation virtual void operator()(RigGeometry&); - class BoneWeight + class BonePtrWeight { public: - BoneWeight(Bone* bone, float weight) : _bone(bone), _weight(weight) {} + 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; } @@ -49,13 +49,13 @@ namespace osgAnimation float _weight; }; - typedef std::vector BoneWeightList; - typedef std::vector VertexList; + typedef std::vector BonePtrWeightList; + typedef std::vector VertexList; - class UniqBoneSetVertexSet + class VertexGroup { public: - BoneWeightList& getBones() { return _bones; } + BonePtrWeightList& getBoneWeights() { return _boneweights; } VertexList& getVertexes() { return _vertexes; } void resetMatrix() @@ -88,18 +88,17 @@ namespace osgAnimation } void computeMatrixForVertexSet() { - if (_bones.empty()) + if (_boneweights.empty()) { - osg::notify(osg::WARN) << this << " RigTransformSoftware::UniqBoneSetVertexSet no bones found" << std::endl; + osg::notify(osg::WARN) << this << " RigTransformSoftware::VertexGroup no bones found" << std::endl; _result = osg::Matrix::identity(); return; } resetMatrix(); - int size = _bones.size(); - for (int i = 0; i < size; i++) + for(BonePtrWeightList::iterator bwit=_boneweights.begin();bwit!=_boneweights.end();++bwit ) { - const Bone* bone = _bones[i].getBone(); + const Bone* bone = bwit->getBone(); if (!bone) { osg::notify(osg::WARN) << this << " RigTransformSoftware::computeMatrixForVertexSet Warning a bone is null, skip it" << std::endl; @@ -107,13 +106,13 @@ namespace osgAnimation } const osg::Matrix& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace(); const osg::Matrix& matrix = bone->getMatrixInSkeletonSpace(); - osg::Matrix::value_type w = _bones[i].getWeight(); + osg::Matrix::value_type w = bwit->getWeight(); accummulateMatrix(invBindMatrix, matrix, w); } } const osg::Matrix& getMatrix() const { return _result;} protected: - BoneWeightList _bones; + BonePtrWeightList _boneweights; VertexList _vertexes; osg::Matrix _result; }; @@ -123,39 +122,34 @@ namespace osgAnimation template 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 - int size = _boneSetVertexSet.size(); - for (int i = 0; i < size; i++) + for(std::vector::iterator itvg=_uniqInfluenceSet2VertIDList.begin(); itvg!=_uniqInfluenceSet2VertIDList.end(); ++itvg) { - UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i]; + VertexGroup& uniq = *itvg; uniq.computeMatrixForVertexSet(); osg::Matrix matrix = transform * uniq.getMatrix() * invTransform; const VertexList& vertexes = uniq.getVertexes(); - int vertexSize = vertexes.size(); - for (int j = 0; j < vertexSize; j++) + for(VertexList::const_iterator vertIDit=vertexes.begin(); vertIDit!=vertexes.end(); ++vertIDit) { - int idx = vertexes[j]; - dst[idx] = src[idx] * matrix; + dst[*vertIDit] = src[*vertIDit] * matrix; } + } } template void computeNormal(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst) { - int size = _boneSetVertexSet.size(); - for (int i = 0; i < size; i++) + for(std::vector::iterator itvg=_uniqInfluenceSet2VertIDList.begin(); itvg!=_uniqInfluenceSet2VertIDList.end(); ++itvg) { - UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i]; + VertexGroup& uniq = *itvg; uniq.computeMatrixForVertexSet(); osg::Matrix matrix = transform * uniq.getMatrix() * invTransform; const VertexList& vertexes = uniq.getVertexes(); - int vertexSize = vertexes.size(); - for (int j = 0; j < vertexSize; j++) + for(VertexList::const_iterator vertIDit=vertexes.begin(); vertIDit!=vertexes.end(); ++vertIDit) { - int idx = vertexes[j]; - dst[idx] = osg::Matrix::transform3x3(src[idx],matrix); + dst[*vertIDit] = osg::Matrix::transform3x3(src[*vertIDit],matrix); } } } @@ -163,8 +157,8 @@ namespace osgAnimation protected: bool init(RigGeometry&); - void initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexSetToBoneSetList& influence); - std::vector _boneSetVertexSet; + void initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexGroupList& influence); + std::vector _uniqInfluenceSet2VertIDList; bool _needInit; diff --git a/include/osgAnimation/VertexInfluence b/include/osgAnimation/VertexInfluence index 47941a43f..345b25db4 100644 --- a/include/osgAnimation/VertexInfluence +++ b/include/osgAnimation/VertexInfluence @@ -25,7 +25,7 @@ namespace osgAnimation { // first is vertex index, and second the weight, the - typedef std::pair VertexIndexWeight; + typedef std::pair VertexIndexWeight; typedef std::vector VertexList; class OSGANIMATION_EXPORT VertexInfluence : public VertexList { @@ -62,43 +62,48 @@ namespace osgAnimation { 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; }; typedef std::vector BoneWeightList; - typedef std::map VertexIndexToBoneWeightMap; + typedef std::vector VertIDToBoneWeightList; - class UniqVertexSetToBoneSet + class VertexGroup { public: + // set Influences of the VertexGroup void setBones(BoneWeightList& bones) { _bones = bones;} const BoneWeightList& getBones() const { return _bones;} - std::vector& getVertexes() { return _vertexes;} - const std::vector& getVertexes() const { return _vertexes;} + // set Vertex Indices of the VertexGroup + std::vector& getVertexes() { return _vertexes;} + const std::vector& getVertexes() const { return _vertexes;} protected: - std::vector _vertexes; + std::vector _vertexes; BoneWeightList _bones; // here we could limit matrix operation by caching (weight * matrix) }; - typedef std::vector UniqVertexSetToBoneSetList; - - const UniqVertexSetToBoneSetList& getUniqVertexSetToBoneSetList() const { return _uniqVertexSetToBoneSet;} + 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 VertexInfluence& v); - void buildVertex2BoneList(); - void buildUniqVertexSetToBoneSetList(); + void buildVertex2BoneList(unsigned int numvertices); void clear(); - const VertexIndexToBoneWeightMap& getVertexToBoneList() const; + const VertIDToBoneWeightList& getVertexToBoneList() const; protected: BoneToVertexList _bone2Vertexes; - VertexIndexToBoneWeightMap _vertex2Bones; - UniqVertexSetToBoneSetList _uniqVertexSetToBoneSet; + VertIDToBoneWeightList _vertex2Bones; + UniqVertexGroupList _uniqVertexSetToBoneSet; }; } diff --git a/src/osgAnimation/AnimationManagerBase.cpp b/src/osgAnimation/AnimationManagerBase.cpp index 1c47851a7..d5a95b421 100644 --- a/src/osgAnimation/AnimationManagerBase.cpp +++ b/src/osgAnimation/AnimationManagerBase.cpp @@ -101,7 +101,10 @@ void AnimationManagerBase::registerAnimation (Animation* animation) buildTargetReference(); } -void AnimationManagerBase::unregisterAnimation (Animation* animation) +void AnimationManagerBase::removeRegisteredAnimation(Animation* animation){ + unregisterAnimation(animation); +} +void AnimationManagerBase::unregisterAnimation(Animation* animation) { AnimationList::iterator it = std::find(_animations.begin(), _animations.end(), animation); if (it != _animations.end()) diff --git a/src/osgAnimation/CMakeLists.txt b/src/osgAnimation/CMakeLists.txt index b0e920544..dc199ef9c 100644 --- a/src/osgAnimation/CMakeLists.txt +++ b/src/osgAnimation/CMakeLists.txt @@ -34,6 +34,7 @@ SET(TARGET_H ${HEADER_PATH}/RigTransform ${HEADER_PATH}/RigTransformHardware ${HEADER_PATH}/RigTransformSoftware + ${HEADER_PATH}/MorphTransformSoftware ${HEADER_PATH}/Sampler ${HEADER_PATH}/Skeleton ${HEADER_PATH}/StackedMatrixElement @@ -75,6 +76,7 @@ SET(TARGET_SRC RigGeometry.cpp RigTransformHardware.cpp RigTransformSoftware.cpp + MorphTransformSoftware.cpp Skeleton.cpp StackedMatrixElement.cpp StackedQuaternionElement.cpp diff --git a/src/osgAnimation/MorphGeometry.cpp b/src/osgAnimation/MorphGeometry.cpp index 9735c06f9..f52c04c3a 100644 --- a/src/osgAnimation/MorphGeometry.cpp +++ b/src/osgAnimation/MorphGeometry.cpp @@ -23,23 +23,23 @@ using namespace osgAnimation; MorphGeometry::MorphGeometry() : _dirty(false), _method(NORMALIZED), + _positionSource(0),_normalSource(0), _morphNormals(true) { setUseDisplayList(false); setUpdateCallback(new UpdateMorphGeometry); - setDataVariance(osg::Object::DYNAMIC); setUseVertexBufferObjects(true); } -MorphGeometry::MorphGeometry(const osg::Geometry& b) : - osg::Geometry(b, osg::CopyOp::DEEP_COPY_ARRAYS), +MorphGeometry::MorphGeometry(const osg::Geometry& g) : + osg::Geometry(g, osg::CopyOp::DEEP_COPY_ARRAYS), _dirty(false), _method(NORMALIZED), + _positionSource(0),_normalSource(0), _morphNormals(true) { setUseDisplayList(false); setUpdateCallback(new UpdateMorphGeometry); - setDataVariance(osg::Object::DYNAMIC); setUseVertexBufferObjects(true); } @@ -56,151 +56,14 @@ MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) setUseVertexBufferObjects(true); } - -void MorphGeometry::transformSoftwareMethod() -{ - if (_dirty) - { - // See if we have an internal optimized geometry - osg::Geometry* morphGeometry = this; - - osg::Vec3Array* pos = dynamic_cast(morphGeometry->getVertexArray()); - - if(pos) - { - if ( _positionSource.size() != pos->size()) - { - _positionSource = std::vector(pos->begin(),pos->end()); - pos->setDataVariance(osg::Object::DYNAMIC); - } - - osg::Vec3Array* normal = dynamic_cast(morphGeometry->getNormalArray()); - bool normalmorphable = _morphNormals && normal; - if (normal && _normalSource.size() != normal->size()) - { - _normalSource = std::vector(normal->begin(),normal->end()); - normal->setDataVariance(osg::Object::DYNAMIC); - } - - - if (!_positionSource.empty()) - { - bool initialized = false; - if (_method == NORMALIZED) - { - // base * 1 - (sum of weights) + sum of (weight * target) - float baseWeight = 0; - for (unsigned int i=0; i < _morphTargets.size(); i++) - { - baseWeight += _morphTargets[i].getWeight(); - } - baseWeight = 1 - baseWeight; - - if (baseWeight != 0) - { - initialized = true; - for (unsigned int i=0; i < pos->size(); i++) - { - (*pos)[i] = _positionSource[i] * baseWeight; - } - if (normalmorphable) - { - for (unsigned int i=0; i < normal->size(); i++) - { - (*normal)[i] = _normalSource[i] * baseWeight; - } - } - } - } - else //if (_method == RELATIVE) - { - // base + sum of (weight * target) - initialized = true; - for (unsigned int i=0; i < pos->size(); i++) - { - (*pos)[i] = _positionSource[i]; - } - if (normalmorphable) - { - for (unsigned int i=0; i < normal->size(); i++) - { - (*normal)[i] = _normalSource[i]; - } - } - } - - for (unsigned int i=0; i < _morphTargets.size(); i++) - { - if (_morphTargets[i].getWeight() > 0) - { - // See if any the targets use the internal optimized geometry - osg::Geometry* targetGeometry = _morphTargets[i].getGeometry(); - - osg::Vec3Array* targetPos = dynamic_cast(targetGeometry->getVertexArray()); - osg::Vec3Array* targetNormals = dynamic_cast(targetGeometry->getNormalArray()); - normalmorphable = normalmorphable && targetNormals; - if(targetPos) - { - if (initialized) - { - // If vertices are initialized, add the morphtargets - for (unsigned int j=0; j < pos->size(); j++) - { - (*pos)[j] += (*targetPos)[j] * _morphTargets[i].getWeight(); - } - - if (normalmorphable) - { - for (unsigned int j=0; j < normal->size(); j++) - { - (*normal)[j] += (*targetNormals)[j] * _morphTargets[i].getWeight(); - } - } - } - else - { - // If not initialized, initialize with this morph target - initialized = true; - for (unsigned int j=0; j < pos->size(); j++) - { - (*pos)[j] = (*targetPos)[j] * _morphTargets[i].getWeight(); - } - - if (normalmorphable) - { - for (unsigned int j=0; j < normal->size(); j++) - { - (*normal)[j] = (*targetNormals)[j] * _morphTargets[i].getWeight(); - } - } - } - } - } - } - - pos->dirty(); - if (normalmorphable) - { - for (unsigned int j=0; j < normal->size(); j++) - { - (*normal)[j].normalize(); - } - normal->dirty(); - } - } - - dirtyBound(); - - } - _dirty = false; - } -} +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), AnimationUpdateCallback(apc, copyop) -{ +{_targetNames=apc._targetNames; } UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback(name) diff --git a/src/osgAnimation/MorphTransformSoftware.cpp b/src/osgAnimation/MorphTransformSoftware.cpp new file mode 100644 index 000000000..7080d8a4d --- /dev/null +++ b/src/osgAnimation/MorphTransformSoftware.cpp @@ -0,0 +1,182 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. + */ + + +#include +#include +#include +#include + +using namespace osgAnimation; + + +bool MorphTransformSoftware::init(MorphGeometry& morphGeometry){ + + + morphGeometry.setDataVariance(osg::Object::DYNAMIC); + osg::Vec3Array* pos = dynamic_cast(morphGeometry.getVertexArray()); + osg::Vec3Array * vertexSource = (morphGeometry.getVertexSource()); + osg::Vec3Array * normalSource = (morphGeometry.getNormalSource()); + + // See if we have an internal optimized geometry + + if(pos) + { + if (!vertexSource|| vertexSource->size() != pos->size()) + { + morphGeometry.setVertexSource(new osg::Vec3Array(pos->begin(),pos->end())); + pos->setDataVariance(osg::Object::DYNAMIC); + } + + osg::Vec3Array* normal = dynamic_cast(morphGeometry.getNormalArray()); + bool normalmorphable = morphGeometry.getMorphNormals() && normal; + morphGeometry.setMorphNormals(normalmorphable); + if (normalmorphable && (!normalSource || normalSource->size() != normal->size())) + { + morphGeometry.setNormalSource(new osg::Vec3Array(normal->begin(),normal->end())); + normal->setDataVariance(osg::Object::DYNAMIC); + } + }else return false; + + _needInit=false; + return true; +} + +void MorphTransformSoftware::operator()(MorphGeometry& morphGeometry) +{ + if (_needInit) + if (!init(morphGeometry)) + return; + if (morphGeometry.isDirty()) + { + osg::Vec3Array* pos = static_cast(morphGeometry.getVertexArray()); + osg::Vec3Array & vertexSource = *(morphGeometry.getVertexSource()); + osg::Vec3Array& normalSource = *(morphGeometry.getNormalSource()); + osg::Vec3Array* normal = static_cast(morphGeometry.getNormalArray()); + bool normalmorphable = morphGeometry.getMorphNormals() && normal; + + + if (!vertexSource.empty()) + { + bool initialized = false; + if (morphGeometry.getMethod() == MorphGeometry::NORMALIZED) + { + // base * 1 - (sum of weights) + sum of (weight * target) + float baseWeight = 0; + for (unsigned int i=0; i < morphGeometry.getMorphTargetList().size(); i++) + { + baseWeight += morphGeometry.getMorphTarget(i).getWeight(); + } + baseWeight = 1 - baseWeight; + + if (baseWeight != 0) + { + initialized = true; + for (unsigned int i=0; i < pos->size(); i++) + { + (*pos)[i] = vertexSource[i] * baseWeight; + } + if (normalmorphable) + { + for (unsigned int i=0; i < normal->size(); i++) + { + (*normal)[i] = normalSource[i] * baseWeight; + } + } + } + } + else //if (_method == RELATIVE) + { + // base + sum of (weight * target) + initialized = true; + for (unsigned int i=0; i < pos->size(); i++) + { + (*pos)[i] = vertexSource[i]; + } + if (normalmorphable) + { + for (unsigned int i=0; i < normal->size(); i++) + { + (*normal)[i] = normalSource[i]; + } + } + } + + for (unsigned int i=0; i < morphGeometry.getMorphTargetList().size(); i++) + { + if (morphGeometry.getMorphTarget(i).getWeight() > 0) + { + // See if any the targets use the internal optimized geometry + osg::Geometry* targetGeometry = morphGeometry.getMorphTarget(i).getGeometry(); + + osg::Vec3Array* targetPos = dynamic_cast(targetGeometry->getVertexArray()); + osg::Vec3Array* targetNormals = dynamic_cast(targetGeometry->getNormalArray()); + normalmorphable = normalmorphable && targetNormals; + if(targetPos) + { + if (initialized) + { + // If vertices are initialized, add the morphtargets + for (unsigned int j=0; j < pos->size(); j++) + { + (*pos)[j] += (*targetPos)[j] * morphGeometry.getMorphTarget(i).getWeight(); + } + + if (normalmorphable) + { + for (unsigned int j=0; j < normal->size(); j++) + { + (*normal)[j] += (*targetNormals)[j] * morphGeometry.getMorphTarget(i).getWeight(); + } + } + } + else + { + // If not initialized, initialize with this morph target + initialized = true; + for (unsigned int j=0; j < pos->size(); j++) + { + (*pos)[j] = (*targetPos)[j] * morphGeometry.getMorphTarget(i).getWeight(); + } + + if (normalmorphable) + { + for (unsigned int j=0; j < normal->size(); j++) + { + (*normal)[j] = (*targetNormals)[j] * morphGeometry.getMorphTarget(i).getWeight(); + } + } + } + } + } + } + + pos->dirty(); + if (normalmorphable) + { + for (unsigned int j=0; j < normal->size(); j++) + { + (*normal)[j].normalize(); + } + normal->dirty(); + } + } + + morphGeometry.dirtyBound(); + + + morphGeometry.dirty(false); + } + +} diff --git a/src/osgAnimation/RigGeometry.cpp b/src/osgAnimation/RigGeometry.cpp index 938629a97..b09c61966 100644 --- a/src/osgAnimation/RigGeometry.cpp +++ b/src/osgAnimation/RigGeometry.cpp @@ -58,7 +58,7 @@ RigGeometry::RigGeometry() _needToComputeMatrix = true; _matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity(); // disable the computation of boundingbox for the rig mesh - setComputeBoundingBoxCallback(new RigComputeBoundingBoxCallback); + setComputeBoundingBoxCallback(new RigComputeBoundingBoxCallback()); } @@ -69,9 +69,12 @@ RigGeometry::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) : _vertexInfluenceSet(b._vertexInfluenceSet), _vertexInfluenceMap(b._vertexInfluenceMap), _needToComputeMatrix(b._needToComputeMatrix) -{ +{ + _needToComputeMatrix = true; + _matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity(); // disable the computation of boundingbox for the rig mesh - setComputeBoundingBoxCallback(new RigComputeBoundingBoxCallback); + + setComputeBoundingBoxCallback(new RigComputeBoundingBoxCallback()); // we don't copy the RigImplementation yet. because the RigImplementation need to be initialized in a valid graph, with a skeleton ... // don't know yet what to do with a clone of a RigGeometry @@ -81,12 +84,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::drawImplementation(osg::RenderInfo& renderInfo) const -{ - osg::Geometry::drawImplementation(renderInfo); -} - void RigGeometry::buildVertexInfluenceSet() { if (!_vertexInfluenceMap.valid()) @@ -97,12 +94,12 @@ void RigGeometry::buildVertexInfluenceSet() _vertexInfluenceSet.clear(); for (osgAnimation::VertexInfluenceMap::iterator it = _vertexInfluenceMap->begin(); it != _vertexInfluenceMap->end(); - ++it) + ++it){ _vertexInfluenceSet.addVertexInfluence(it->second); - - _vertexInfluenceSet.buildVertex2BoneList(); - _vertexInfluenceSet.buildUniqVertexSetToBoneSetList(); - OSG_DEBUG << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl; + } + _vertexInfluenceSet.buildVertex2BoneList(getSourceGeometry()->getVertexArray()->getNumElements()); + _vertexInfluenceSet.buildUniqVertexGroupList(); + OSG_DEBUG << "uniq groups " << _vertexInfluenceSet.getUniqVertexGroupList().size() << " for " << getName() << std::endl; } void RigGeometry::computeMatrixFromRootSkeleton() @@ -116,7 +113,7 @@ void RigGeometry::computeMatrixFromRootSkeleton() osg::Matrix notRoot = _root->getMatrix(); _matrixFromSkeletonToGeometry = mtxList[0] * osg::Matrix::inverse(notRoot); _invMatrixFromSkeletonToGeometry = osg::Matrix::inverse(_matrixFromSkeletonToGeometry); - _needToComputeMatrix = false; + _needToComputeMatrix = false; } void RigGeometry::update() @@ -132,45 +129,45 @@ void RigGeometry::update() void RigGeometry::copyFrom(osg::Geometry& from) { - bool copyToSelf = (this==&from); + if (this==&from) return; osg::Geometry& target = *this; - if (!copyToSelf) target.setStateSet(from.getStateSet()); + target.setStateSet(from.getStateSet()); // copy over primitive sets. - if (!copyToSelf) target.getPrimitiveSetList() = from.getPrimitiveSetList(); + target.getPrimitiveSetList() = from.getPrimitiveSetList(); if (from.getVertexArray()) { - if (!copyToSelf) target.setVertexArray(from.getVertexArray()); + target.setVertexArray(from.getVertexArray()); } if (from.getNormalArray()) { - if (!copyToSelf) target.setNormalArray(from.getNormalArray()); + target.setNormalArray(from.getNormalArray()); } if (from.getColorArray()) { - if (!copyToSelf) target.setColorArray(from.getColorArray()); + target.setColorArray(from.getColorArray()); } if (from.getSecondaryColorArray()) { - if (!copyToSelf) target.setSecondaryColorArray(from.getSecondaryColorArray()); + target.setSecondaryColorArray(from.getSecondaryColorArray()); } if (from.getFogCoordArray()) { - if (!copyToSelf) target.setFogCoordArray(from.getFogCoordArray()); + target.setFogCoordArray(from.getFogCoordArray()); } for(unsigned int ti=0;ti= (int)_boneWeightAttribArrays.size()) + if (index >= _boneWeightAttribArrays.size()) return 0; return _boneWeightAttribArrays[index].get(); } -int RigTransformHardware::getNumVertexAttrib() +unsigned int RigTransformHardware::getNumVertexAttrib() { return _boneWeightAttribArrays.size(); } @@ -61,68 +60,83 @@ osg::Uniform* RigTransformHardware::getMatrixPaletteUniform() void RigTransformHardware::computeMatrixPaletteUniform(const osg::Matrix& transformFromSkeletonToGeometry, const osg::Matrix& invTransformFromSkeletonToGeometry) { - for (int i = 0; i < (int)_bonePalette.size(); i++) + for (unsigned int i = 0; i < _bonePalette.size(); i++) { osg::ref_ptr bone = _bonePalette[i].get(); - const osg::Matrix& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace(); - const osg::Matrix& boneMatrix = bone->getMatrixInSkeletonSpace(); - osg::Matrix resultBoneMatrix = invBindMatrix * boneMatrix; - osg::Matrix result = transformFromSkeletonToGeometry * resultBoneMatrix * invTransformFromSkeletonToGeometry; + const osg::Matrixf& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace(); + const osg::Matrixf& boneMatrix = bone->getMatrixInSkeletonSpace(); + osg::Matrixf resultBoneMatrix = invBindMatrix * boneMatrix; + osg::Matrixf result = transformFromSkeletonToGeometry * resultBoneMatrix * invTransformFromSkeletonToGeometry; if (!_uniformMatrixPalette->setElement(i, result)) OSG_WARN << "RigTransformHardware::computeUniformMatrixPalette can't set uniform at " << i << " elements" << std::endl; } } -int RigTransformHardware::getNumBonesPerVertex() const { return _bonesPerVertex;} -int RigTransformHardware::getNumVertexes() const { return _nbVertexes;} +unsigned int RigTransformHardware::getNumBonesPerVertex() const { return _bonesPerVertex;} +unsigned int RigTransformHardware::getNumVertexes() const { return _nbVertexes;} -bool RigTransformHardware::createPalette(int nbVertexes, BoneMap boneMap, const VertexInfluenceSet::VertexIndexToBoneWeightMap& vertexIndexToBoneWeightMap) +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 palette; + _bonePalette.clear(); + _boneNameToPalette.clear(); BoneNameCountMap boneNameCountMap; - // init vertex attribute data VertexIndexWeightList vertexIndexWeight; vertexIndexWeight.resize(nbVertexes); - int maxBonePerVertex = 0; - for (VertexInfluenceSet::VertexIndexToBoneWeightMap::const_iterator vit = vertexIndexToBoneWeightMap.begin(); vit != vertexIndexToBoneWeightMap.end(); ++vit) + unsigned int maxBonePerVertex = 0; + if(vertexIndexToBoneWeightMap.size()!=nbVertexes) { + OSG_WARN << "RigTransformHardware::some vertex has no transform " <first; - const VertexInfluenceSet::BoneWeightList& boneWeightList = vit->second; - int bonesForThisVertex = 0; + const VertexInfluenceSet::BoneWeightList& boneWeightList = *vit; + unsigned int bonesForThisVertex = 0; for (VertexInfluenceSet::BoneWeightList::const_iterator it = boneWeightList.begin(); it != boneWeightList.end(); ++it) { const VertexInfluenceSet::BoneWeight& bw = *it; - if(fabs(bw.getWeight()) > 1e-2) // don't use bone with weight too small + if(fabs(bw.getWeight()) > 1e-4) // don't use bone with weight too small { - if (boneNameCountMap.find(bw.getBoneName()) != boneNameCountMap.end()) + if ((boneName2PaletteIndex= _boneNameToPalette.find(bw.getBoneName())) != _boneNameToPalette.end()) { boneNameCountMap[bw.getBoneName()]++; bonesForThisVertex++; // count max number of bones per vertexes - vertexIndexWeight[vertexIndex].push_back(IndexWeightEntry(_boneNameToPalette[bw.getBoneName()],bw.getWeight())); + vertexIndexWeight[vertexID].push_back(IndexWeightEntry(boneName2PaletteIndex->second,bw.getWeight())); } else { - if (boneMap.find(bw.getBoneName()) == boneMap.end()) + BoneMap::const_iterator bonebyname; + if ((bonebyname=boneMap.find(bw.getBoneName())) == boneMap.end()) { - OSG_INFO << "RigTransformHardware::createPalette can't find bone " << bw.getBoneName() << " skip this influence" << std::endl; + 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++; - palette.push_back(boneMap[bw.getBoneName()]); - _boneNameToPalette[bw.getBoneName()] = palette.size()-1; - vertexIndexWeight[vertexIndex].push_back(IndexWeightEntry(_boneNameToPalette[bw.getBoneName()],bw.getWeight())); - } + + _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 " << vertexIndex << " this bone will not be in the palette" << std::endl; + 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; @@ -136,15 +150,12 @@ bool RigTransformHardware::createPalette(int nbVertexes, BoneMap boneMap, const OSG_INFO << "RigTransformHardware::createPalette will use " << boneNameCountMap.size() * 4 << " uniforms" << std::endl; - for (int i = 0 ; i < (int)vertexIndexWeight.size(); i++) - vertexIndexWeight[i].resize(maxBonePerVertex); - - _nbVertexes = nbVertexes; _bonesPerVertex = maxBonePerVertex; - _bonePalette = palette; - _vertexIndexMatrixWeightList = vertexIndexWeight; + for (int i = 0 ; i < (int)vertexIndexWeight.size(); i++) + vertexIndexWeight[i].resize(maxBonePerVertex); + _uniformMatrixPalette = createVertexUniform(); - _boneWeightAttribArrays = createVertexAttribList(); + createVertexAttribList(*this,vertexIndexWeight,this->_boneWeightAttribArrays); return true; } @@ -157,33 +168,34 @@ bool RigTransformHardware::createPalette(int nbVertexes, BoneMap boneMap, const // the idea is to use this format to have a granularity smaller // than the 4 bones using two vertex attributes // -RigTransformHardware::BoneWeightAttribList RigTransformHardware::createVertexAttribList() +void createVertexAttribList(RigTransformHardware& rig,const VertexIndexWeightList& _vertexIndexMatrixWeightList, RigTransformHardware::BoneWeightAttribList& boneWeightAttribArrays) { - BoneWeightAttribList arrayList; - int nbArray = static_cast(ceilf(getNumBonesPerVertex() * 0.5)); + unsigned int nbVertices= rig.getNumVertexes(); + unsigned int maxbonepervertex=rig.getNumBonesPerVertex(); + unsigned int nbArray = static_cast(ceilf( ((float)maxbonepervertex) * 0.5f)); if (!nbArray) - return arrayList; + return ; - arrayList.resize(nbArray); - for (int i = 0; i < nbArray; i++) + boneWeightAttribArrays.resize(nbArray); + for (unsigned int i = 0; i < nbArray; i++) { osg::ref_ptr array = new osg::Vec4Array(osg::Array::BIND_PER_VERTEX); - arrayList[i] = array; - int nbVertexes = getNumVertexes(); - array->resize(nbVertexes); - for (int j = 0; j < nbVertexes; j++) + boneWeightAttribArrays[i] = array; + array->resize( nbVertices); + for (unsigned int j = 0; j < nbVertices; j++) { - for (int b = 0; b < 2; b++) + + for (unsigned int b = 0; b < 2; b++) { // the granularity is 2 so if we have only one bone // it's convenient to init the second with a weight 0 - int boneIndexInList = i*2 + b; - int boneIndexInVec4 = b*2; + unsigned int boneIndexInList = i*2 + b; + unsigned int boneIndexInVec4 = b*2; (*array)[j][0 + boneIndexInVec4] = 0; (*array)[j][1 + boneIndexInVec4] = 0; - if (boneIndexInList < getNumBonesPerVertex()) + if (boneIndexInList < maxbonepervertex) { - float boneIndex = static_cast(_vertexIndexMatrixWeightList[j][boneIndexInList].getIndex()); + float boneIndex = static_cast(_vertexIndexMatrixWeightList[j][boneIndexInList].getBoneIndex()); float boneWeight = _vertexIndexMatrixWeightList[j][boneIndexInList].getWeight(); // fill the vec4 (*array)[j][0 + boneIndexInVec4] = boneIndex; @@ -192,10 +204,9 @@ RigTransformHardware::BoneWeightAttribList RigTransformHardware::createVertexAtt } } } - return arrayList; + return ; } - osg::Uniform* RigTransformHardware::createVertexUniform() { osg::Uniform* uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size()); @@ -210,6 +221,15 @@ void RigTransformHardware::setShader(osg::Shader* shader) bool RigTransformHardware::init(RigGeometry& geom) { + if (!geom.getSkeleton()) + { + OSG_WARN << "RigTransformHardware no skeleton set in geometry " << geom.getName() << std::endl; + return false; + } + BoneMapVisitor mapVisitor; + geom.getSkeleton()->accept(mapVisitor); + BoneMap bm = mapVisitor.getBoneMap(); + osg::Geometry& source = *geom.getSourceGeometry(); osg::Vec3Array* positionSrc = dynamic_cast(source.getVertexArray()); if (!positionSrc) @@ -218,72 +238,93 @@ bool RigTransformHardware::init(RigGeometry& geom) return false; } - if (!geom.getSkeleton()) - { - OSG_WARN << "RigTransformHardware no skeleton set in geometry " << geom.getName() << std::endl; - return false; - } - - // copy shallow from source geometry to rig geom.copyFrom(source); - - BoneMapVisitor mapVisitor; - geom.getSkeleton()->accept(mapVisitor); - BoneMap bm = mapVisitor.getBoneMap(); - - if (!createPalette(positionSrc->size(),bm, geom.getVertexInfluenceSet().getVertexToBoneList())) + if (!createPalette(positionSrc->size(),bm,geom.getVertexInfluenceSet().getVertexToBoneList())) return false; - osg::ref_ptr program = new osg::Program; - program->setName("HardwareSkinning"); - if (!_shader.valid()) - _shader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"skinning.vert"); + osg::ref_ptr program ; + osg::ref_ptr vertexshader; + osg::ref_ptr stateset = geom.getOrCreateStateSet(); - if (!_shader.valid()) { + //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 = _shader->getShaderSource(); + 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()); - _shader->setShaderSource(str); + vertexshader->setShaderSource(str); } else { - OSG_WARN << "MAX_MATRIX not found in Shader! " << str << std::endl; + OSG_INFO<< "MAX_MATRIX not found in Shader! " << str << std::endl; } OSG_INFO << "Shader " << str << std::endl; } - int attribIndex = 11; - int nbAttribs = getNumVertexAttrib(); - 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; 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(_shader.get()); - osg::ref_ptr ss = geom.getOrCreateStateSet(); - ss->addUniform(getMatrixPaletteUniform()); - ss->addUniform(new osg::Uniform("nbBonesPerVertex", getNumBonesPerVertex())); - ss->setAttributeAndModes(program.get()); + 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; } + void RigTransformHardware::operator()(RigGeometry& geom) { if (_needInit) diff --git a/src/osgAnimation/RigTransformSoftware.cpp b/src/osgAnimation/RigTransformSoftware.cpp index b9537cf8d..79224cdd1 100644 --- a/src/osgAnimation/RigTransformSoftware.cpp +++ b/src/osgAnimation/RigTransformSoftware.cpp @@ -18,6 +18,7 @@ #include #include +#include using namespace osgAnimation; RigTransformSoftware::RigTransformSoftware() @@ -33,6 +34,45 @@ RigTransformSoftware::RigTransformSoftware(const RigTransformSoftware& rts,const } +// sort by name and weight +struct SortByNameAndWeight : public std::less +{ + bool operator()(const VertexInfluenceSet::BoneWeight& b0, + const VertexInfluenceSet::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; + } +}; + +struct SortByBoneWeightList : public std::less +{ + bool operator()(const VertexInfluenceSet::BoneWeightList& b0, + const VertexInfluenceSet::BoneWeightList& b1) const + { + if (b0.size() < b1.size()) + return true; + else if (b0.size() > b1.size()) + return false; + + int size = b0.size(); + for (int i = 0; i < size; i++) + { + bool result = SortByNameAndWeight()(b0[i], b1[i]); + if (result) + return true; + else if (SortByNameAndWeight()(b1[i], b0[i])) + return false; + } + return false; + } +}; + bool RigTransformSoftware::init(RigGeometry& geom) { if (!geom.getSkeleton()) @@ -41,12 +81,34 @@ bool RigTransformSoftware::init(RigGeometry& geom) BoneMapVisitor mapVisitor; geom.getSkeleton()->accept(mapVisitor); BoneMap bm = mapVisitor.getBoneMap(); - initVertexSetFromBones(bm, geom.getVertexInfluenceSet().getUniqVertexSetToBoneSetList()); + initVertexSetFromBones(bm, geom.getVertexInfluenceSet().getUniqVertexGroupList()); if (geom.getSourceGeometry()) geom.copyFrom(*geom.getSourceGeometry()); - geom.setVertexArray(0); - geom.setNormalArray(0); + + + osg::Vec3Array* normalSrc = dynamic_cast(geom.getSourceGeometry()->getNormalArray()); + osg::Vec3Array* positionSrc = dynamic_cast(geom.getSourceGeometry()->getVertexArray()); + + if(!(positionSrc) || positionSrc->empty() ) + return false; + if(normalSrc&& normalSrc->size()!=positionSrc->size()) + return false; + + + geom.setVertexArray(new osg::Vec3Array); + osg::Vec3Array* positionDst =new osg::Vec3Array; + geom.setVertexArray(positionDst); + *positionDst=*positionSrc; + positionDst->setDataVariance(osg::Object::DYNAMIC); + + + if(normalSrc){ + osg::Vec3Array* normalDst =new osg::Vec3Array; + *normalDst=*normalSrc; + geom.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX); + normalDst->setDataVariance(osg::Object::DYNAMIC); + } _needInit = false; return true; @@ -65,74 +127,50 @@ void RigTransformSoftware::operator()(RigGeometry& geom) osg::Geometry& source = *geom.getSourceGeometry(); osg::Geometry& destination = geom; - osg::Vec3Array* positionSrc = dynamic_cast(source.getVertexArray()); - osg::Vec3Array* positionDst = dynamic_cast(destination.getVertexArray()); - if (positionSrc ) - { - if (!positionDst || (positionDst->size() != positionSrc->size()) ) - { - if (!positionDst) - { - positionDst = new osg::Vec3Array; - positionDst->setDataVariance(osg::Object::DYNAMIC); - destination.setVertexArray(positionDst); - } - *positionDst = *positionSrc; - } - if (!positionDst->empty()) - { - compute(geom.getMatrixFromSkeletonToGeometry(), - geom.getInvMatrixFromSkeletonToGeometry(), - &positionSrc->front(), - &positionDst->front()); - positionDst->dirty(); - } - - } - + osg::Vec3Array* positionSrc = static_cast(source.getVertexArray()); + osg::Vec3Array* positionDst = static_cast(destination.getVertexArray()); osg::Vec3Array* normalSrc = dynamic_cast(source.getNormalArray()); - osg::Vec3Array* normalDst = dynamic_cast(destination.getNormalArray()); + osg::Vec3Array* normalDst = static_cast(destination.getNormalArray()); + + + compute(geom.getMatrixFromSkeletonToGeometry(), + geom.getInvMatrixFromSkeletonToGeometry(), + &positionSrc->front(), + &positionDst->front()); + positionDst->dirty(); + + + if (normalSrc ) { - if (!normalDst || (normalDst->size() != normalSrc->size()) ) - { - if (!normalDst) - { - normalDst = new osg::Vec3Array; - normalDst->setDataVariance(osg::Object::DYNAMIC); - destination.setNormalArray(normalDst, osg::Array::BIND_PER_VERTEX); - } - *normalDst = *normalSrc; - } - if (!normalDst->empty()) - { computeNormal(geom.getMatrixFromSkeletonToGeometry(), geom.getInvMatrixFromSkeletonToGeometry(), &normalSrc->front(), &normalDst->front()); normalDst->dirty(); - } } } -void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexSetToBoneSetList& influence) +///convert BoneWeight to BonePtrWeight using bonemap +void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexGroupList& vertexgroups) { - _boneSetVertexSet.clear(); + _uniqInfluenceSet2VertIDList.clear(); - int size = influence.size(); - _boneSetVertexSet.resize(size); - for (int i = 0; i < size; i++) + 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::UniqVertexSetToBoneSet& inf = influence[i]; - int nbBones = inf.getBones().size(); - BoneWeightList& boneList = _boneSetVertexSet[i].getBones(); + 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 = inf.getBones()[b].getBoneName(); - float weight = inf.getBones()[b].getWeight(); + 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() ) { @@ -143,18 +181,18 @@ void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const Vert continue; } Bone* bone = it->second.get(); - boneList.push_back(BoneWeight(bone, weight)); + 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; + /*const double threshold = 1e-4; if (!_boneSetVertexSet[i].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); - } - _boneSetVertexSet[i].getVertexes() = inf.getVertexes(); + }*/ + _uniqInfluenceSet2VertIDList[i].getVertexes() = vg.getVertexes(); } } diff --git a/src/osgAnimation/VertexInfluence.cpp b/src/osgAnimation/VertexInfluence.cpp index ad1686277..f5a983234 100644 --- a/src/osgAnimation/VertexInfluence.cpp +++ b/src/osgAnimation/VertexInfluence.cpp @@ -16,16 +16,21 @@ #include #include #include +#include using namespace osgAnimation; void VertexInfluenceSet::addVertexInfluence(const VertexInfluence& v) { _bone2Vertexes.push_back(v); } -const VertexInfluenceSet::VertexIndexToBoneWeightMap& VertexInfluenceSet::getVertexToBoneList() const { return _vertex2Bones;} +const VertexInfluenceSet::VertIDToBoneWeightList& VertexInfluenceSet::getVertexToBoneList() const { return _vertex2Bones;} // this class manage VertexInfluence database by mesh // reference bones per vertex ... -void VertexInfluenceSet::buildVertex2BoneList() + +void VertexInfluenceSet::buildVertex2BoneList(unsigned int numvertices) { _vertex2Bones.clear(); + _vertex2Bones.reserve(numvertices); + _vertex2Bones.resize(numvertices); + for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); ++it) { const VertexInfluence& vi = (*it); @@ -35,23 +40,25 @@ void VertexInfluenceSet::buildVertex2BoneList() VertexIndexWeight viw = vi[i]; int index = viw.first; float weight = viw.second; - if (vi.getName().empty()) + 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)); } } // normalize weight per vertex - for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it) + unsigned int vertid=0; + for (VertIDToBoneWeightList::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it,++vertid) { - BoneWeightList& bones = it->second; + 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) { - OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << it->first << " seems to have 0 weight, skip normalize for this vertex" << std::endl; + OSG_WARN << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " < UnifyBoneGroup; + typedef std::map UnifyBoneGroup; UnifyBoneGroup unifyBuffer; - for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it) + unsigned int vertexID=0; + for (VertIDToBoneWeightList::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it,++vertexID) { - BoneWeightList bones = it->second; - int vertexIndex = it->first; + BoneWeightList bones = *it; // sort the vector to have a consistent key std::sort(bones.begin(), bones.end(), SortByNameAndWeight()); @@ -128,10 +135,12 @@ void VertexInfluenceSet::buildUniqVertexSetToBoneSetList() UnifyBoneGroup::iterator result = unifyBuffer.find(bones); if (result == unifyBuffer.end()) unifyBuffer[bones].setBones(bones); - unifyBuffer[bones].getVertexes().push_back(vertexIndex); + unifyBuffer[bones].getVertexes().push_back(vertexID); } _uniqVertexSetToBoneSet.reserve(unifyBuffer.size()); + + for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it) { _uniqVertexSetToBoneSet.push_back(it->second);