Skylicht Engine
Loading...
Searching...
No Matches
quaternion.h
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#ifndef __IRR_QUATERNION_H_INCLUDED__
6#define __IRR_QUATERNION_H_INCLUDED__
7
8#include "irrTypes.h"
9#include "irrMath.h"
10#include "matrix4.h"
11#include "vector3d.h"
12
13// Between Irrlicht 1.7 and Irrlicht 1.8 the quaternion-matrix conversions got fixed.
14// This define disables all involved functions completely to allow finding all places
15// where the wrong conversions had been in use.
16#define IRR_TEST_BROKEN_QUATERNION_USE 0
17
18namespace irr
19{
20namespace core
21{
22
24
27{
28 public:
29
31 quaternion() : X(0.0f), Y(0.0f), Z(0.0f), W(1.0f) {}
32
34 quaternion(f32 x, f32 y, f32 z, f32 w) : X(x), Y(y), Z(z), W(w) { }
35
37 quaternion(f32 x, f32 y, f32 z);
38
40 quaternion(const vector3df& vec);
41
42#if !IRR_TEST_BROKEN_QUATERNION_USE
44 quaternion(const matrix4& mat);
45#endif
46
48 bool operator==(const quaternion& other) const;
49
51 bool operator!=(const quaternion& other) const;
52
54 inline quaternion& operator=(const quaternion& other);
55
56#if !IRR_TEST_BROKEN_QUATERNION_USE
58 inline quaternion& operator=(const matrix4& other);
59#endif
60
62 quaternion operator+(const quaternion& other) const;
63
65 quaternion operator*(const quaternion& other) const;
66
68 quaternion operator*(f32 s) const;
69
72
74 vector3df operator*(const vector3df& v) const;
75
77 quaternion& operator*=(const quaternion& other);
78
80 inline f32 dotProduct(const quaternion& other) const;
81
83 inline quaternion& set(f32 x, f32 y, f32 z, f32 w);
84
86 inline quaternion& set(f32 x, f32 y, f32 z);
87
89 inline quaternion& set(const core::vector3df& vec);
90
92 inline quaternion& set(const core::quaternion& quat);
93
95 inline bool equals(const quaternion& other,
96 const f32 tolerance = ROUNDING_ERROR_f32 ) const;
97
99 inline quaternion& normalize();
100
101#if !IRR_TEST_BROKEN_QUATERNION_USE
103 matrix4 getMatrix() const;
104#endif
105
107 void getMatrix( matrix4 &dest, const core::vector3df &translation ) const;
108 void getMatrix( matrix4 &dest) const;
109
127 void getMatrixCenter( matrix4 &dest, const core::vector3df &center, const core::vector3df &translation ) const;
128
130 inline void getMatrix_transposed( matrix4 &dest ) const;
131
134
136
142 quaternion& lerp(quaternion q1, quaternion q2, f32 time);
143
145
157 f32 time, f32 threshold=.05f);
158
160
165 quaternion& fromAngleAxis (f32 angle, const vector3df& axis);
166
168 void toAngleAxis (f32 &angle, core::vector3df& axis) const;
169
171 void toEuler(vector3df& euler) const;
172
175
177 quaternion& rotationFromTo(const vector3df& from, const vector3df& to);
178
180 f32 X; // vectorial (imaginary) part
181 f32 Y;
182 f32 Z;
183 f32 W; // real part
184};
185
186
187// Constructor which converts euler angles to a quaternion
189{
190 set(x,y,z);
191}
192
193
194// Constructor which converts euler angles to a quaternion
196{
197 set(vec.X,vec.Y,vec.Z);
198}
199
200#if !IRR_TEST_BROKEN_QUATERNION_USE
201// Constructor which converts a matrix to a quaternion
203{
204 (*this) = mat;
205}
206#endif
207
208// equal operator
209inline bool quaternion::operator==(const quaternion& other) const
210{
211 return ((X == other.X) &&
212 (Y == other.Y) &&
213 (Z == other.Z) &&
214 (W == other.W));
215}
216
217// inequality operator
218inline bool quaternion::operator!=(const quaternion& other) const
219{
220 return !(*this == other);
221}
222
223// assignment operator
225{
226 X = other.X;
227 Y = other.Y;
228 Z = other.Z;
229 W = other.W;
230 return *this;
231}
232
233#if !IRR_TEST_BROKEN_QUATERNION_USE
234// matrix assignment operator
236{
237 const f32 diag = m[0] + m[5] + m[10] + 1;
238
239 if( diag > 0.0f )
240 {
241 const f32 scale = sqrtf(diag) * 2.0f; // get scale from diagonal
242
243 // TODO: speed this up
244 X = (m[6] - m[9]) / scale;
245 Y = (m[8] - m[2]) / scale;
246 Z = (m[1] - m[4]) / scale;
247 W = 0.25f * scale;
248 }
249 else
250 {
251 if (m[0]>m[5] && m[0]>m[10])
252 {
253 // 1st element of diag is greatest value
254 // find scale according to 1st element, and double it
255 const f32 scale = sqrtf(1.0f + m[0] - m[5] - m[10]) * 2.0f;
256
257 // TODO: speed this up
258 X = 0.25f * scale;
259 Y = (m[4] + m[1]) / scale;
260 Z = (m[2] + m[8]) / scale;
261 W = (m[6] - m[9]) / scale;
262 }
263 else if (m[5]>m[10])
264 {
265 // 2nd element of diag is greatest value
266 // find scale according to 2nd element, and double it
267 const f32 scale = sqrtf(1.0f + m[5] - m[0] - m[10]) * 2.0f;
268
269 // TODO: speed this up
270 X = (m[4] + m[1]) / scale;
271 Y = 0.25f * scale;
272 Z = (m[9] + m[6]) / scale;
273 W = (m[8] - m[2]) / scale;
274 }
275 else
276 {
277 // 3rd element of diag is greatest value
278 // find scale according to 3rd element, and double it
279 const f32 scale = sqrtf(1.0f + m[10] - m[0] - m[5]) * 2.0f;
280
281 // TODO: speed this up
282 X = (m[8] + m[2]) / scale;
283 Y = (m[9] + m[6]) / scale;
284 Z = 0.25f * scale;
285 W = (m[1] - m[4]) / scale;
286 }
287 }
288
289 return normalize();
290}
291#endif
292
293
294// multiplication operator
296{
297 quaternion tmp;
298
299 tmp.W = (other.W * W) - (other.X * X) - (other.Y * Y) - (other.Z * Z);
300 tmp.X = (other.W * X) + (other.X * W) + (other.Y * Z) - (other.Z * Y);
301 tmp.Y = (other.W * Y) + (other.Y * W) + (other.Z * X) - (other.X * Z);
302 tmp.Z = (other.W * Z) + (other.Z * W) + (other.X * Y) - (other.Y * X);
303
304 return tmp;
305}
306
307
308// multiplication operator
310{
311 return quaternion(s*X, s*Y, s*Z, s*W);
312}
313
314
315// multiplication operator
317{
318 X*=s;
319 Y*=s;
320 Z*=s;
321 W*=s;
322 return *this;
323}
324
325// multiplication operator
327{
328 return (*this = other * (*this));
329}
330
331// add operator
333{
334 return quaternion(X+b.X, Y+b.Y, Z+b.Z, W+b.W);
335}
336
337#if !IRR_TEST_BROKEN_QUATERNION_USE
338// Creates a matrix from this quaternion
340{
342 getMatrix(m);
343 return m;
344}
345#endif
346
350inline void quaternion::getMatrix( matrix4 &dest) const
351{
352 irr::f32 *m = dest.pointer();
353
354 m[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
355 m[1] = 2.0f*X*Y + 2.0f*Z*W;
356 m[2] = 2.0f*X*Z - 2.0f*Y*W;
357 m[3] = 0.0f;
358
359 m[4] = 2.0f*X*Y - 2.0f*Z*W;
360 m[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
361 m[6] = 2.0f*Z*Y + 2.0f*X*W;
362 m[7] = 0.0f;
363
364 m[8] = 2.0f*X*Z + 2.0f*Y*W;
365 m[9] = 2.0f*Z*Y - 2.0f*X*W;
366 m[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
367 m[11] = 0.0f;
368
369 m[12] = 0.0f;
370 m[13] = 0.0f;
371 m[14] = 0.0f;
372 m[15] = 1.f;
373
374 dest.setDefinitelyIdentityMatrix ( false );
375}
376
378 const core::vector3df &center) const
379{
380 irr::f32 *m = dest.pointer();
381
382 m[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
383 m[1] = 2.0f*X*Y + 2.0f*Z*W;
384 m[2] = 2.0f*X*Z - 2.0f*Y*W;
385 m[3] = 0.0f;
386
387 m[4] = 2.0f*X*Y - 2.0f*Z*W;
388 m[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
389 m[6] = 2.0f*Z*Y + 2.0f*X*W;
390 m[7] = 0.0f;
391
392 m[8] = 2.0f*X*Z + 2.0f*Y*W;
393 m[9] = 2.0f*Z*Y - 2.0f*X*W;
394 m[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
395 m[11] = 0.0f;
396
397 m[12] = center.X;
398 m[13] = center.Y;
399 m[14] = center.Z;
400 m[15] = 1.f;
401
402 dest.setDefinitelyIdentityMatrix ( false );
403}
404
405
419 const core::vector3df &center,
420 const core::vector3df &translation) const
421{
422 dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
423 dest[1] = 2.0f*X*Y + 2.0f*Z*W;
424 dest[2] = 2.0f*X*Z - 2.0f*Y*W;
425 dest[3] = 0.0f;
426
427 dest[4] = 2.0f*X*Y - 2.0f*Z*W;
428 dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
429 dest[6] = 2.0f*Z*Y + 2.0f*X*W;
430 dest[7] = 0.0f;
431
432 dest[8] = 2.0f*X*Z + 2.0f*Y*W;
433 dest[9] = 2.0f*Z*Y - 2.0f*X*W;
434 dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
435 dest[11] = 0.0f;
436
437 dest.setRotationCenter ( center, translation );
438}
439
440// Creates a matrix from this quaternion
442{
443 dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
444 dest[4] = 2.0f*X*Y + 2.0f*Z*W;
445 dest[8] = 2.0f*X*Z - 2.0f*Y*W;
446 dest[12] = 0.0f;
447
448 dest[1] = 2.0f*X*Y - 2.0f*Z*W;
449 dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
450 dest[9] = 2.0f*Z*Y + 2.0f*X*W;
451 dest[13] = 0.0f;
452
453 dest[2] = 2.0f*X*Z + 2.0f*Y*W;
454 dest[6] = 2.0f*Z*Y - 2.0f*X*W;
455 dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
456 dest[14] = 0.0f;
457
458 dest[3] = 0.f;
459 dest[7] = 0.f;
460 dest[11] = 0.f;
461 dest[15] = 1.f;
462
463 dest.setDefinitelyIdentityMatrix(false);
464}
465
466
467// Inverts this quaternion
469{
470 X = -X; Y = -Y; Z = -Z;
471 return *this;
472}
473
474
475// sets new quaternion
477{
478 X = x;
479 Y = y;
480 Z = z;
481 W = w;
482 return *this;
483}
484
485
486// sets new quaternion based on euler angles
488{
489 f64 angle;
490
491 angle = x * 0.5;
492 const f64 sr = sin(angle);
493 const f64 cr = cos(angle);
494
495 angle = y * 0.5;
496 const f64 sp = sin(angle);
497 const f64 cp = cos(angle);
498
499 angle = z * 0.5;
500 const f64 sy = sin(angle);
501 const f64 cy = cos(angle);
502
503 const f64 cpcy = cp * cy;
504 const f64 spcy = sp * cy;
505 const f64 cpsy = cp * sy;
506 const f64 spsy = sp * sy;
507
508 X = (f32)(sr * cpcy - cr * spsy);
509 Y = (f32)(cr * spcy + sr * cpsy);
510 Z = (f32)(cr * cpsy - sr * spcy);
511 W = (f32)(cr * cpcy + sr * spsy);
512
513 return normalize();
514}
515
516// sets new quaternion based on euler angles
518{
519 return set(vec.X, vec.Y, vec.Z);
520}
521
522// sets new quaternion based on other quaternion
524{
525 return (*this=quat);
526}
527
528
530inline bool quaternion::equals(const quaternion& other, const f32 tolerance) const
531{
532 return core::equals(X, other.X, tolerance) &&
533 core::equals(Y, other.Y, tolerance) &&
534 core::equals(Z, other.Z, tolerance) &&
535 core::equals(W, other.W, tolerance);
536}
537
538
539// normalizes the quaternion
541{
542 const f32 n = X*X + Y*Y + Z*Z + W*W;
543
544 if (n == 1)
545 return *this;
546
547 //n = 1.0f / sqrtf(n);
548 return (*this *= reciprocal_squareroot ( n ));
549}
550
551
552// set this quaternion to the result of the linear interpolation between two quaternions
554{
555 const f32 scale = 1.0f - time;
556 return (*this = (q1*scale) + (q2*time));
557}
558
559
560// set this quaternion to the result of the interpolation between two quaternions
561inline quaternion& quaternion::slerp(quaternion q1, quaternion q2, f32 time, f32 threshold)
562{
563 f32 angle = q1.dotProduct(q2);
564
565 // make sure we use the short rotation
566 if (angle < 0.0f)
567 {
568 q1 *= -1.0f;
569 angle *= -1.0f;
570 }
571
572 if (angle <= (1-threshold)) // spherical interpolation
573 {
574 const f32 theta = acosf(angle);
575 const f32 invsintheta = reciprocal(sinf(theta));
576 const f32 scale = sinf(theta * (1.0f-time)) * invsintheta;
577 const f32 invscale = sinf(theta * time) * invsintheta;
578 return (*this = (q1*scale) + (q2*invscale));
579 }
580 else // linear interploation
581 return lerp(q1,q2,time);
582}
583
584
585// calculates the dot product
586inline f32 quaternion::dotProduct(const quaternion& q2) const
587{
588 return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W);
589}
590
591
594{
595 const f32 fHalfAngle = 0.5f*angle;
596 const f32 fSin = sinf(fHalfAngle);
597 W = cosf(fHalfAngle);
598 X = fSin*axis.X;
599 Y = fSin*axis.Y;
600 Z = fSin*axis.Z;
601 return *this;
602}
603
604
605inline void quaternion::toAngleAxis(f32 &angle, core::vector3df &axis) const
606{
607 const f32 scale = sqrtf(X*X + Y*Y + Z*Z);
608
609 if (core::iszero(scale) || W > 1.0f || W < -1.0f)
610 {
611 angle = 0.0f;
612 axis.X = 0.0f;
613 axis.Y = 1.0f;
614 axis.Z = 0.0f;
615 }
616 else
617 {
618 const f32 invscale = reciprocal(scale);
619 angle = 2.0f * acosf(W);
620 axis.X = X * invscale;
621 axis.Y = Y * invscale;
622 axis.Z = Z * invscale;
623 }
624}
625
626inline void quaternion::toEuler(vector3df& euler) const
627{
628 const f64 sqw = W*W;
629 const f64 sqx = X*X;
630 const f64 sqy = Y*Y;
631 const f64 sqz = Z*Z;
632 const f64 test = 2.0 * (Y*W - X*Z);
633
634 if (core::equals(test, 1.0, 0.000001))
635 {
636 // heading = rotation about z-axis
637 euler.Z = (f32) (-2.0*atan2(X, W));
638 // bank = rotation about x-axis
639 euler.X = 0;
640 // attitude = rotation about y-axis
641 euler.Y = (f32) (core::PI64/2.0);
642 }
643 else if (core::equals(test, -1.0, 0.000001))
644 {
645 // heading = rotation about z-axis
646 euler.Z = (f32) (2.0*atan2(X, W));
647 // bank = rotation about x-axis
648 euler.X = 0;
649 // attitude = rotation about y-axis
650 euler.Y = (f32) (core::PI64/-2.0);
651 }
652 else
653 {
654 // heading = rotation about z-axis
655 euler.Z = (f32) atan2(2.0 * (X*Y +Z*W),(sqx - sqy - sqz + sqw));
656 // bank = rotation about x-axis
657 euler.X = (f32) atan2(2.0 * (Y*Z +X*W),(-sqx - sqy + sqz + sqw));
658 // attitude = rotation about y-axis
659 euler.Y = (f32) asin( clamp(test, -1.0, 1.0) );
660 }
661}
662
663
665{
666 // nVidia SDK implementation
667
668 vector3df uv, uuv;
669 vector3df qvec(X, Y, Z);
670 uv = qvec.crossProduct(v);
671 uuv = qvec.crossProduct(uv);
672
673 //uv *= (2.0f * W);
674 f32 mul = 2.0f*W;
675 uv.X *= mul;
676 uv.Y *= mul;
677 uv.Z *= mul;
678
679 //uuv *= 2.0f;
680 uuv.X *= 2.0f;
681 uuv.Y *= 2.0f;
682 uuv.Z *= 2.0f;
683
684 return v + uv + uuv;
685}
686
687// set quaternion to identity
689{
690 W = 1.f;
691 X = 0.f;
692 Y = 0.f;
693 Z = 0.f;
694 return *this;
695}
696
698{
699 // Based on Stan Melax's article in Game Programming Gems
700 // Copy, since cannot modify local
701 vector3df v0 = from;
702 vector3df v1 = to;
703 v0.normalize();
704 v1.normalize();
705
706 const f32 d = v0.dotProduct(v1);
707 if (d >= 1.0f) // If dot == 1, vectors are the same
708 {
709 return makeIdentity();
710 }
711 else if (d <= -1.0f) // exactly opposite
712 {
713 core::vector3df axis(1.0f, 0.f, 0.f);
714 axis = axis.crossProduct(v0);
715 if (axis.getLength()==0)
716 {
717 axis.set(0.f,1.f,0.f);
718 axis.crossProduct(v0);
719 }
720 // same as fromAngleAxis(core::PI, axis).normalize();
721 return set(axis.X, axis.Y, axis.Z, 0).normalize();
722 }
723
724 const f32 s = sqrtf( (1+d)*2 ); // optimize inv_sqrt
725 const f32 invs = 1.f / s;
726 const vector3df c = v0.crossProduct(v1)*invs;
727 return set(c.X, c.Y, c.Z, s * 0.5f).normalize();
728}
729
730
731} // end namespace core
732} // end namespace irr
733
734#endif
735
const T * pointer() const
Returns pointer to internal array.
Definition matrix4.h:99
void setRotationCenter(const core::vector3df &center, const core::vector3df &translate)
Builds a combined matrix which translates to a center before rotation and translates from origin afte...
Definition matrix4.h:2049
void setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix)
Sets if the matrix is definitely identity matrix.
Definition matrix4.h:2196
Quaternion class for representing rotations.
Definition quaternion.h:27
quaternion & operator=(const quaternion &other)
Assignment operator.
Definition quaternion.h:224
f32 dotProduct(const quaternion &other) const
Calculates the dot product.
Definition quaternion.h:586
matrix4 getMatrix() const
Creates a matrix from this quaternion.
Definition quaternion.h:339
quaternion & makeInverse()
Inverts this quaternion.
Definition quaternion.h:468
quaternion & makeIdentity()
Set quaternion to identity.
Definition quaternion.h:688
bool equals(const quaternion &other, const f32 tolerance=ROUNDING_ERROR_f32) const
returns if this quaternion equals the other one, taking floating point rounding errors into account
Definition quaternion.h:530
quaternion & set(f32 x, f32 y, f32 z, f32 w)
Sets new quaternion.
Definition quaternion.h:476
bool operator!=(const quaternion &other) const
inequality operator
Definition quaternion.h:218
void toEuler(vector3df &euler) const
Output this quaternion to an euler angle (radians).
Definition quaternion.h:626
f32 X
Quaternion elements.
Definition quaternion.h:180
bool operator==(const quaternion &other) const
Equalilty operator.
Definition quaternion.h:209
quaternion & lerp(quaternion q1, quaternion q2, f32 time)
Set this quaternion to the linear interpolation between two quaternions.
Definition quaternion.h:553
quaternion(f32 x, f32 y, f32 z, f32 w)
Constructor.
Definition quaternion.h:34
quaternion operator+(const quaternion &other) const
Add operator.
Definition quaternion.h:332
void toAngleAxis(f32 &angle, core::vector3df &axis) const
Fills an angle (radians) around an axis (unit vector).
Definition quaternion.h:605
quaternion & slerp(quaternion q1, quaternion q2, f32 time, f32 threshold=.05f)
Set this quaternion to the result of the spherical interpolation between two quaternions.
Definition quaternion.h:561
quaternion & operator*=(f32 s)
Multiplication operator with scalar.
Definition quaternion.h:316
quaternion & rotationFromTo(const vector3df &from, const vector3df &to)
Set quaternion to represent a rotation from one vector to another.
Definition quaternion.h:697
quaternion & normalize()
Normalizes the quaternion.
Definition quaternion.h:540
void getMatrixCenter(matrix4 &dest, const core::vector3df &center, const core::vector3df &translation) const
Definition quaternion.h:418
quaternion & fromAngleAxis(f32 angle, const vector3df &axis)
Create quaternion from rotation angle and rotation axis.
Definition quaternion.h:593
void getMatrix_transposed(matrix4 &dest) const
Creates a matrix from this quaternion.
Definition quaternion.h:441
quaternion operator*(const quaternion &other) const
Multiplication operator.
Definition quaternion.h:295
quaternion()
Default Constructor.
Definition quaternion.h:31
vector3d< T > crossProduct(const vector3d< T > &p) const
Calculates the cross product with another vector.
Definition vector3d.h:147
T getLength() const
Get length of the vector.
Definition vector3d.h:117
T X
X coordinate of the vector.
Definition vector3d.h:408
vector3d< T > & normalize()
Normalizes the vector.
Definition vector3d.h:168
T Z
Z coordinate of the vector.
Definition vector3d.h:414
T dotProduct(const vector3d< T > &other) const
Get the dot product with another vector.
Definition vector3d.h:125
T Y
Y coordinate of the vector.
Definition vector3d.h:411
Basic classes such as vectors, planes, arrays, lists, and so on can be found in this namespace.
Definition aabbox3d.h:15
vector3d< f32 > vector3df
Typedef for a f32 3d vector.
Definition vector3d.h:445
const f64 PI64
Constant for 64bit PI.
Definition irrMath.h:68
const T clamp(const T &value, const T &low, const T &high)
clamps a value between low and high
Definition irrMath.h:166
CMatrix4< f32 > matrix4
Typedef for f32 matrix.
Definition matrix4.h:2241
bool equals(const f64 a, const f64 b, const f64 tolerance=ROUNDING_ERROR_f64)
returns if a equals b, taking possible rounding errors into account
Definition irrMath.h:185
bool iszero(const f64 a, const f64 tolerance=ROUNDING_ERROR_f64)
returns if a equals zero, taking rounding errors into account
Definition irrMath.h:270
Everything in the Irrlicht Engine can be found in this namespace.
Definition Skylicht.h:33
float f32
32 bit floating point variable.
Definition irrTypes.h:104
double f64
64 bit floating point variable.
Definition irrTypes.h:108