Developer Documentation
SkeletonTransform.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#include "SkeletonTransform.hh"
46//-----------------------------------------------------------------------------
47
49SkeletonTransform::SkeletonTransform(Skeleton& _skeleton) : skeleton_(_skeleton)
50{
51 refPose_ = skeleton_.referencePose();
52}
53
54//-----------------------------------------------------------------------------
55
66
67 // note: scaling the root joints is important since this controls e.g. the size of foot steps
68
69 if ( _pose == 0)
70 _pose = refPose_;
71
72 //scale bones in the given pose
73 for (Skeleton::Iterator it = skeleton_.begin(); it != skeleton_.end(); ++it )
74 _pose->setLocalTranslation( (*it)->id(), _pose->localTranslation((*it)->id()) * _factor );
75
76 // if given pose is refPose
77 if ( _pose == refPose_){
78 //scale bones in the animations
79 for (size_t a=0; a < skeleton_.animationCount(); a++)
80 for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
81
82 Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
83
84 if ( pose == refPose_ )
85 continue;
86
87 for (Skeleton::Iterator it = skeleton_.begin(); it != skeleton_.end(); ++it )
88 pose->setLocalTranslation( (*it)->id(), pose->localTranslation((*it)->id()) * _factor );
89 }
90 }
91}
92
93//-----------------------------------------------------------------------------
94
107
108 if ( _pose == 0)
109 _pose = refPose_;
110
111 //apply the transformation to given pose
112 ACG::Vec3d position = _pose->globalTranslation( 0 );
113 _pose->setGlobalTranslation( 0, position + _translation );
114
115 // apply to all animations if the refpose was changed
116 if ( _pose == refPose_ ){
117
118 // apply transformation to all frames of all animations
119 for (unsigned int a=0; a < skeleton_.animationCount(); a++)
120 for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
121
122 Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
123
124 if ( pose == refPose_ )
125 continue;
126
127 ACG::Vec3d globalTranslation = pose->globalTranslation( 0 );
128 pose->setGlobalTranslation( 0, globalTranslation + _translation );
129 }
130 }
131}
132
133//-----------------------------------------------------------------------------
134
144
145 if ( _pose == 0)
146 _pose = refPose_;
147
148 //apply the transformation to given pose
149 ACG::Matrix4x4d local = _pose->localMatrix( 0 );
150 _pose->setLocalMatrix( 0, _transformation * local );
151
152 // apply to all animations if the refpose was changed
153 if ( _pose == refPose_ ){
154
155 // apply transformation to all frames of all animations
156 for (unsigned int a=0; a < skeleton_.animationCount(); a++)
157 for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
158
159 Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
160
161 if ( pose == refPose_ )
162 continue;
163
164 ACG::Matrix4x4d localMatrix = pose->localMatrix( 0 );
165 pose->setLocalMatrix( 0, _transformation * localMatrix );
166 }
167 }
168}
169
170//-----------------------------------------------------------------------------
171
186void SkeletonTransform::transformJoint(Skeleton::Joint* _joint, Matrix4x4 _matrix, bool _keepChildPositions) {
187
188 if (_joint == 0)
189 return;
190
191 Matrix4x4 transform;
192 transform.identity();
193
194 //get transformation matrix
195 Skeleton::Joint* parent = _joint->parent();
196
197 if ( parent != 0 )
198 // new GlobalMatrix after application of _matrix is: newGlobal = _matrix * activePose->getGlobal( joint )
199 // new LocalMatrix : activePose->getGlobalInv( parent->getID() ) * newGlobal
200 // Transformation from LocalMatrix to new LocalMatrix:
201 transform = refPose_->globalMatrixInv( parent->id() ) * _matrix * refPose_->globalMatrix( _joint->id() ) * refPose_->localMatrixInv( _joint->id() );
202 else
203 // the transformation for the root joint has to be applied directly
204 // _matrix defines a post-multiplication but we need a pre-multiplication matrix X in order to apply
205 // the transformation to all frames: _matrix * Global = Global * X --> X = GlobalInverse * _matrix * global
206 transform = refPose_->globalMatrixInv( _joint->id() ) * _matrix * refPose_->globalMatrix( _joint->id() );
207
208
209 //transform refPose
210 if ( parent != 0 ){
211
212 Matrix4x4 newMatrix = transform * refPose_->localMatrix( _joint->id() );
213 refPose_->setLocalMatrix( _joint->id(), newMatrix, !_keepChildPositions); //keep child for local means !keepChild global
214
215 } else {
216 //directly apply the global transformation
217 Matrix4x4 newMatrix = refPose_->globalMatrix( _joint->id() ) * transform;
218 refPose_->setLocalMatrix( _joint->id(), newMatrix, !_keepChildPositions);
219 }
220
221 // apply transformation to all frames of all animations
222 for (unsigned int a=0; a < skeleton_.animationCount(); a++)
223 for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
224
225 Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
226
227 if ( parent != 0 ){
228
229 //transform the local matrix
230 Matrix4x4 newMatrix = transform * pose->localMatrix( _joint->id() );
231 pose->setLocalMatrix( _joint->id(), newMatrix, !_keepChildPositions);
232
233 // the transformation may have changed two things
234 // 1. due to the changed length of neighboring bones the rotation
235 // angle changes this has to be corrected by rotating the coord-frame
236 // 2. the length of the bone to a child may have changed. Check that
237 // the length is the same like in the refPose
238
239 } else {
240
241 //directly apply the global transformation
242 Matrix4x4 newMatrix = pose->globalMatrix( _joint->id() ) * transform;
243
244 pose->setLocalMatrix( _joint->id(), newMatrix, !_keepChildPositions);
245 }
246 }
247}
248
249//-----------------------------------------------------------------------------
250
265void SkeletonTransform::translateJoint(Skeleton::Joint* _joint, ACG::Vec3d _translation, bool _keepChildPositions) {
266 ACG::GLMatrixd transformation;
267 transformation.identity();
268 transformation.translate( _translation );
269
270 transformJoint(_joint, transformation, _keepChildPositions);
271}
272
273//-----------------------------------------------------------------------------
274
285void SkeletonTransform::rotateJoint(Skeleton::Joint* _joint, Skeleton::Pose* _pose, Matrix4x4 _rotation, bool _applyToWholeAnimation) {
286
287 if (_joint == 0)
288 return;
289
290 if ( fabs(1.0 - determinant(_rotation)) > 1E-6 ){
291 std::cerr << "Cannot rotate joint. Matrix is not a rotation matrix (det:" << determinant(_rotation) << ")" << std::endl;
292 return;
293 }
294
295 Matrix4x4 transform;
296 transform.identity();
297
298 //get transformation matrix
299 Skeleton::Joint* parent = _joint->parent();
300
301 if ( parent != 0 )
302 // new GlobalMatrix after application of _matrix is: newGlobal = _matrix * activePose->getGlobal( joint )
303 // new LocalMatrix : activePose->getGlobalInv( parent->getID() ) * newGlobal
304 // Transformation from LocalMatrix to new LocalMatrix:
305 transform = _pose->globalMatrixInv( parent->id() ) * _rotation * _pose->globalMatrix( _joint->id() ) * _pose->localMatrixInv( _joint->id() );
306 else
307 // the transformation for the root joint has to be applied directly
308 // _matrix defines a post-multiplication but we need a pre-multiplication matrix X in order to apply
309 // the transformation to all frames: _matrix * Global = Global * X --> X = GlobalInverse * _matrix * global
310 transform = _pose->globalMatrixInv( _joint->id() ) * _rotation * _pose->globalMatrix( _joint->id() );
311
312
313 //transform pose
314 if ( (_pose == refPose_) || !_applyToWholeAnimation ){
315
316 if ( parent != 0 ){
317
318 Matrix4x4 newMatrix = transform * _pose->localMatrix( _joint->id() );
319 _pose->setLocalMatrix( _joint->id(), newMatrix);
320
321 } else {
322
323 //directly apply the global transformation
324 Matrix4x4 newMatrix = _pose->globalMatrix( _joint->id() ) * transform;
325 _pose->setLocalMatrix( _joint->id(), newMatrix);
326 }
327 }
328
329 //TODO don't apply to all frames but only to those belonging to the same animation as _pose
330 if ( _applyToWholeAnimation ){
331 // apply transformation to all frames of all animations
332 for (unsigned int a=0; a < skeleton_.animationCount(); a++)
333 for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
334
335 Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
336
337 if ( parent != 0 ){
338 //transform the local matrix
339 Matrix4x4 newMatrix = transform * pose->localMatrix( _joint->id() );
340
341 pose->setLocalMatrix( _joint->id(), newMatrix);
342
343 } else {
344
345 //directly apply the global transformation
346 Matrix4x4 newMatrix = pose->globalMatrix( _joint->id() ) * transform;
347
348 pose->setLocalMatrix( _joint->id(), newMatrix);
349 }
350 }
351 }
352}
353
354//-----------------------------------------------------------------------------
355
356
358 double value;
359
360 value =
361 _m(0,3) * _m(1,2) * _m(2,1) * _m(3,0)-_m(0,2) * _m(1,3) * _m(2,1) * _m(3,0)-_m(0,3) * _m(1,1) * _m(2,2) * _m(3,0)+_m(0,1) * _m(1,3) * _m(2,2) * _m(3,0)+
362 _m(0,2) * _m(1,1) * _m(2,3) * _m(3,0)-_m(0,1) * _m(1,2) * _m(2,3) * _m(3,0)-_m(0,3) * _m(1,2) * _m(2,0) * _m(3,1)+_m(0,2) * _m(1,3) * _m(2,0) * _m(3,1)+
363 _m(0,3) * _m(1,0) * _m(2,2) * _m(3,1)-_m(0,0) * _m(1,3) * _m(2,2) * _m(3,1)-_m(0,2) * _m(1,0) * _m(2,3) * _m(3,1)+_m(0,0) * _m(1,2) * _m(2,3) * _m(3,1)+
364 _m(0,3) * _m(1,1) * _m(2,0) * _m(3,2)-_m(0,1) * _m(1,3) * _m(2,0) * _m(3,2)-_m(0,3) * _m(1,0) * _m(2,1) * _m(3,2)+_m(0,0) * _m(1,3) * _m(2,1) * _m(3,2)+
365 _m(0,1) * _m(1,0) * _m(2,3) * _m(3,2)-_m(0,0) * _m(1,1) * _m(2,3) * _m(3,2)-_m(0,2) * _m(1,1) * _m(2,0) * _m(3,3)+_m(0,1) * _m(1,2) * _m(2,0) * _m(3,3)+
366 _m(0,2) * _m(1,0) * _m(2,1) * _m(3,3)-_m(0,0) * _m(1,2) * _m(2,1) * _m(3,3)-_m(0,1) * _m(1,0) * _m(2,2) * _m(3,3)+_m(0,0) * _m(1,1) * _m(2,2) * _m(3,3);
367
368 return value;
369}
Functions for geometric operations related to angles.
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
void identity()
setup an identity matrix
Represents a single joint in the skeleton.
Definition: JointT.hh:61
size_t id() const
returns the joint id
Definition: JointT_impl.hh:97
Joint * parent()
Returns the parent joint.
Definition: JointT_impl.hh:156
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:59
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
Definition: PoseT_impl.hh:120
Matrix localMatrixInv(unsigned int _joint) const
Simply returns the inverse of the local matrix.
Definition: PoseT_impl.hh:176
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
Definition: PoseT_impl.hh:104
void setGlobalTranslation(unsigned int _joint, const Vector &_position, bool _keepGlobalChildPositions=true)
Sets the global translation vector.
Definition: PoseT_impl.hh:249
void setLocalTranslation(unsigned int _joint, const Vector &_position, bool _keepLocalChildPositions=true)
Sets the local translation vector.
Definition: PoseT_impl.hh:161
const Matrix & globalMatrix(unsigned int _joint) const
Returns the global matrix for the given joint.
Definition: PoseT_impl.hh:193
Vector localTranslation(unsigned int _joint)
Returns the local translation vector.
Definition: PoseT_impl.hh:139
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
Definition: PoseT_impl.hh:227
virtual Matrix globalMatrixInv(unsigned int _joint) const
Simply returns the inverse of the global matrix.
Definition: PoseT_impl.hh:267
Iterator class for the skeleton.
Definition: SkeletonT.hh:83
Pose * referencePose()
Returns a pointer to the reference pose.
Iterator begin()
Iterator over joints of the skeletal tree in TOP-DOWN order (from root to leafs)
size_t animationCount()
Returns the number of animations stored in this skeleton.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
void scaleSkeleton(double _factor, Skeleton::Pose *_pose=0)
scale all bones of the skeleton by the given factor
void transformJoint(Skeleton::Joint *_joint, Matrix4x4 _matrix, bool _keepChildPositions=true)
apply a transformation to a joint in the refPose
void rotateJoint(Skeleton::Joint *_joint, Skeleton::Pose *_pose, Matrix4x4 _rotation, bool _applyToWholeAnimation=true)
rotate a joint in an arbitrary Pose
static double determinant(const Matrix4x4 &_m)
compute determinant to check if matrix is rotation matrix
void translateJoint(Skeleton::Joint *_joint, ACG::Vec3d _translation, bool _keepChildPositions=true)
apply a translation to a joint in the refPose
SkeletonTransform(Skeleton &_skeleton)
Le constructeur.
void translateSkeleton(ACG::Vec3d _translation, Skeleton::Pose *_pose=0)
translate the skeleton
void transformSkeleton(Matrix4x4 _transformation, Skeleton::Pose *_pose=0)
transform the skeleton