You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
6.2 KiB
172 lines
6.2 KiB
/* -*-c++-*- |
|
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@plopbyte.net> |
|
* |
|
* 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_RIGTRANSFORM_SOFTWARE |
|
#define OSGANIMATION_RIGTRANSFORM_SOFTWARE 1 |
|
|
|
#include <osgAnimation/Export> |
|
#include <osgAnimation/RigTransform> |
|
#include <osgAnimation/Bone> |
|
#include <osgAnimation/VertexInfluence> |
|
#include <osg/observer_ptr> |
|
|
|
namespace osgAnimation |
|
{ |
|
|
|
class RigGeometry; |
|
|
|
/// This class manage format for hardware skinning |
|
class OSGANIMATION_EXPORT RigTransformSoftware : public RigTransform |
|
{ |
|
public: |
|
|
|
RigTransformSoftware(); |
|
virtual void operator()(RigGeometry&); |
|
|
|
|
|
class BoneWeight |
|
{ |
|
public: |
|
BoneWeight(Bone* bone, float weight) : _bone(bone), _weight(weight) {} |
|
const Bone* getBone() const { return _bone.get(); } |
|
float getWeight() const { return _weight; } |
|
void setWeight(float w) { _weight = w; } |
|
protected: |
|
osg::observer_ptr<Bone> _bone; |
|
float _weight; |
|
}; |
|
|
|
typedef std::vector<BoneWeight> BoneWeightList; |
|
typedef std::vector<int> VertexList; |
|
|
|
class UniqBoneSetVertexSet |
|
{ |
|
public: |
|
BoneWeightList& getBones() { return _bones; } |
|
VertexList& getVertexes() { return _vertexes; } |
|
|
|
void resetMatrix() |
|
{ |
|
_result.set(0, 0, 0, 0, |
|
0, 0, 0, 0, |
|
0, 0, 0, 0, |
|
0, 0, 0, 1); |
|
} |
|
void accummulateMatrix(const osg::Matrix& invBindMatrix, const osg::Matrix& matrix, osg::Matrix::value_type weight) |
|
{ |
|
osg::Matrix m = invBindMatrix * matrix; |
|
osg::Matrix::value_type* ptr = m.ptr(); |
|
osg::Matrix::value_type* ptrresult = _result.ptr(); |
|
ptrresult[0] += ptr[0] * weight; |
|
ptrresult[1] += ptr[1] * weight; |
|
ptrresult[2] += ptr[2] * weight; |
|
|
|
ptrresult[4] += ptr[4] * weight; |
|
ptrresult[5] += ptr[5] * weight; |
|
ptrresult[6] += ptr[6] * weight; |
|
|
|
ptrresult[8] += ptr[8] * weight; |
|
ptrresult[9] += ptr[9] * weight; |
|
ptrresult[10] += ptr[10] * weight; |
|
|
|
ptrresult[12] += ptr[12] * weight; |
|
ptrresult[13] += ptr[13] * weight; |
|
ptrresult[14] += ptr[14] * weight; |
|
} |
|
void computeMatrixForVertexSet() |
|
{ |
|
if (_bones.empty()) |
|
{ |
|
osg::notify(osg::WARN) << this << " RigTransformSoftware::UniqBoneSetVertexSet no bones found" << std::endl; |
|
_result = osg::Matrix::identity(); |
|
return; |
|
} |
|
resetMatrix(); |
|
|
|
int size = _bones.size(); |
|
for (int i = 0; i < size; i++) |
|
{ |
|
const Bone* bone = _bones[i].getBone(); |
|
if (!bone) |
|
{ |
|
osg::notify(osg::WARN) << this << " RigTransformSoftware::computeMatrixForVertexSet Warning a bone is null, skip it" << std::endl; |
|
continue; |
|
} |
|
const osg::Matrix& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace(); |
|
const osg::Matrix& matrix = bone->getMatrixInSkeletonSpace(); |
|
osg::Matrix::value_type w = _bones[i].getWeight(); |
|
accummulateMatrix(invBindMatrix, matrix, w); |
|
} |
|
} |
|
const osg::Matrix& getMatrix() const { return _result;} |
|
protected: |
|
BoneWeightList _bones; |
|
VertexList _vertexes; |
|
osg::Matrix _result; |
|
}; |
|
|
|
|
|
|
|
template <class V> 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++) |
|
{ |
|
UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i]; |
|
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++) |
|
{ |
|
int idx = vertexes[j]; |
|
dst[idx] = src[idx] * matrix; |
|
} |
|
} |
|
} |
|
|
|
|
|
template <class V> 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++) |
|
{ |
|
UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i]; |
|
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++) |
|
{ |
|
int idx = vertexes[j]; |
|
dst[idx] = osg::Matrix::transform3x3(src[idx],matrix); |
|
} |
|
} |
|
} |
|
|
|
protected: |
|
|
|
bool init(RigGeometry&); |
|
void initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexSetToBoneSetList& influence); |
|
std::vector<UniqBoneSetVertexSet> _boneSetVertexSet; |
|
|
|
bool _needInit; |
|
|
|
}; |
|
} |
|
|
|
#endif
|
|
|