quaternion.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  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. #ifndef IRR_QUATERNION_H_INCLUDED
  5. #define IRR_QUATERNION_H_INCLUDED
  6. #include "irrTypes.h"
  7. #include "irrMath.h"
  8. #include "matrix4.h"
  9. #include "vector3d.h"
  10. // NOTE: You *only* need this when updating an application from Irrlicht before 1.8 to Irrlicht 1.8 or later.
  11. // Between Irrlicht 1.7 and Irrlicht 1.8 the quaternion-matrix conversions changed.
  12. // Before the fix they had mixed left- and right-handed rotations.
  13. // To test if your code was affected by the change enable IRR_TEST_BROKEN_QUATERNION_USE and try to compile your application.
  14. // This defines removes those functions so you get compile errors anywhere you use them in your code.
  15. // For every line with a compile-errors you have to change the corresponding lines like that:
  16. // - When you pass the matrix to the quaternion constructor then replace the matrix by the transposed matrix.
  17. // - For uses of getMatrix() you have to use quaternion::getMatrix_transposed instead.
  18. // #define IRR_TEST_BROKEN_QUATERNION_USE
  19. namespace irr
  20. {
  21. namespace core
  22. {
  23. //! Quaternion class for representing rotations.
  24. /** It provides cheap combinations and avoids gimbal locks.
  25. Also useful for interpolations. */
  26. class quaternion
  27. {
  28. public:
  29. //! Default Constructor
  30. quaternion() : X(0.0f), Y(0.0f), Z(0.0f), W(1.0f) {}
  31. //! Constructor
  32. quaternion(f32 x, f32 y, f32 z, f32 w) : X(x), Y(y), Z(z), W(w) { }
  33. //! Constructor which converts Euler angles (radians) to a quaternion
  34. quaternion(f32 x, f32 y, f32 z);
  35. //! Constructor which converts Euler angles (radians) to a quaternion
  36. quaternion(const vector3df& vec);
  37. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  38. //! Constructor which converts a matrix to a quaternion
  39. quaternion(const matrix4& mat);
  40. #endif
  41. //! Equality operator
  42. bool operator==(const quaternion& other) const;
  43. //! inequality operator
  44. bool operator!=(const quaternion& other) const;
  45. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  46. //! Matrix assignment operator
  47. inline quaternion& operator=(const matrix4& other);
  48. #endif
  49. //! Add operator
  50. quaternion operator+(const quaternion& other) const;
  51. //! Multiplication operator
  52. //! Be careful, unfortunately the operator order here is opposite of that in CMatrix4::operator*
  53. quaternion operator*(const quaternion& other) const;
  54. //! Multiplication operator with scalar
  55. quaternion operator*(f32 s) const;
  56. //! Multiplication operator with scalar
  57. quaternion& operator*=(f32 s);
  58. //! Multiplication operator
  59. vector3df operator*(const vector3df& v) const;
  60. //! Multiplication operator
  61. quaternion& operator*=(const quaternion& other);
  62. //! Calculates the dot product
  63. inline f32 dotProduct(const quaternion& other) const;
  64. //! Sets new quaternion
  65. inline quaternion& set(f32 x, f32 y, f32 z, f32 w);
  66. //! Sets new quaternion based on Euler angles (radians)
  67. inline quaternion& set(f32 x, f32 y, f32 z);
  68. //! Sets new quaternion based on Euler angles (radians)
  69. inline quaternion& set(const core::vector3df& vec);
  70. //! Sets new quaternion from other quaternion
  71. inline quaternion& set(const core::quaternion& quat);
  72. //! returns if this quaternion equals the other one, taking floating point rounding errors into account
  73. inline bool equals(const quaternion& other,
  74. const f32 tolerance = ROUNDING_ERROR_f32 ) const;
  75. //! Normalizes the quaternion
  76. inline quaternion& normalize();
  77. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  78. //! Creates a matrix from this quaternion
  79. matrix4 getMatrix() const;
  80. #endif
  81. //! Faster method to create a rotation matrix, you should normalize the quaternion before!
  82. void getMatrixFast(matrix4 &dest) const;
  83. //! Creates a matrix from this quaternion
  84. void getMatrix( matrix4 &dest, const core::vector3df &translation=core::vector3df() ) const;
  85. /*!
  86. Creates a matrix from this quaternion
  87. Rotate about a center point
  88. shortcut for
  89. core::quaternion q;
  90. q.rotationFromTo ( vin[i].Normal, forward );
  91. q.getMatrixCenter ( lookat, center, newPos );
  92. core::matrix4 m2;
  93. m2.setInverseTranslation ( center );
  94. lookat *= m2;
  95. core::matrix4 m3;
  96. m2.setTranslation ( newPos );
  97. lookat *= m3;
  98. */
  99. void getMatrixCenter( matrix4 &dest, const core::vector3df &center, const core::vector3df &translation ) const;
  100. //! Creates a matrix from this quaternion
  101. inline void getMatrix_transposed( matrix4 &dest ) const;
  102. //! Inverts this quaternion
  103. quaternion& makeInverse();
  104. //! Set this quaternion to the linear interpolation between two quaternions
  105. /** NOTE: lerp result is *not* a normalized quaternion. In most cases
  106. you will want to use lerpN instead as most other quaternion functions expect
  107. to work with a normalized quaternion.
  108. \param q1 First quaternion to be interpolated.
  109. \param q2 Second quaternion to be interpolated.
  110. \param time Progress of interpolation. For time=0 the result is
  111. q1, for time=1 the result is q2. Otherwise interpolation
  112. between q1 and q2. Result is not normalized.
  113. */
  114. quaternion& lerp(quaternion q1, quaternion q2, f32 time);
  115. //! Set this quaternion to the linear interpolation between two quaternions and normalize the result
  116. /**
  117. \param q1 First quaternion to be interpolated.
  118. \param q2 Second quaternion to be interpolated.
  119. \param time Progress of interpolation. For time=0 the result is
  120. q1, for time=1 the result is q2. Otherwise interpolation
  121. between q1 and q2. Result is normalized.
  122. */
  123. quaternion& lerpN(quaternion q1, quaternion q2, f32 time);
  124. //! Set this quaternion to the result of the spherical interpolation between two quaternions
  125. /** \param q1 First quaternion to be interpolated.
  126. \param q2 Second quaternion to be interpolated.
  127. \param time Progress of interpolation. For time=0 the result is
  128. q1, for time=1 the result is q2. Otherwise interpolation
  129. between q1 and q2.
  130. \param threshold To avoid inaccuracies at the end (time=1) the
  131. interpolation switches to linear interpolation at some point.
  132. This value defines how much of the remaining interpolation will
  133. be calculated with lerp. Everything from 1-threshold up will be
  134. linear interpolation.
  135. */
  136. quaternion& slerp(quaternion q1, quaternion q2,
  137. f32 time, f32 threshold=.05f);
  138. //! Set this quaternion to represent a rotation from angle and axis.
  139. /** Axis must be unit length.
  140. The quaternion representing the rotation is
  141. q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k).
  142. \param angle Rotation Angle in radians.
  143. \param axis Rotation axis. */
  144. quaternion& fromAngleAxis (f32 angle, const vector3df& axis);
  145. //! Fills an angle (radians) around an axis (unit vector)
  146. void toAngleAxis (f32 &angle, core::vector3df& axis) const;
  147. //! Output this quaternion to an Euler angle (radians)
  148. void toEuler(vector3df& euler) const;
  149. //! Set quaternion to identity
  150. quaternion& makeIdentity();
  151. //! Set quaternion to represent a rotation from one vector to another.
  152. quaternion& rotationFromTo(const vector3df& from, const vector3df& to);
  153. //! Quaternion elements.
  154. f32 X; // vectorial (imaginary) part
  155. f32 Y;
  156. f32 Z;
  157. f32 W; // real part
  158. };
  159. // Constructor which converts Euler angles to a quaternion
  160. inline quaternion::quaternion(f32 x, f32 y, f32 z)
  161. {
  162. set(x,y,z);
  163. }
  164. // Constructor which converts Euler angles to a quaternion
  165. inline quaternion::quaternion(const vector3df& vec)
  166. {
  167. set(vec.X,vec.Y,vec.Z);
  168. }
  169. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  170. // Constructor which converts a matrix to a quaternion
  171. inline quaternion::quaternion(const matrix4& mat)
  172. {
  173. (*this) = mat;
  174. }
  175. #endif
  176. // equal operator
  177. inline bool quaternion::operator==(const quaternion& other) const
  178. {
  179. return ((X == other.X) &&
  180. (Y == other.Y) &&
  181. (Z == other.Z) &&
  182. (W == other.W));
  183. }
  184. // inequality operator
  185. inline bool quaternion::operator!=(const quaternion& other) const
  186. {
  187. return !(*this == other);
  188. }
  189. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  190. // matrix assignment operator
  191. inline quaternion& quaternion::operator=(const matrix4& m)
  192. {
  193. const f32 diag = m[0] + m[5] + m[10] + 1;
  194. if( diag > 0.0f )
  195. {
  196. const f32 scale = sqrtf(diag) * 2.0f; // get scale from diagonal
  197. // TODO: speed this up
  198. X = (m[6] - m[9]) / scale;
  199. Y = (m[8] - m[2]) / scale;
  200. Z = (m[1] - m[4]) / scale;
  201. W = 0.25f * scale;
  202. }
  203. else
  204. {
  205. if (m[0]>m[5] && m[0]>m[10])
  206. {
  207. // 1st element of diag is greatest value
  208. // find scale according to 1st element, and double it
  209. const f32 scale = sqrtf(1.0f + m[0] - m[5] - m[10]) * 2.0f;
  210. // TODO: speed this up
  211. X = 0.25f * scale;
  212. Y = (m[4] + m[1]) / scale;
  213. Z = (m[2] + m[8]) / scale;
  214. W = (m[6] - m[9]) / scale;
  215. }
  216. else if (m[5]>m[10])
  217. {
  218. // 2nd element of diag is greatest value
  219. // find scale according to 2nd element, and double it
  220. const f32 scale = sqrtf(1.0f + m[5] - m[0] - m[10]) * 2.0f;
  221. // TODO: speed this up
  222. X = (m[4] + m[1]) / scale;
  223. Y = 0.25f * scale;
  224. Z = (m[9] + m[6]) / scale;
  225. W = (m[8] - m[2]) / scale;
  226. }
  227. else
  228. {
  229. // 3rd element of diag is greatest value
  230. // find scale according to 3rd element, and double it
  231. const f32 scale = sqrtf(1.0f + m[10] - m[0] - m[5]) * 2.0f;
  232. // TODO: speed this up
  233. X = (m[8] + m[2]) / scale;
  234. Y = (m[9] + m[6]) / scale;
  235. Z = 0.25f * scale;
  236. W = (m[1] - m[4]) / scale;
  237. }
  238. }
  239. return normalize();
  240. }
  241. #endif
  242. // multiplication operator
  243. inline quaternion quaternion::operator*(const quaternion& other) const
  244. {
  245. quaternion tmp;
  246. tmp.W = (other.W * W) - (other.X * X) - (other.Y * Y) - (other.Z * Z);
  247. tmp.X = (other.W * X) + (other.X * W) + (other.Y * Z) - (other.Z * Y);
  248. tmp.Y = (other.W * Y) + (other.Y * W) + (other.Z * X) - (other.X * Z);
  249. tmp.Z = (other.W * Z) + (other.Z * W) + (other.X * Y) - (other.Y * X);
  250. return tmp;
  251. }
  252. // multiplication operator
  253. inline quaternion quaternion::operator*(f32 s) const
  254. {
  255. return quaternion(s*X, s*Y, s*Z, s*W);
  256. }
  257. // multiplication operator
  258. inline quaternion& quaternion::operator*=(f32 s)
  259. {
  260. X*=s;
  261. Y*=s;
  262. Z*=s;
  263. W*=s;
  264. return *this;
  265. }
  266. // multiplication operator
  267. inline quaternion& quaternion::operator*=(const quaternion& other)
  268. {
  269. return (*this = other * (*this));
  270. }
  271. // add operator
  272. inline quaternion quaternion::operator+(const quaternion& b) const
  273. {
  274. return quaternion(X+b.X, Y+b.Y, Z+b.Z, W+b.W);
  275. }
  276. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  277. // Creates a matrix from this quaternion
  278. inline matrix4 quaternion::getMatrix() const
  279. {
  280. core::matrix4 m;
  281. getMatrix(m);
  282. return m;
  283. }
  284. #endif
  285. //! Faster method to create a rotation matrix, you should normalize the quaternion before!
  286. inline void quaternion::getMatrixFast( matrix4 &dest) const
  287. {
  288. // TODO:
  289. // gpu quaternion skinning => fast Bones transform chain O_O YEAH!
  290. // http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf
  291. dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
  292. dest[1] = 2.0f*X*Y + 2.0f*Z*W;
  293. dest[2] = 2.0f*X*Z - 2.0f*Y*W;
  294. dest[3] = 0.0f;
  295. dest[4] = 2.0f*X*Y - 2.0f*Z*W;
  296. dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
  297. dest[6] = 2.0f*Z*Y + 2.0f*X*W;
  298. dest[7] = 0.0f;
  299. dest[8] = 2.0f*X*Z + 2.0f*Y*W;
  300. dest[9] = 2.0f*Z*Y - 2.0f*X*W;
  301. dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
  302. dest[11] = 0.0f;
  303. dest[12] = 0.f;
  304. dest[13] = 0.f;
  305. dest[14] = 0.f;
  306. dest[15] = 1.f;
  307. dest.setDefinitelyIdentityMatrix(false);
  308. }
  309. /*!
  310. Creates a matrix from this quaternion
  311. */
  312. inline void quaternion::getMatrix(matrix4 &dest,
  313. const core::vector3df &center) const
  314. {
  315. // ok creating a copy may be slower, but at least avoid internal
  316. // state chance (also because otherwise we cannot keep this method "const").
  317. quaternion q( *this);
  318. q.normalize();
  319. f32 X = q.X;
  320. f32 Y = q.Y;
  321. f32 Z = q.Z;
  322. f32 W = q.W;
  323. dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
  324. dest[1] = 2.0f*X*Y + 2.0f*Z*W;
  325. dest[2] = 2.0f*X*Z - 2.0f*Y*W;
  326. dest[3] = 0.0f;
  327. dest[4] = 2.0f*X*Y - 2.0f*Z*W;
  328. dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
  329. dest[6] = 2.0f*Z*Y + 2.0f*X*W;
  330. dest[7] = 0.0f;
  331. dest[8] = 2.0f*X*Z + 2.0f*Y*W;
  332. dest[9] = 2.0f*Z*Y - 2.0f*X*W;
  333. dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
  334. dest[11] = 0.0f;
  335. dest[12] = center.X;
  336. dest[13] = center.Y;
  337. dest[14] = center.Z;
  338. dest[15] = 1.f;
  339. dest.setDefinitelyIdentityMatrix ( false );
  340. }
  341. /*!
  342. Creates a matrix from this quaternion
  343. Rotate about a center point
  344. shortcut for
  345. core::quaternion q;
  346. q.rotationFromTo(vin[i].Normal, forward);
  347. q.getMatrix(lookat, center);
  348. core::matrix4 m2;
  349. m2.setInverseTranslation(center);
  350. lookat *= m2;
  351. */
  352. inline void quaternion::getMatrixCenter(matrix4 &dest,
  353. const core::vector3df &center,
  354. const core::vector3df &translation) const
  355. {
  356. quaternion q(*this);
  357. q.normalize();
  358. f32 X = q.X;
  359. f32 Y = q.Y;
  360. f32 Z = q.Z;
  361. f32 W = q.W;
  362. dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
  363. dest[1] = 2.0f*X*Y + 2.0f*Z*W;
  364. dest[2] = 2.0f*X*Z - 2.0f*Y*W;
  365. dest[3] = 0.0f;
  366. dest[4] = 2.0f*X*Y - 2.0f*Z*W;
  367. dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
  368. dest[6] = 2.0f*Z*Y + 2.0f*X*W;
  369. dest[7] = 0.0f;
  370. dest[8] = 2.0f*X*Z + 2.0f*Y*W;
  371. dest[9] = 2.0f*Z*Y - 2.0f*X*W;
  372. dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
  373. dest[11] = 0.0f;
  374. dest.setRotationCenter ( center, translation );
  375. }
  376. // Creates a matrix from this quaternion
  377. inline void quaternion::getMatrix_transposed(matrix4 &dest) const
  378. {
  379. quaternion q(*this);
  380. q.normalize();
  381. f32 X = q.X;
  382. f32 Y = q.Y;
  383. f32 Z = q.Z;
  384. f32 W = q.W;
  385. dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
  386. dest[4] = 2.0f*X*Y + 2.0f*Z*W;
  387. dest[8] = 2.0f*X*Z - 2.0f*Y*W;
  388. dest[12] = 0.0f;
  389. dest[1] = 2.0f*X*Y - 2.0f*Z*W;
  390. dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
  391. dest[9] = 2.0f*Z*Y + 2.0f*X*W;
  392. dest[13] = 0.0f;
  393. dest[2] = 2.0f*X*Z + 2.0f*Y*W;
  394. dest[6] = 2.0f*Z*Y - 2.0f*X*W;
  395. dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
  396. dest[14] = 0.0f;
  397. dest[3] = 0.f;
  398. dest[7] = 0.f;
  399. dest[11] = 0.f;
  400. dest[15] = 1.f;
  401. dest.setDefinitelyIdentityMatrix(false);
  402. }
  403. // Inverts this quaternion
  404. inline quaternion& quaternion::makeInverse()
  405. {
  406. X = -X; Y = -Y; Z = -Z;
  407. return *this;
  408. }
  409. // sets new quaternion
  410. inline quaternion& quaternion::set(f32 x, f32 y, f32 z, f32 w)
  411. {
  412. X = x;
  413. Y = y;
  414. Z = z;
  415. W = w;
  416. return *this;
  417. }
  418. // sets new quaternion based on Euler angles
  419. inline quaternion& quaternion::set(f32 x, f32 y, f32 z)
  420. {
  421. f64 angle;
  422. angle = x * 0.5;
  423. const f64 sr = sin(angle);
  424. const f64 cr = cos(angle);
  425. angle = y * 0.5;
  426. const f64 sp = sin(angle);
  427. const f64 cp = cos(angle);
  428. angle = z * 0.5;
  429. const f64 sy = sin(angle);
  430. const f64 cy = cos(angle);
  431. const f64 cpcy = cp * cy;
  432. const f64 spcy = sp * cy;
  433. const f64 cpsy = cp * sy;
  434. const f64 spsy = sp * sy;
  435. X = (f32)(sr * cpcy - cr * spsy);
  436. Y = (f32)(cr * spcy + sr * cpsy);
  437. Z = (f32)(cr * cpsy - sr * spcy);
  438. W = (f32)(cr * cpcy + sr * spsy);
  439. return normalize();
  440. }
  441. // sets new quaternion based on Euler angles
  442. inline quaternion& quaternion::set(const core::vector3df& vec)
  443. {
  444. return set( vec.X, vec.Y, vec.Z);
  445. }
  446. // sets new quaternion based on other quaternion
  447. inline quaternion& quaternion::set(const core::quaternion& quat)
  448. {
  449. return (*this=quat);
  450. }
  451. //! returns if this quaternion equals the other one, taking floating point rounding errors into account
  452. inline bool quaternion::equals(const quaternion& other, const f32 tolerance) const
  453. {
  454. return core::equals( X, other.X, tolerance) &&
  455. core::equals( Y, other.Y, tolerance) &&
  456. core::equals( Z, other.Z, tolerance) &&
  457. core::equals( W, other.W, tolerance);
  458. }
  459. // normalizes the quaternion
  460. inline quaternion& quaternion::normalize()
  461. {
  462. // removed conditional branch since it may slow down and anyway the condition was
  463. // false even after normalization in some cases.
  464. return (*this *= (f32)reciprocal_squareroot ( (f64)(X*X + Y*Y + Z*Z + W*W) ));
  465. }
  466. // Set this quaternion to the result of the linear interpolation between two quaternions
  467. inline quaternion& quaternion::lerp( quaternion q1, quaternion q2, f32 time)
  468. {
  469. const f32 scale = 1.0f - time;
  470. return (*this = (q1*scale) + (q2*time));
  471. }
  472. // Set this quaternion to the result of the linear interpolation between two quaternions and normalize the result
  473. inline quaternion& quaternion::lerpN( quaternion q1, quaternion q2, f32 time)
  474. {
  475. const f32 scale = 1.0f - time;
  476. return (*this = ((q1*scale) + (q2*time)).normalize() );
  477. }
  478. // set this quaternion to the result of the interpolation between two quaternions
  479. inline quaternion& quaternion::slerp( quaternion q1, quaternion q2, f32 time, f32 threshold)
  480. {
  481. f32 angle = q1.dotProduct(q2);
  482. // make sure we use the short rotation
  483. if (angle < 0.0f)
  484. {
  485. q1 *= -1.0f;
  486. angle *= -1.0f;
  487. }
  488. if (angle <= (1-threshold)) // spherical interpolation
  489. {
  490. const f32 theta = acosf(angle);
  491. const f32 invsintheta = reciprocal(sinf(theta));
  492. const f32 scale = sinf(theta * (1.0f-time)) * invsintheta;
  493. const f32 invscale = sinf(theta * time) * invsintheta;
  494. return (*this = (q1*scale) + (q2*invscale));
  495. }
  496. else // linear interpolation
  497. return lerpN(q1,q2,time);
  498. }
  499. // calculates the dot product
  500. inline f32 quaternion::dotProduct(const quaternion& q2) const
  501. {
  502. return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W);
  503. }
  504. //! axis must be unit length, angle in radians
  505. inline quaternion& quaternion::fromAngleAxis(f32 angle, const vector3df& axis)
  506. {
  507. const f32 fHalfAngle = 0.5f*angle;
  508. const f32 fSin = sinf(fHalfAngle);
  509. W = cosf(fHalfAngle);
  510. X = fSin*axis.X;
  511. Y = fSin*axis.Y;
  512. Z = fSin*axis.Z;
  513. return *this;
  514. }
  515. inline void quaternion::toAngleAxis(f32 &angle, core::vector3df &axis) const
  516. {
  517. const f32 scale = sqrtf(X*X + Y*Y + Z*Z);
  518. if (core::iszero(scale) || W > 1.0f || W < -1.0f)
  519. {
  520. angle = 0.0f;
  521. axis.X = 0.0f;
  522. axis.Y = 1.0f;
  523. axis.Z = 0.0f;
  524. }
  525. else
  526. {
  527. const f32 invscale = reciprocal(scale);
  528. angle = 2.0f * acosf(W);
  529. axis.X = X * invscale;
  530. axis.Y = Y * invscale;
  531. axis.Z = Z * invscale;
  532. }
  533. }
  534. inline void quaternion::toEuler(vector3df& euler) const
  535. {
  536. const f64 sqw = W*W;
  537. const f64 sqx = X*X;
  538. const f64 sqy = Y*Y;
  539. const f64 sqz = Z*Z;
  540. const f64 test = 2.0 * (Y*W - X*Z);
  541. if (core::equals(test, 1.0, 0.000001))
  542. {
  543. // heading = rotation about z-axis
  544. euler.Z = (f32) (-2.0*atan2(X, W));
  545. // bank = rotation about x-axis
  546. euler.X = 0;
  547. // attitude = rotation about y-axis
  548. euler.Y = (f32) (core::PI64/2.0);
  549. }
  550. else if (core::equals(test, -1.0, 0.000001))
  551. {
  552. // heading = rotation about z-axis
  553. euler.Z = (f32) (2.0*atan2(X, W));
  554. // bank = rotation about x-axis
  555. euler.X = 0;
  556. // attitude = rotation about y-axis
  557. euler.Y = (f32) (core::PI64/-2.0);
  558. }
  559. else
  560. {
  561. // heading = rotation about z-axis
  562. euler.Z = (f32) atan2(2.0 * (X*Y +Z*W),(sqx - sqy - sqz + sqw));
  563. // bank = rotation about x-axis
  564. euler.X = (f32) atan2(2.0 * (Y*Z +X*W),(-sqx - sqy + sqz + sqw));
  565. // attitude = rotation about y-axis
  566. euler.Y = (f32) asin( clamp(test, -1.0, 1.0) );
  567. }
  568. }
  569. inline vector3df quaternion::operator* (const vector3df& v) const
  570. {
  571. // nVidia SDK implementation
  572. vector3df uv, uuv;
  573. const vector3df qvec(X, Y, Z);
  574. uv = qvec.crossProduct(v);
  575. uuv = qvec.crossProduct(uv);
  576. uv *= (2.0f * W);
  577. uuv *= 2.0f;
  578. return v + uv + uuv;
  579. }
  580. // set quaternion to identity
  581. inline core::quaternion& quaternion::makeIdentity()
  582. {
  583. W = 1.f;
  584. X = 0.f;
  585. Y = 0.f;
  586. Z = 0.f;
  587. return *this;
  588. }
  589. inline core::quaternion& quaternion::rotationFromTo(const vector3df& from, const vector3df& to)
  590. {
  591. // Based on Stan Melax's article in Game Programming Gems
  592. // Optimized by Robert Eisele: https://raw.org/proof/quaternion-from-two-vectors
  593. // Copy, since cannot modify local
  594. vector3df v0 = from;
  595. vector3df v1 = to;
  596. v0.normalize();
  597. v1.normalize();
  598. const f32 d = v0.dotProduct(v1);
  599. if (d >= 1.0f) // If dot == 1, vectors are the same
  600. {
  601. return makeIdentity();
  602. }
  603. else if (d <= -1.0f) // exactly opposite
  604. {
  605. core::vector3df axis(1.0f, 0.f, 0.f);
  606. axis = axis.crossProduct(v0);
  607. if (axis.getLength()==0)
  608. {
  609. axis.set(0.f,1.f,0.f);
  610. axis = axis.crossProduct(v0);
  611. }
  612. // same as fromAngleAxis(core::PI, axis).normalize();
  613. return set(axis.X, axis.Y, axis.Z, 0).normalize();
  614. }
  615. const vector3df c = v0.crossProduct(v1);
  616. return set(c.X, c.Y, c.Z, 1 + d).normalize();
  617. }
  618. } // end namespace core
  619. } // end namespace irr
  620. #endif