Developer Documentation

SkinT_impl.hh
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_(Blending::M_LBS),
67 weightsComputed_(false)
68
69 {
70 }
71
72 //-----------------------------------------------------------------------------
73
74 template<typename MeshT>
75 SkinT<MeshT>::~SkinT()
76 {
77
78 }
79
80 //-----------------------------------------------------------------------------
81
82 template<typename MeshT>
83 typename SkinT<MeshT>::Skeleton* SkinT<MeshT>::skeleton()
84 {
85 return skeleton_;
86 }
87
88 //-----------------------------------------------------------------------------
89
98 template<typename MeshT>
99 void SkinT<MeshT>::attachSkin()
100 {
101 // create the skins properties
102 OpenMesh::VPropHandleT<DefaultPose> propDefaultPose;
103 OpenMesh::VPropHandleT<SkinWeights> propWeights;
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>
120 void SkinT<MeshT>::deformSkin()
121 {
122 deformSkin(lastAnimationHandle_, lastmethod_);
123 }
124
125 //-----------------------------------------------------------------------------
126
157 template<typename MeshT>
158 void SkinT<MeshT>::deformSkin(const AnimationHandle &_hAni, Blending::Method _method)
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;
171 OpenMesh::VPropHandleT<SkinWeights> propWeights;
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 == Blending::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 == Blending::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>
269 void SkinT<MeshT>::releaseSkin()
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
BaseSkin
Abstract base class for the skin template, wrapping all template versions of the skin.
Definition: BaseSkin.hh:62
OpenMesh::VertexHandle
Handle for a vertex entity.
Definition: Handles.hh:120
PoseT::unifiedDualQuaternion
const DualQuaternion & unifiedDualQuaternion(size_t _joint)
Returns a dual quaternion holding the unified matrix represented as dual quaternion.
Definition: PoseT_impl.hh:431
SkinT::releaseSkin
void releaseSkin()
The given mesh will be reset to its default pose and all skin properties are removed.
Definition: SkinT_impl.hh:269
SkeletonT
Definition: JointT.hh:50
BaseSkin::DefaultPose
Holds the skins default pose.
Definition: BaseSkin.hh:78
ACG::Matrix4x4T::transform_point
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_impl.hh:196
PoseT
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:58
ACG::DualQuaternionT::transform_vector
Vec3 transform_vector(const Vec3 &_point) const
Transform a vector with the dual quaternion.
Definition: DualQuaternionT_impl.hh:395
SkinT::attachSkin
void attachSkin()
Attach the given mesh as skin to this skeleton.
Definition: SkinT_impl.hh:99
AnimationHandle
A handle used to refer to an animation or to a specific frame in an animation.
Definition: AnimationHandle.hh:47
SkinT
General skin class, used to bind skeleton and mesh and deform the mesh.
Definition: SkinT.hh:14
ACG::DualQuaternionT::interpolate
static DualQuaternion interpolate(VectorType &_weights, const std::vector< DualQuaternion > &_dualQuaternions)
linear interpolation of dual quaternions. Result is normalized afterwards
SkinT::SkinT
SkinT(SkeletonT< PointT > *_skeleton, MeshT *_mesh, int _objectID)
constructor
Definition: SkinT_impl.hh:61
SkeletonT::pose
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
Definition: SkeletonT_impl.hh:735
BaseSkin::SkinWeights
std::map< unsigned int, double > SkinWeights
Stores the joint weights per vertex.
Definition: BaseSkin.hh:94
ACG::Matrix4x4T
Definition: Matrix4x4T.hh:92
ACG::DualQuaternionT
DualQuaternion class for representing rigid motions in 3d.
Definition: DualQuaternionT.hh:80
PoseT::unifiedMatrix
const Matrix & unifiedMatrix(size_t _joint)
Returns the unified matrix.
Definition: PoseT_impl.hh:397
OpenMesh::VectorT< double, 3 >
ACG::DualQuaternionT::transform_point
Vec3 transform_point(const Vec3 &_point) const
Transform a point with the dual quaternion.
Definition: DualQuaternionT_impl.hh:366
SkinT::deformSkin
void deformSkin()
Attach the given mesh as skin to this skeleton.
Definition: SkinT_impl.hh:120
ACG::Matrix4x4T::transform_vector
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_impl.hh:219
Blending
Definition: BlendingMethod.hh:4
OpenMesh::VPropHandleT
Definition: Property.hh:482