Developer Documentation
SkinT.cc
1 /* ========================================================================= *
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  * ========================================================================= */
41 
42 /*===========================================================================*\
43  *
44  * $Revision: 21010 $
45  * $Date: 2015-07-16 10:52:48 +0200 (Do, 16 Jul 2015) $
46  *
47 \*===========================================================================*/
48 
49 
50 
51 
52 
53 #ifdef USE_OPENMP
54 #include <omp.h>
55 #endif
56 #define SKINT_C
57 
58 //-----------------------------------------------------------------------------
59 
60 template<typename MeshT>
61 SkinT<MeshT>::SkinT(SkeletonT<PointT> *_skeleton, MeshT *_mesh, int _objectID) :
62  BaseSkin(_objectID),
63  skeleton_(_skeleton),
64  mesh_(_mesh),
65  objectId_(_objectID),
66  lastmethod_(M_LBS),
67  weightsComputed_(false)
68 
69 {
70 }
71 
72 //-----------------------------------------------------------------------------
73 
74 template<typename MeshT>
76 {
77 
78 }
79 
80 //-----------------------------------------------------------------------------
81 
82 template<typename MeshT>
84 {
85  return skeleton_;
86 }
87 
88 //-----------------------------------------------------------------------------
89 
98 template<typename MeshT>
100 {
101  // create the skins properties
102  OpenMesh::VPropHandleT<DefaultPose> propDefaultPose;
104 
105  //make sure properties are there
106  if( !mesh_->get_property_handle(propDefaultPose, DEFAULTPOSE_PROP) )
107  mesh_->add_property(propDefaultPose, DEFAULTPOSE_PROP);
108 
109  if (! mesh_->get_property_handle(propWeights, SKIN_WEIGHTS_PROP))
110  mesh_->add_property(propWeights, SKIN_WEIGHTS_PROP);
111 
112  // backup the default pose
113  for(typename MeshT::VertexIter it = mesh_->vertices_begin(); it != mesh_->vertices_end(); ++it)
114  mesh_->property(propDefaultPose, *it) = DefaultPose(mesh_->point(*it), mesh_->normal(*it));
115 }
116 
117 //-----------------------------------------------------------------------------
118 
119 template<typename MeshT>
121 {
122  deformSkin(lastAnimationHandle_, lastmethod_);
123 }
124 
125 //-----------------------------------------------------------------------------
126 
157 template<typename MeshT>
159 {
160  // Do not transform skin if skin weights were not computed before
161  // as the mesh entirely disappears since all vertices collapse to origin
162  if(!weightsComputed_) {
163  return;
164  }
165 
166  lastAnimationHandle_ = _hAni;
167  lastmethod_ = _method;
168 
169  // first get the properties
170  OpenMesh::VPropHandleT<DefaultPose> propDefaultPose;
172 
173  if(!mesh_->get_property_handle(propDefaultPose, DEFAULTPOSE_PROP) ||
174  !mesh_->get_property_handle(propWeights, SKIN_WEIGHTS_PROP))
175  return; // missing properties
176 
177  Pose* pose = skeleton_->pose(_hAni);
178 
179  #ifndef USE_OPENMP
180  int verticesWithoutWeights = 0;
181  #endif
182 
183  // for every vertex
184  typename MeshT::VertexIter it;
185 #ifdef USE_OPENMP
186  std::vector< OpenMesh::VertexHandle > vhandles; vhandles.clear(); vhandles.reserve(mesh_->n_vertices());
187  for(it = mesh_->vertices_begin(); it != mesh_->vertices_end(); ++it){vhandles.push_back(*it);}
188  int vhcount = (int) vhandles.size();
189  #pragma omp parallel for
190  for (int vhindex = 0; vhindex < vhcount; vhindex++)
191 #else
192  for(it = mesh_->vertices_begin(); it != mesh_->vertices_end(); ++it)
193 #endif
194  {
195  #ifdef USE_OPENMP
196  const OpenMesh::VertexHandle currentVertexH = vhandles[vhindex];
197  #else
198  const OpenMesh::VertexHandle currentVertexH = *it;
199  #endif
200 
201  // based on its position in the default pose
202  OpenMesh::Vec3d default_point = mesh_->property(propDefaultPose, currentVertexH).point,
203  default_normal = mesh_->property(propDefaultPose, currentVertexH).normal;
204 
205  OpenMesh::Vec3d point(0, 0, 0), normal(0, 0, 0); // the new position and normal
206 
207  if( _method == M_LBS ) {
208 
209  // Linear blend skinning
210  SkinWeights &weights = mesh_->property(propWeights, currentVertexH);
211 
212  #ifndef USE_OPENMP
213  if (weights.size() == 0)
214  {
215  verticesWithoutWeights++;
216  }
217  #endif
218 
219  SkinWeights::iterator it_w;
220  for(it_w = weights.begin(); it_w != weights.end(); ++it_w)
221  {
222  const Matrix &unified = pose->unifiedMatrix(it_w->first);
223 
224  point += it_w->second * unified.transform_point(default_point);
225  normal += it_w->second * unified.transform_vector(default_normal);
226  }
227 
228  }else if( _method == M_DBS ) {
229  // Dual quaternion blend skinning
230 
231  std::vector<double> weightVector;
232  std::vector<DualQuaternion> dualQuaternions;
233 
234  SkinWeights &weights = mesh_->property(propWeights, currentVertexH);
235  SkinWeights::iterator it_w;
236 
237  for(it_w = weights.begin(); it_w != weights.end(); ++it_w){
238  weightVector.push_back( it_w->second );
239  dualQuaternions.push_back( pose->unifiedDualQuaternion(it_w->first) );
240  }
241 
242  DualQuaternion dq = DualQuaternion::interpolate(weightVector, dualQuaternions);
243 
244  point = dq.transform_point(default_point);
245  normal = dq.transform_vector(default_normal);
246 
247  } else {
248  std::cerr << "ERROR: Unknown skinning method!" << std::endl;
249  }
250 
251  mesh_->set_point(currentVertexH, point);
252  mesh_->set_normal(currentVertexH, normal);
253  }
254 
255  #ifndef USE_OPENMP
256  if ( verticesWithoutWeights > 0 )
257  std::cerr << "Deform skin: " << verticesWithoutWeights << " vertices without skin weights." << std::endl;
258  #endif
259 
260  mesh_->update_face_normals();
261 }
262 
263 //-----------------------------------------------------------------------------
264 
268 template<typename MeshT>
270 {
271  // create the skins properties
272  OpenMesh::VPropHandleT<DefaultPose> propDefaultPose;
273 
274  // try to restore the default pose
275  if(mesh_->get_property_handle(propDefaultPose, DEFAULTPOSE_PROP))
276  {
277  typename MeshT::VertexIter it;
278  for(it = mesh_->vertices_begin(); it != mesh_->vertices_end(); ++it)
279  {
280  mesh_->set_point(*it, mesh_->property(propDefaultPose, *it).point);
281  mesh_->set_normal(*it, mesh_->property(propDefaultPose, *it).normal);
282  }
283  mesh_->remove_property(propDefaultPose);
284  }
285 
286  // Remove the skin weights
287  OpenMesh::VPropHandleT<SkinWeights> propSkinWeights;
288  mesh_->remove_property(propSkinWeights);
289 }
290 
291 //-----------------------------------------------------------------------------
292 
DualQuaternion class for representing rigid motions in 3d.
VectorT< T, 3 > transform_point(const VectorT< T, 3 > &_v) const
transform point (x&#39;,y&#39;,z&#39;,1) = M * (x,y,z,1)
Definition: Matrix4x4T.cc:202
std::map< unsigned int, double > SkinWeights
Stores the joint weights per vertex.
Definition: BaseSkin.hh:99
Method
Possible deformation methods.
Definition: BaseSkin.hh:109
Vec3 transform_vector(const Vec3 &_point) const
Transform a vector with the dual quaternion.
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:68
A handle used to refer to an animation or to a specific frame in an animation.
static DualQuaternion interpolate(VectorType &_weights, const std::vector< DualQuaternion > &_dualQuaternions)
linear interpolation of dual quaternions. Result is normalized afterwards
void attachSkin()
Attach the given mesh as skin to this skeleton.
Definition: SkinT.cc:99
Abstract base class for the skin template, wrapping all template versions of the skin.
Definition: BaseSkin.hh:67
Handle for a vertex entity.
Definition: Handles.hh:125
Vec3 transform_point(const Vec3 &_point) const
Transform a point with the dual quaternion.
const DualQuaternion & unifiedDualQuaternion(unsigned int _joint)
Returns a dual quaternion holding the unified matrix represented as dual quaternion.
Definition: PoseT.cc:437
SkinT(SkeletonT< PointT > *_skeleton, MeshT *_mesh, int _objectID)
constructor
Definition: SkinT.cc:61
Holds the skins default pose.
Definition: BaseSkin.hh:83
void releaseSkin()
The given mesh will be reset to its default pose and all skin properties are removed.
Definition: SkinT.cc:269
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
Definition: SkeletonT.cc:741
const Matrix & unifiedMatrix(unsigned int _joint)
Returns the unified matrix.
Definition: PoseT.cc:403
General skin class, used to bind skeleton and mesh and deform the mesh.
Definition: SkinT.hh:12
VectorT< T, 3 > transform_vector(const VectorT< T, 3 > &_v) const
transform vector (x&#39;,y&#39;,z&#39;,0) = A * (x,y,z,0)
Definition: Matrix4x4T.cc:225
void deformSkin()
Attach the given mesh as skin to this skeleton.
Definition: SkinT.cc:120