Commit 0b961656 authored by Dirk Wilden's avatar Dirk Wilden
Browse files

skeleton classes for skinning

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@10742 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 3fab8ab0
......@@ -43,15 +43,23 @@
#ifndef BASESKIN_HH
#define BASESKIN_HH
#include "OpenFlipper/common/perObjectData.hh"
#include <ObjectTypes/Skeleton/SkeletonT.hh>
#include <OpenMesh/Core/IO/MeshIO.hh>
#define OBJECTDATA_SKIN "Skin Object-Data"
#define SKIN_WEIGHTS_PROP "skin-weights"
#define DEFAULTPOSE_PROP "Default pose"
/**
* @brief Abstract base class for the skin template, wrapping all template versions of the skin
*/
class BaseSkin
class BaseSkin : public PerObjectData
{
public:
/**
* @name Properties
* These structures store mesh properties used to make the mesh a skin.
......@@ -80,7 +88,6 @@ public:
* vertex are supposed to sum to one.
*/
typedef map<unsigned int, double> SkinWeights;
SkinWeights weights;
//@}
/**
......@@ -106,9 +113,10 @@ public:
* These methods are related to using a mesh as skin with this skeleton.
*/
//@{
virtual void AttachSkin() = 0;
virtual void DeformSkin(const AnimationHandle &_hAni, Method _method = M_LBS) = 0;
virtual void ReleaseSkin() = 0;
virtual void attachSkin() = 0;
virtual void deformSkin() = 0;
virtual void deformSkin(const AnimationHandle &_hAni, Method _method = M_LBS) = 0;
virtual void releaseSkin() = 0;
//@}
};
......
......@@ -40,55 +40,91 @@
* *
\*===========================================================================*/
#ifndef SKELETONOBJECTDATAT_HH
#define SKELETONOBJECTDATAT_HH
#ifndef SKELETONOBJECTDATA_HH
#define SKELETONOBJECTDATA_HH
#include <OpenFlipper/common/Types.hh>
#include "OpenFlipper/common/perObjectData.hh"
#include "OpenFlipper/common/BaseObjectData.hh"
#define OBJECTDATA_SKELETON "Skeleton Object Data"
/**
* @brief Data object attached to the skeleton
*
* It stores the skin attached to this skeleton, by both holding a pointer to the mesh as well as to the
* object that stores the mesh.
* It stores the object ids of skins attached to this skeleton
*
*/
template<typename BaseSkinT>
class SkeletonObjectDataT : public PerObjectData
class SkeletonObjectData : public PerObjectData
{
public:
SkeletonObjectDataT()
{
pSkin_ = 0;
pSkinObjectId_ = -1;
SkeletonObjectData(){
}
SkeletonObjectDataT(const SkeletonObjectDataT& _copy)
{
pSkin_ = _copy.pSkin_;
pSkinObjectId_ = _copy.pSkinObjectId_;
SkeletonObjectData(const SkeletonObjectData& _copy){
skins_ = _copy.skins_;
}
~SkeletonObjectDataT()
{
delete pSkin_;
~SkeletonObjectData(){
}
// Copy function
PerObjectData* copyPerObjectData() {
SkeletonObjectDataT* copy = new SkeletonObjectDataT(*this);
SkeletonObjectData* copy = new SkeletonObjectData(*this);
return copy;
}
public:
/// The skin object, an instance of SkinT or one of its derivatives
BaseSkinT *pSkin_;
/**
* \brief Get the skin with given index (0 <= _index < skinCount())
*/
int skin( unsigned int _index ){
if ( _index >= skins_.size() )
return -1;
return skins_[_index];
}
/**
* \brief Get the number of associated skins
*/
unsigned int skinCount(){
return skins_.size();
}
/**
* \brief Add a skin to the skeleton
*/
void addSkin(int _objectId){
//check if already available
for(unsigned int i=0; i < skins_.size(); i++)
if ( skins_[i] == _objectId )
return;
//add the skin
skins_.push_back(_objectId);
}
/**
* \brief Remove a skin from the skeleton
*/
void removeSkin(int _objectId){
//check if already available
for(unsigned int i=0; i < skins_.size(); i++)
if ( skins_[i] == _objectId ){
skins_.erase( skins_.begin() + i );
return;
}
//not found
std::cerr << "Cannot remove skin with object id:" << _objectId << ". Not found!" << std::endl;
}
/**
* \brief Remove all skins from the skeleton
*/
void clearSkins(){
skins_.clear();
}
/// The id of the mesh object used as skin
int pSkinObjectId_;
private:
//vector of object ids from all skins attached to this skeleton
std::vector< int > skins_;
};
#endif //SKELETONOBJECTDATAT_HH
\ No newline at end of file
#endif //SKELETONOBJECTDATA_HH
\ No newline at end of file
#define SKINT_C
//-----------------------------------------------------------------------------
template<typename MeshT>
SkinT<MeshT>::SkinT(SkeletonT<PointT> *_skeleton, MeshT *_mesh) :
skeleton_(_skeleton),
mesh_(_mesh),
lastmethod_(M_LBS)
{
}
//-----------------------------------------------------------------------------
template<typename MeshT>
SkinT<MeshT>::~SkinT()
{
}
//-----------------------------------------------------------------------------
template<typename MeshT>
typename SkinT<MeshT>::Skeleton* SkinT<MeshT>::skeleton()
{
return skeleton_;
}
//-----------------------------------------------------------------------------
/**
* @brief Attach the given mesh as skin to this skeleton
*
* The mesh will be equipped with two properties. One holding the original vertex coordinates, a second
* holding the per vertex weights for the joints.
* The bone weights are derived from the segment information stored with the bones and in a vertex based
* mesh property called "Face Segment".
*/
template<typename MeshT>
void SkinT<MeshT>::attachSkin()
{
// create the skins properties
OpenMesh::VPropHandleT<DefaultPose> propDefaultPose;
OpenMesh::VPropHandleT<SkinWeights> propWeights;
//make sure properties are there
if( !mesh_->get_property_handle(propDefaultPose, DEFAULTPOSE_PROP) )
mesh_->add_property(propDefaultPose, DEFAULTPOSE_PROP);
if (! mesh_->get_property_handle(propWeights, SKIN_WEIGHTS_PROP))
mesh_->add_property(propWeights, SKIN_WEIGHTS_PROP);
// backup the default pose
for(typename MeshT::VertexIter it = mesh_->vertices_begin(); it != mesh_->vertices_end(); ++it)
mesh_->property(propDefaultPose, it) = DefaultPose(mesh_->point(it), mesh_->normal(it));
}
//-----------------------------------------------------------------------------
template<typename MeshT>
void SkinT<MeshT>::deformSkin()
{
deformSkin(lastAnimationHandle_, lastmethod_);
}
//-----------------------------------------------------------------------------
/**
* @brief Deforms the given skin to the pose defined by the skeleton
*
* This method will only work properly if the mesh has been prepared to be a skin by a call of
* SkeletonT::PrepareSkin.
*
* Two algorithms are implemented:
* - Linear Blend Skinning (LBS) or Skeletal Space Deformation (SSD), e.g. see \ref LCF00 "[2]", \ref RLN06 "[3]"
* - Spherical Blend Skinning (SBS), see \ref KZ05 "[1]"
*
* @par Linear Blend Skinning
* Every vertex will be transformed by every joint with a non-null weight. First
* of all the vertex is transformed into the coordinate system of the joint, then it is transformed back
* to the global coordinate system of the pose given by the active frame in the given animation.
*
* @par
* Since the mesh is given in the default pose the default pose joints are used to calculate the vertices
* position relative to the joint. Then they are transformed back into global coordinates using the joints
* in the current pose.
*
* @par
* The global matrices of the default pose and animation are not updated by this method, make sure to
* update them before deforming the skin or the results will be unexpected.
*
* \f[ v_{pose} = M_{pose} \cdot M^{-1}_{default} \cdot v_{default} \f]
*
*
* @param _hAni The animation frame to be used as target
* @param _method deformation method to be used @see BaseSkin.hh
*/
template<typename MeshT>
void SkinT<MeshT>::deformSkin(const AnimationHandle &_hAni, Method _method)
{
lastAnimationHandle_ = _hAni;
lastmethod_ = _method;
// first get the properties
OpenMesh::VPropHandleT<DefaultPose> propDefaultPose;
OpenMesh::VPropHandleT<SkinWeights> propWeights;
if(!mesh_->get_property_handle(propDefaultPose, DEFAULTPOSE_PROP) ||
!mesh_->get_property_handle(propWeights, SKIN_WEIGHTS_PROP))
return; // missing properties
Pose* pose = skeleton_->pose(_hAni);
int verticesWithoutWeights = 0;
// for every vertex
typename MeshT::VertexIter it;
for(it = mesh_->vertices_begin(); it != mesh_->vertices_end(); ++it)
{
// based on its position in the default pose
OpenMesh::Vec3d default_point = mesh_->property(propDefaultPose, it).point,
default_normal = mesh_->property(propDefaultPose, it).normal;
OpenMesh::Vec3d point(0, 0, 0), normal(0, 0, 0); // the new position and normal
if( _method == M_LBS ) {
// Linear blend skinning
SkinWeights &weights = mesh_->property(propWeights, it);
if (weights.size() == 0)
verticesWithoutWeights++;
SkinWeights::iterator it_w;
for(it_w = weights.begin(); it_w != weights.end(); ++it_w)
{
const Matrix &unified = pose->unifiedMatrix(it_w->first);
point += it_w->second * unified.transform_point(default_point);
normal += it_w->second * unified.transform_vector(default_normal);
}
}else if( _method == M_DBS ) {
// Dual quaternion blend skinning
std::vector<double> weightVector;
std::vector<DualQuaternion> dualQuaternions;
SkinWeights &weights = mesh_->property(propWeights, it);
SkinWeights::iterator it_w;
for(it_w = weights.begin(); it_w != weights.end(); ++it_w){
weightVector.push_back( it_w->second );
dualQuaternions.push_back( pose->unifiedDualQuaternion(it_w->first) );
}
DualQuaternion dq = DualQuaternion::interpolate(weightVector, dualQuaternions);
point = dq.transform_point(default_point);
normal = dq.transform_vector(default_normal);
} else {
std::cerr << "ERROR: Unknown skinning method!" << std::endl;
}
mesh_->set_point(it, point);
mesh_->set_normal(it, normal);
}
if ( verticesWithoutWeights > 0 )
std::cerr << "Deform skin: " << verticesWithoutWeights << " vertices without skin weights." << std::endl;
mesh_->update_face_normals();
}
//-----------------------------------------------------------------------------
/**
* @brief The given mesh will be reset to its default pose and all skin properties are removed
*/
template<typename MeshT>
void SkinT<MeshT>::releaseSkin()
{
// create the skins properties
OpenMesh::VPropHandleT<DefaultPose> propDefaultPose;
// try to restore the default pose
if(mesh_->get_property_handle(propDefaultPose, DEFAULTPOSE_PROP))
{
typename MeshT::VertexIter it;
for(it = mesh_->vertices_begin(); it != mesh_->vertices_end(); ++it)
{
mesh_->set_point(it, mesh_->property(propDefaultPose, it).point);
mesh_->set_normal(it, mesh_->property(propDefaultPose, it).normal);
}
mesh_->remove_property(propDefaultPose);
}
}
//-----------------------------------------------------------------------------
#ifndef SKINT_HH
#define SKINT_HH
#include <ObjectTypes/Skeleton/BaseSkin.hh>
/**
* @brief General skin class, used to bind skeleton and mesh and deform the mesh
*
* The mesh is given to the constructor. To prepare the mesh for deformation, call the SkinT::AttachSkin method.
*/
template<typename MeshT>
class SkinT : public BaseSkin
{
public:
typedef typename MeshT::Point PointT;
typedef PointT Point;
typedef typename PointT::value_type Scalar;
typedef SkeletonT<PointT> Skeleton;
typedef JointT<PointT> Joint;
typedef PoseT<PointT> Pose;
typedef typename ACG::Matrix4x4T<Scalar> Matrix;
typedef typename ACG::QuaternionT<Scalar> Quaternion;
typedef typename ACG::DualQuaternionT<Scalar> DualQuaternion;
public:
SkinT(SkeletonT<PointT> *_skeleton, MeshT *_mesh);
virtual ~SkinT();
public:
/**
* @name Skinning
* These methods are related to using a mesh as skin with this skeleton.
*/
//@{
void attachSkin();
void deformSkin();
void deformSkin(const AnimationHandle &_hAni, Method _method = M_LBS);
void releaseSkin();
//@}
Skeleton* skeleton();
private:
Skeleton* skeleton_;
MeshT* mesh_;
AnimationHandle lastAnimationHandle_;
Method lastmethod_;
};
typedef SkinT< TriMesh > TriMeshSkin;
typedef SkinT< PolyMesh > PolyMeshSkin;
//=============================================================================
//=============================================================================
#if defined(INCLUDE_TEMPLATES) && !defined(SKINT_C)
#define SKINT_TEMPLATES
#include "SkinT.cc"
#endif
//=============================================================================
#endif
//=============================================================================
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment