Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/math/quaternion.cc @ 7194

Last change on this file since 7194 was 7191, checked in by bensch, 19 years ago

orxonox/trunk: some better and faster slerp functions

File size: 6.7 KB
RevLine 
[4578]1/*
[2043]2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
[4578]12   main-programmer: Christian Meyer
[2551]13   co-programmer: Patrick Boenzli : Vector::scale()
14                                    Vector::abs()
[4578]15
[2190]16   Quaternion code borrowed from an Gamasutra article by Nick Bobick and Ken Shoemake
[5420]17
18   2005-06-02: Benjamin Grauer: speed up, and new Functionality to Vector (mostly inline now)
[2043]19*/
20
[3590]21#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_MATH
[2043]22
[6616]23#include "quaternion.h"
[5662]24#ifdef DEBUG
[5672]25  #include "debug.h"
[5662]26#else
[5672]27  #include <stdio.h>
28  #define PRINT(x) printf
[5662]29#endif
[2043]30
31using namespace std;
32
[4477]33/////////////////
34/* QUATERNIONS */
35/////////////////
[3541]36/**
[4836]37 *  calculates a lookAt rotation
38 * @param dir: the direction you want to look
39 * @param up: specify what direction up should be
[4578]40
[2551]41   Mathematically this determines the rotation a (0,0,1)-Vector has to undergo to point
42   the same way as dir. If you want to use this with cameras, you'll have to reverse the
43   dir Vector (Vector(0,0,0) - your viewing direction) or you'll point the wrong way. You
[4578]44   can use this for meshes as well (then you do not have to reverse the vector), but keep
45   in mind that if you do that, the model's front has to point in +z direction, and left
[2551]46   and right should be -x or +x respectively or the mesh wont rotate correctly.
[5004]47 *
[5005]48 * @TODO !!! OPTIMIZE THIS !!!
[5420]49 */
[2190]50Quaternion::Quaternion (const Vector& dir, const Vector& up)
[2551]51{
[5004]52  Vector z = dir.getNormalized();
53  Vector x = up.cross(z).getNormalized();
[2190]54  Vector y = z.cross(x);
[4578]55
[2190]56  float m[4][4];
57  m[0][0] = x.x;
58  m[0][1] = x.y;
59  m[0][2] = x.z;
60  m[0][3] = 0;
61  m[1][0] = y.x;
62  m[1][1] = y.y;
63  m[1][2] = y.z;
64  m[1][3] = 0;
65  m[2][0] = z.x;
66  m[2][1] = z.y;
67  m[2][2] = z.z;
68  m[2][3] = 0;
69  m[3][0] = 0;
70  m[3][1] = 0;
71  m[3][2] = 0;
72  m[3][3] = 1;
[4578]73
[2190]74  *this = Quaternion (m);
75}
76
77/**
[4836]78 *  calculates a rotation from euler angles
79 * @param roll: the roll in radians
80 * @param pitch: the pitch in radians
81 * @param yaw: the yaw in radians
[5420]82 */
[2190]83Quaternion::Quaternion (float roll, float pitch, float yaw)
84{
[4477]85  float cr, cp, cy, sr, sp, sy, cpcy, spsy;
[4578]86
[4477]87  // calculate trig identities
88  cr = cos(roll/2);
89  cp = cos(pitch/2);
90  cy = cos(yaw/2);
[4578]91
[4477]92  sr = sin(roll/2);
93  sp = sin(pitch/2);
94  sy = sin(yaw/2);
[4578]95
[4477]96  cpcy = cp * cy;
97  spsy = sp * sy;
[4578]98
[4477]99  w = cr * cpcy + sr * spsy;
100  v.x = sr * cpcy - cr * spsy;
101  v.y = cr * sp * cy + sr * cp * sy;
102  v.z = cr * cp * sy - sr * sp * cy;
[2190]103}
104
105/**
[4836]106 *  convert the Quaternion to a 4x4 rotational glMatrix
107 * @param m: a buffer to store the Matrix in
[5420]108 */
[2190]109void Quaternion::matrix (float m[4][4]) const
110{
[4578]111  float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
112
[2551]113  // calculate coefficients
114  x2 = v.x + v.x;
[4578]115  y2 = v.y + v.y;
[2551]116  z2 = v.z + v.z;
117  xx = v.x * x2; xy = v.x * y2; xz = v.x * z2;
118  yy = v.y * y2; yz = v.y * z2; zz = v.z * z2;
119  wx = w * x2; wy = w * y2; wz = w * z2;
[4578]120
[2551]121  m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz;
122  m[2][0] = xz + wy; m[3][0] = 0.0;
[4578]123
[2551]124  m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz);
125  m[2][1] = yz - wx; m[3][1] = 0.0;
[4578]126
[2551]127  m[0][2] = xz - wy; m[1][2] = yz + wx;
128  m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0;
[4578]129
[2551]130  m[0][3] = 0; m[1][3] = 0;
131  m[2][3] = 0; m[3][3] = 1;
[2190]132}
133
[7191]134
[3449]135/**
[7191]136 * Slerps this QUaternion performs a smooth move.
137 * @param toQuat to this Quaternion
138 * @param t \% inth the the direction[0..1]
139 */
140void Quaternion::slerpTo(const Quaternion& toQuat, float t)
141{
142  float tol[4];
143  double omega, cosom, sinom, scale0, scale1;
144  //  float DELTA = 0.2;
145
146  cosom = this->v.x * toQuat.v.x + this->v.y * toQuat.v.y + this->v.z * toQuat.v.z + this->w * toQuat.w;
147
148  if( cosom < 0.0 )
149  {
150    cosom = -cosom;
151    tol[0] = -toQuat.v.x;
152    tol[1] = -toQuat.v.y;
153    tol[2] = -toQuat.v.z;
154    tol[3] = -toQuat.w;
155  }
156  else
157  {
158    tol[0] = toQuat.v.x;
159    tol[1] = toQuat.v.y;
160    tol[2] = toQuat.v.z;
161    tol[3] = toQuat.w;
162  }
163
164  omega = acos(cosom);
165  sinom = sin(omega);
166  scale0 = sin((1.0 - t) * omega) / sinom;
167  scale1 = sin(t * omega) / sinom;
168  this->v = Vector(scale0 * this->v.x + scale1 * tol[0],
169                    scale0 * this->v.y + scale1 * tol[1],
170                    scale0 * this->v.z + scale1 * tol[2]);
171  this->w = scale0 * this->w + scale1 * tol[3];
172}
173
174
175/**
[4836]176 *  performs a smooth move.
177 * @param from  where
178 * @param to where
179 * @param t the time this transformation should take value [0..1]
180 * @returns the Result of the smooth move
[5420]181 */
[4998]182Quaternion Quaternion::quatSlerp(const Quaternion& from, const Quaternion& to, float t)
[2551]183{
184  float tol[4];
185  double omega, cosom, sinom, scale0, scale1;
[3971]186  //  float DELTA = 0.2;
[2551]187
[3966]188  cosom = from.v.x * to.v.x + from.v.y * to.v.y + from.v.z * to.v.z + from.w * to.w;
[2551]189
[4578]190  if( cosom < 0.0 )
191    {
192      cosom = -cosom;
[3966]193      tol[0] = -to.v.x;
194      tol[1] = -to.v.y;
195      tol[2] = -to.v.z;
196      tol[3] = -to.w;
[2551]197    }
198  else
199    {
[3966]200      tol[0] = to.v.x;
201      tol[1] = to.v.y;
202      tol[2] = to.v.z;
203      tol[3] = to.w;
[2551]204    }
[4578]205
[3966]206  omega = acos(cosom);
207  sinom = sin(omega);
208  scale0 = sin((1.0 - t) * omega) / sinom;
209  scale1 = sin(t * omega) / sinom;
[3971]210  return Quaternion(Vector(scale0 * from.v.x + scale1 * tol[0],
[5420]211                    scale0 * from.v.y + scale1 * tol[1],
212                    scale0 * from.v.z + scale1 * tol[2]),
[4578]213                    scale0 * from.w + scale1 * tol[3]);
[2551]214}
215
216
[2190]217/**
[4836]218 *  convert a rotational 4x4 glMatrix into a Quaternion
219 * @param m: a 4x4 matrix in glMatrix order
[5420]220 */
[2190]221Quaternion::Quaternion (float m[4][4])
222{
[4578]223
[2551]224  float  tr, s, q[4];
225  int    i, j, k;
226
227  int nxt[3] = {1, 2, 0};
228
229  tr = m[0][0] + m[1][1] + m[2][2];
230
[4578]231        // check the diagonal
232  if (tr > 0.0)
[2551]233  {
234    s = sqrt (tr + 1.0);
235    w = s / 2.0;
236    s = 0.5 / s;
237    v.x = (m[1][2] - m[2][1]) * s;
238    v.y = (m[2][0] - m[0][2]) * s;
239    v.z = (m[0][1] - m[1][0]) * s;
[4578]240        }
241        else
242        {
243                // diagonal is negative
244        i = 0;
245        if (m[1][1] > m[0][0]) i = 1;
[2551]246    if (m[2][2] > m[i][i]) i = 2;
247    j = nxt[i];
248    k = nxt[j];
249
250    s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
[4578]251
[2551]252    q[i] = s * 0.5;
[4578]253
[2551]254    if (s != 0.0) s = 0.5 / s;
[4578]255
256          q[3] = (m[j][k] - m[k][j]) * s;
[2551]257    q[j] = (m[i][j] + m[j][i]) * s;
258    q[k] = (m[i][k] + m[k][i]) * s;
259
[4578]260        v.x = q[0];
261        v.y = q[1];
262        v.z = q[2];
263        w = q[3];
[2190]264  }
265}
266
267/**
[4836]268 *  outputs some nice formated debug information about this quaternion
[3541]269*/
[7003]270void Quaternion::debug() const
[3541]271{
272  PRINT(0)("real a=%f; imag: x=%f y=%f z=%f\n", w, v.x, v.y, v.z);
273}
274
[7003]275void Quaternion::debug2() const
[5000]276{
277  Vector axis = this->getSpacialAxis();
278  PRINT(0)("angle = %f, axis: ax=%f, ay=%f, az=%f\n", this->getSpacialAxisAngle(), axis.x, axis.y, axis.z );
279}
Note: See TracBrowser for help on using the repository browser.