BsQuaternion.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #include "BsQuaternion.h"
  5. #include "BsMath.h"
  6. #include "BsMatrix3.h"
  7. #include "BsVector3.h"
  8. namespace BansheeEngine
  9. {
  10. const float Quaternion::EPSILON = 1e-03f;
  11. const Quaternion Quaternion::ZERO(0.0f, 0.0f, 0.0f, 0.0f);
  12. const Quaternion Quaternion::IDENTITY(1.0f, 0.0f, 0.0f, 0.0f);
  13. const Quaternion::EulerAngleOrderData Quaternion::EA_LOOKUP[6] =
  14. { { 0, 1, 2}, { 0, 2, 1}, { 1, 0, 2},
  15. { 1, 2, 0}, { 2, 0, 1}, { 2, 1, 0} };;
  16. void Quaternion::fromRotationMatrix(const Matrix3& mat)
  17. {
  18. // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
  19. // article "Quaternion Calculus and Fast Animation".
  20. float trace = mat[0][0]+mat[1][1]+mat[2][2];
  21. float root;
  22. if (trace > 0.0f)
  23. {
  24. // |w| > 1/2, may as well choose w > 1/2
  25. root = Math::sqrt(trace + 1.0f); // 2w
  26. w = 0.5f*root;
  27. root = 0.5f/root; // 1/(4w)
  28. x = (mat[2][1]-mat[1][2])*root;
  29. y = (mat[0][2]-mat[2][0])*root;
  30. z = (mat[1][0]-mat[0][1])*root;
  31. }
  32. else
  33. {
  34. // |w| <= 1/2
  35. static UINT32 nextLookup[3] = { 1, 2, 0 };
  36. UINT32 i = 0;
  37. if (mat[1][1] > mat[0][0])
  38. i = 1;
  39. if (mat[2][2] > mat[i][i])
  40. i = 2;
  41. UINT32 j = nextLookup[i];
  42. UINT32 k = nextLookup[j];
  43. root = Math::sqrt(mat[i][i]-mat[j][j]-mat[k][k] + 1.0f);
  44. float* cmpntLookup[3] = { &x, &y, &z };
  45. *cmpntLookup[i] = 0.5f*root;
  46. root = 0.5f/root;
  47. w = (mat[k][j]-mat[j][k])*root;
  48. *cmpntLookup[j] = (mat[j][i]+mat[i][j])*root;
  49. *cmpntLookup[k] = (mat[k][i]+mat[i][k])*root;
  50. }
  51. normalize();
  52. }
  53. void Quaternion::fromAxisAngle(const Vector3& axis, const Radian& angle)
  54. {
  55. // Assert: axis[] is unit length
  56. Radian halfAngle (0.5f*angle);
  57. float sin = Math::sin(halfAngle);
  58. w = Math::cos(halfAngle);
  59. x = sin*axis.x;
  60. y = sin*axis.y;
  61. z = sin*axis.z;
  62. }
  63. void Quaternion::fromAxes(const Vector3& xaxis, const Vector3& yaxis, const Vector3& zaxis)
  64. {
  65. Matrix3 kRot;
  66. kRot[0][0] = xaxis.x;
  67. kRot[1][0] = xaxis.y;
  68. kRot[2][0] = xaxis.z;
  69. kRot[0][1] = yaxis.x;
  70. kRot[1][1] = yaxis.y;
  71. kRot[2][1] = yaxis.z;
  72. kRot[0][2] = zaxis.x;
  73. kRot[1][2] = zaxis.y;
  74. kRot[2][2] = zaxis.z;
  75. fromRotationMatrix(kRot);
  76. }
  77. void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle)
  78. {
  79. Quaternion quats[3];
  80. quats[0].fromAxisAngle(Vector3::UNIT_X, xAngle);
  81. quats[1].fromAxisAngle(Vector3::UNIT_Y, yAngle);
  82. quats[2].fromAxisAngle(Vector3::UNIT_Z, zAngle);
  83. *this = quats[2]*(quats[0] * quats[1]);
  84. }
  85. void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order)
  86. {
  87. const EulerAngleOrderData& l = EA_LOOKUP[(int)order];
  88. Quaternion quats[3];
  89. quats[0].fromAxisAngle(Vector3::UNIT_X, xAngle);
  90. quats[1].fromAxisAngle(Vector3::UNIT_Y, yAngle);
  91. quats[2].fromAxisAngle(Vector3::UNIT_Z, zAngle);
  92. *this = quats[l.c]*(quats[l.a] * quats[l.b]);
  93. }
  94. void Quaternion::toRotationMatrix(Matrix3& mat) const
  95. {
  96. float tx = x+x;
  97. float ty = y+y;
  98. float fTz = z+z;
  99. float twx = tx*w;
  100. float twy = ty*w;
  101. float twz = fTz*w;
  102. float txx = tx*x;
  103. float txy = ty*x;
  104. float txz = fTz*x;
  105. float tyy = ty*y;
  106. float tyz = fTz*y;
  107. float tzz = fTz*z;
  108. mat[0][0] = 1.0f-(tyy+tzz);
  109. mat[0][1] = txy-twz;
  110. mat[0][2] = txz+twy;
  111. mat[1][0] = txy+twz;
  112. mat[1][1] = 1.0f-(txx+tzz);
  113. mat[1][2] = tyz-twx;
  114. mat[2][0] = txz-twy;
  115. mat[2][1] = tyz+twx;
  116. mat[2][2] = 1.0f-(txx+tyy);
  117. }
  118. void Quaternion::toAxisAngle(Vector3& axis, Radian& angle) const
  119. {
  120. float sqrLength = x*x+y*y+z*z;
  121. if ( sqrLength > 0.0 )
  122. {
  123. angle = 2.0*Math::acos(w);
  124. float invLength = Math::invSqrt(sqrLength);
  125. axis.x = x*invLength;
  126. axis.y = y*invLength;
  127. axis.z = z*invLength;
  128. }
  129. else
  130. {
  131. // Angle is 0 (mod 2*pi), so any axis will do
  132. angle = Radian(0.0);
  133. axis.x = 1.0;
  134. axis.y = 0.0;
  135. axis.z = 0.0;
  136. }
  137. }
  138. void Quaternion::toAxes(Vector3& xaxis, Vector3& yaxis, Vector3& zaxis) const
  139. {
  140. Matrix3 matRot;
  141. toRotationMatrix(matRot);
  142. xaxis.x = matRot[0][0];
  143. xaxis.y = matRot[1][0];
  144. xaxis.z = matRot[2][0];
  145. yaxis.x = matRot[0][1];
  146. yaxis.y = matRot[1][1];
  147. yaxis.z = matRot[2][1];
  148. zaxis.x = matRot[0][2];
  149. zaxis.y = matRot[1][2];
  150. zaxis.z = matRot[2][2];
  151. }
  152. bool Quaternion::toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const
  153. {
  154. Matrix3 matRot;
  155. toRotationMatrix(matRot);
  156. return matRot.toEulerAngles(xAngle, yAngle, zAngle);
  157. }
  158. bool Quaternion::toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle, EulerAngleOrder order) const
  159. {
  160. Matrix3 matRot;
  161. toRotationMatrix(matRot);
  162. return matRot.toEulerAngles(xAngle, yAngle, zAngle, order);
  163. }
  164. Vector3 Quaternion::xAxis() const
  165. {
  166. float fTy = 2.0f*y;
  167. float fTz = 2.0f*z;
  168. float fTwy = fTy*w;
  169. float fTwz = fTz*w;
  170. float fTxy = fTy*x;
  171. float fTxz = fTz*x;
  172. float fTyy = fTy*y;
  173. float fTzz = fTz*z;
  174. return Vector3(1.0f-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);
  175. }
  176. Vector3 Quaternion::yAxis() const
  177. {
  178. float fTx = 2.0f*x;
  179. float fTy = 2.0f*y;
  180. float fTz = 2.0f*z;
  181. float fTwx = fTx*w;
  182. float fTwz = fTz*w;
  183. float fTxx = fTx*x;
  184. float fTxy = fTy*x;
  185. float fTyz = fTz*y;
  186. float fTzz = fTz*z;
  187. return Vector3(fTxy-fTwz, 1.0f-(fTxx+fTzz), fTyz+fTwx);
  188. }
  189. Vector3 Quaternion::zAxis() const
  190. {
  191. float fTx = 2.0f*x;
  192. float fTy = 2.0f*y;
  193. float fTz = 2.0f*z;
  194. float fTwx = fTx*w;
  195. float fTwy = fTy*w;
  196. float fTxx = fTx*x;
  197. float fTxz = fTz*x;
  198. float fTyy = fTy*y;
  199. float fTyz = fTz*y;
  200. return Vector3(fTxz+fTwy, fTyz-fTwx, 1.0f-(fTxx+fTyy));
  201. }
  202. Quaternion Quaternion::operator+ (const Quaternion& rhs) const
  203. {
  204. return Quaternion(w+rhs.w,x+rhs.x,y+rhs.y,z+rhs.z);
  205. }
  206. Quaternion Quaternion::operator- (const Quaternion& rhs) const
  207. {
  208. return Quaternion(w-rhs.w,x-rhs.x,y-rhs.y,z-rhs.z);
  209. }
  210. Quaternion Quaternion::operator* (const Quaternion& rhs) const
  211. {
  212. return Quaternion
  213. (
  214. w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z,
  215. w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y,
  216. w * rhs.y + y * rhs.w + z * rhs.x - x * rhs.z,
  217. w * rhs.z + z * rhs.w + x * rhs.y - y * rhs.x
  218. );
  219. }
  220. Quaternion Quaternion::operator* (float rhs) const
  221. {
  222. return Quaternion(rhs*w,rhs*x,rhs*y,rhs*z);
  223. }
  224. Quaternion Quaternion::operator- () const
  225. {
  226. return Quaternion(-w,-x,-y,-z);
  227. }
  228. float Quaternion::dot(const Quaternion& other) const
  229. {
  230. return w*other.w+x*other.x+y*other.y+z*other.z;
  231. }
  232. Quaternion Quaternion::inverse() const
  233. {
  234. float fNorm = w*w+x*x+y*y+z*z;
  235. if (fNorm > 0.0f)
  236. {
  237. float fInvNorm = 1.0f/fNorm;
  238. return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm);
  239. }
  240. else
  241. {
  242. // Return an invalid result to flag the error
  243. return ZERO;
  244. }
  245. }
  246. Vector3 Quaternion::rotate(const Vector3& v) const
  247. {
  248. Matrix3 rot;
  249. toRotationMatrix(rot);
  250. return rot.transform(v);
  251. }
  252. Quaternion Quaternion::slerp(float t, const Quaternion& p, const Quaternion& q, bool shortestPath)
  253. {
  254. float cos = p.dot(q);
  255. Quaternion quat;
  256. if (cos < 0.0f && shortestPath)
  257. {
  258. cos = -cos;
  259. quat = -q;
  260. }
  261. else
  262. {
  263. quat = q;
  264. }
  265. if (Math::abs(cos) < 1 - EPSILON)
  266. {
  267. // Standard case (slerp)
  268. float sin = Math::sqrt(1 - Math::sqr(cos));
  269. Radian angle = Math::atan2(sin, cos);
  270. float invSin = 1.0f / sin;
  271. float coeff0 = Math::sin((1.0f - t) * angle) * invSin;
  272. float coeff1 = Math::sin(t * angle) * invSin;
  273. return coeff0 * p + coeff1 * quat;
  274. }
  275. else
  276. {
  277. // There are two situations:
  278. // 1. "p" and "q" are very close (fCos ~= +1), so we can do a linear
  279. // interpolation safely.
  280. // 2. "p" and "q" are almost inverse of each other (fCos ~= -1), there
  281. // are an infinite number of possibilities interpolation. but we haven't
  282. // have method to fix this case, so just use linear interpolation here.
  283. Quaternion ret = (1.0f - t) * p + t * quat;
  284. // Taking the complement requires renormalization
  285. ret.normalize();
  286. return ret;
  287. }
  288. }
  289. float Quaternion::normalize()
  290. {
  291. float len = w*w+x*x+y*y+z*z;
  292. float factor = 1.0f / Math::sqrt(len);
  293. *this = *this * factor;
  294. return len;
  295. }
  296. Quaternion Quaternion::getRotationFromTo(const Vector3& from, const Vector3& dest, const Vector3& fallbackAxis)
  297. {
  298. // Based on Stan Melax's article in Game Programming Gems
  299. Quaternion q;
  300. Vector3 v0 = from;
  301. Vector3 v1 = dest;
  302. v0.normalize();
  303. v1.normalize();
  304. float d = v0.dot(v1);
  305. // If dot == 1, vectors are the same
  306. if (d >= 1.0f)
  307. return Quaternion::IDENTITY;
  308. if (d < (1e-6f - 1.0f))
  309. {
  310. if (fallbackAxis != Vector3::ZERO)
  311. {
  312. // Rotate 180 degrees about the fallback axis
  313. q.fromAxisAngle(fallbackAxis, Radian(Math::PI));
  314. }
  315. else
  316. {
  317. // Generate an axis
  318. Vector3 axis = Vector3::UNIT_X.cross(from);
  319. if (axis.isZeroLength()) // Pick another if colinear
  320. axis = Vector3::UNIT_Y.cross(from);
  321. axis.normalize();
  322. q.fromAxisAngle(axis, Radian(Math::PI));
  323. }
  324. }
  325. else
  326. {
  327. float s = Math::sqrt( (1+d)*2 );
  328. float invs = 1 / s;
  329. Vector3 c = v0.cross(v1);
  330. q.x = c.x * invs;
  331. q.y = c.y * invs;
  332. q.z = c.z * invs;
  333. q.w = s * 0.5f;
  334. q.normalize();
  335. }
  336. return q;
  337. }
  338. Quaternion operator* (float lhs, const Quaternion& rhs)
  339. {
  340. return Quaternion(lhs*rhs.w,lhs*rhs.x,lhs*rhs.y,
  341. lhs*rhs.z);
  342. }
  343. }