Quaternion.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Quaternion.h"
  25. const Quaternion Quaternion::sIdentity(1.0f, 0.0f, 0.0f, 0.0f);
  26. Quaternion::Quaternion(float angle, const Vector3& Axis)
  27. {
  28. fromAngleAxis(angle, Axis);
  29. }
  30. Quaternion::Quaternion(const Vector3& euler)
  31. {
  32. fromEulerAngles(euler);
  33. }
  34. Quaternion::Quaternion(float angleX, float angleY, float angleZ)
  35. {
  36. fromEulerAngles(Vector3(angleX, angleY, angleZ));
  37. }
  38. Quaternion::Quaternion(const Vector3& start, const Vector3& end)
  39. {
  40. fromRotationTo(start, end);
  41. }
  42. Quaternion::Quaternion(const Matrix3& matrix)
  43. {
  44. fromRotationMatrix(matrix);
  45. }
  46. void Quaternion::fromAngleAxis(float angle, const Vector3& axis)
  47. {
  48. Vector3 normAxis = axis.getNormalized();
  49. float sinAngle = sinf((angle * M_DEGTORAD) * 0.5f);
  50. float cosAngle = cosf((angle * M_DEGTORAD) * 0.5f);
  51. mW = cosAngle;
  52. mX = normAxis.mX * sinAngle;
  53. mY = normAxis.mY * sinAngle;
  54. mZ = normAxis.mZ * sinAngle;
  55. }
  56. void Quaternion::fromEulerAngles(const Vector3& euler)
  57. {
  58. // Order of rotations: Z first, then X, then Y (mimics typical FPS camera with gimbal lock at top/bottom)
  59. float sinX = sinf((euler.mX * M_DEGTORAD) * 0.5f);
  60. float cosX = cosf((euler.mX * M_DEGTORAD) * 0.5f);
  61. float sinY = sinf((euler.mY * M_DEGTORAD) * 0.5f);
  62. float cosY = cosf((euler.mY * M_DEGTORAD) * 0.5f);
  63. float sinZ = sinf((euler.mZ * M_DEGTORAD) * 0.5f);
  64. float cosZ = cosf((euler.mZ * M_DEGTORAD) * 0.5f);
  65. mW = cosY * cosX * cosZ + sinY * sinX * sinZ;
  66. mX = cosY * sinX * cosZ + sinY * cosX * sinZ;
  67. mY = sinY * cosX * cosZ - cosY * sinX * sinZ;
  68. mZ = cosY * cosX * sinZ - sinY * sinX * cosZ;
  69. }
  70. void Quaternion::fromRotationTo(const Vector3& start, const Vector3& end)
  71. {
  72. Vector3 normStart = start.getNormalized();
  73. Vector3 normEnd = end.getNormalized();
  74. float d = normStart.dotProduct(normEnd);
  75. if (d > -1.0f + M_EPSILON)
  76. {
  77. Vector3 c = normStart.crossProduct(normEnd);
  78. float s = sqrtf((1.0f + d) * 2.0f);
  79. float invS = 1.0f / s;
  80. mX = c.mX * invS;
  81. mY = c.mY * invS;
  82. mZ = c.mZ * invS;
  83. mW = 0.5f * s;
  84. }
  85. else
  86. {
  87. Vector3 tempAxis = Vector3::sRight.crossProduct(normStart);
  88. if (tempAxis.getLength() < M_EPSILON)
  89. tempAxis = Vector3::sUp.crossProduct(normStart);
  90. fromAngleAxis(180.0f, tempAxis);
  91. }
  92. }
  93. void Quaternion::fromRotationMatrix(const Matrix3& matrix)
  94. {
  95. float t = matrix.m00 + matrix.m11 + matrix.m22 + 1.0f;
  96. if (t > 0.0f)
  97. {
  98. float s = sqrtf(t) * 2.0f;
  99. float invS = 1.0f / s;
  100. mX = (matrix.m21 - matrix.m12) * invS;
  101. mY = (matrix.m02 - matrix.m20) * invS;
  102. mZ = (matrix.m10 - matrix.m01) * invS;
  103. mW = 0.25f * s;
  104. }
  105. else
  106. {
  107. if ((matrix.m00 > matrix.m11) && (matrix.m00 > matrix.m22))
  108. {
  109. float s = sqrtf(1.0f + matrix.m00 - matrix.m11 - matrix.m22) * 2.0f;
  110. float invS = 1.0f / s;
  111. mX = 0.25f * s;
  112. mY = (matrix.m01 + matrix.m10) * invS;
  113. mZ = (matrix.m20 + matrix.m02) * invS;
  114. mW = (matrix.m21 - matrix.m12) * invS;
  115. }
  116. else if (matrix.m11 > matrix.m22)
  117. {
  118. float s = sqrtf(1.0f + matrix.m11 - matrix.m00 - matrix.m22) * 2.0f;
  119. float invS = 1.0f / s;
  120. mX = (matrix.m01 + matrix.m10) * invS;
  121. mY = 0.25f * s;
  122. mZ = (matrix.m12 + matrix.m21) * invS;
  123. mW = (matrix.m02 - matrix.m20) * invS;
  124. }
  125. else
  126. {
  127. float s = sqrtf(1.0f + matrix.m22 - matrix.m00 - matrix.m11) * 2.0f;
  128. float invS = 1.0f / s;
  129. mX = (matrix.m02 + matrix.m20) * invS;
  130. mY = (matrix.m12 + matrix.m21) * invS;
  131. mZ = 0.25f * s;
  132. mW = (matrix.m10 - matrix.m01) * invS;
  133. }
  134. }
  135. }
  136. Vector3 Quaternion::getEulerAngles() const
  137. {
  138. // Derivation from http://www.geometrictools.com/Documentation/EulerAngles.pdf
  139. // Order of rotations: Z first, then X, then Y
  140. float check = 2.0f * (-mY * mZ + mW * mX);
  141. if (check < -0.995f)
  142. {
  143. return Vector3(
  144. -90.0f,
  145. 0.0f,
  146. -atan2f(2.0f * (mX * mZ - mW * mY), 1.0f - 2.0f * (mY * mY + mZ * mZ)) * M_RADTODEG
  147. );
  148. }
  149. else if (check > 0.995f)
  150. {
  151. return Vector3(
  152. 90.0f,
  153. 0.0f,
  154. atan2f(2.0f * (mX * mZ - mW * mY), 1.0f - 2.0f * (mY * mY + mZ * mZ)) * M_RADTODEG
  155. );
  156. }
  157. else
  158. {
  159. return Vector3(
  160. asinf(check) * M_RADTODEG,
  161. atan2f(2.0f * (mX * mZ + mW * mY), 1.0f - 2.0f * (mX * mX + mY * mY)) * M_RADTODEG,
  162. atan2f(2.0f * (mX * mY + mW * mZ), 1.0f - 2.0f * (mX * mX + mZ * mZ)) * M_RADTODEG
  163. );
  164. }
  165. }
  166. float Quaternion::getYaw() const
  167. {
  168. return getEulerAngles().mY;
  169. }
  170. float Quaternion::getPitch() const
  171. {
  172. return getEulerAngles().mX;
  173. }
  174. float Quaternion::getRoll() const
  175. {
  176. return getEulerAngles().mZ;
  177. }
  178. Matrix3 Quaternion::getRotationMatrix() const
  179. {
  180. return Matrix3(
  181. 1.0f - 2.0f * mY * mY - 2.0f * mZ * mZ,
  182. 2.0f * mX * mY - 2.0f * mW * mZ,
  183. 2.0f * mX * mZ + 2.0f * mW * mY,
  184. 2.0f * mX * mY + 2.0f * mW * mZ,
  185. 1.0f - 2.0f * mX * mX - 2.0f * mZ * mZ,
  186. 2.0f * mY * mZ - 2.0f * mW * mX,
  187. 2.0f * mX * mZ - 2.0f * mW * mY,
  188. 2.0f * mY * mZ + 2.0f * mW * mX,
  189. 1.0f - 2.0f * mX * mX - 2.0f * mY * mY
  190. );
  191. }
  192. Quaternion Quaternion::slerp(Quaternion rhs, float t) const
  193. {
  194. float cosAngle = dotProduct(rhs);
  195. // Enable shortest path rotation
  196. if (cosAngle < 0.0f)
  197. {
  198. cosAngle = -cosAngle;
  199. rhs = -rhs;
  200. }
  201. float angle = acosf(cosAngle);
  202. float sinAngle = sinf(angle);
  203. float t1, t2;
  204. if (sinAngle > 0.001f)
  205. {
  206. t1 = sinf((1.0f - t) * angle) / sinAngle;
  207. t2 = sinf(t * angle) / sinAngle;
  208. }
  209. else
  210. {
  211. t1 = 1.0f - t;
  212. t2 = t;
  213. }
  214. return *this * t1 + rhs * t2;
  215. }