Quaternion.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. #include "Base.h"
  2. #include "Quaternion.h"
  3. namespace gameplay
  4. {
  5. Quaternion::Quaternion()
  6. : x(0.0f), y(0.0f), z(0.0f), w(1.0f)
  7. {
  8. }
  9. Quaternion::Quaternion(float x, float y, float z, float w)
  10. : x(x), y(y), z(z), w(w)
  11. {
  12. }
  13. Quaternion::Quaternion(float* array)
  14. {
  15. set(array);
  16. }
  17. Quaternion::Quaternion(const Matrix& m)
  18. {
  19. set(m);
  20. }
  21. Quaternion::Quaternion(const Vector3& axis, float angle)
  22. {
  23. set(axis, angle);
  24. }
  25. Quaternion::Quaternion(const Quaternion& copy)
  26. {
  27. set(copy);
  28. }
  29. Quaternion::~Quaternion()
  30. {
  31. }
  32. const Quaternion& Quaternion::identity()
  33. {
  34. static Quaternion value(0.0f, 0.0f, 0.0f, 1.0f);
  35. return value;
  36. }
  37. const Quaternion& Quaternion::zero()
  38. {
  39. static Quaternion value(0.0f, 0.0f, 0.0f, 0.0f);
  40. return value;
  41. }
  42. bool Quaternion::isIdentity() const
  43. {
  44. return x == 0.0f && y == 0.0f && z == 0.0f && w == 1.0f;
  45. }
  46. bool Quaternion::isZero() const
  47. {
  48. return x == 0.0f && y == 0.0f && z == 0.0f && w == 0.0f;
  49. }
  50. void Quaternion::createFromRotationMatrix(const Matrix& m, Quaternion* dst)
  51. {
  52. m.getRotation(dst);
  53. }
  54. void Quaternion::createFromAxisAngle(const Vector3& axis, float angle, Quaternion* dst)
  55. {
  56. GP_ASSERT(dst);
  57. float halfAngle = angle * 0.5f;
  58. float sinHalfAngle = sinf(halfAngle);
  59. Vector3 normal(axis);
  60. normal.normalize();
  61. dst->x = normal.x * sinHalfAngle;
  62. dst->y = normal.y * sinHalfAngle;
  63. dst->z = normal.z * sinHalfAngle;
  64. dst->w = cosf(halfAngle);
  65. }
  66. void Quaternion::conjugate()
  67. {
  68. conjugate(this);
  69. }
  70. void Quaternion::conjugate(Quaternion* dst) const
  71. {
  72. GP_ASSERT(dst);
  73. dst->x = -x;
  74. dst->y = -y;
  75. dst->z = -z;
  76. dst->w = w;
  77. }
  78. bool Quaternion::inverse()
  79. {
  80. return inverse(this);
  81. }
  82. bool Quaternion::inverse(Quaternion* dst) const
  83. {
  84. GP_ASSERT(dst);
  85. float n = x * x + y * y + z * z + w * w;
  86. if (n == 1.0f)
  87. {
  88. dst->x = -x;
  89. dst->y = -y;
  90. dst->z = -z;
  91. dst->w = w;
  92. return true;
  93. }
  94. // Too close to zero.
  95. if (n < 0.000001f)
  96. return false;
  97. n = 1.0f / n;
  98. dst->x = -x * n;
  99. dst->y = -y * n;
  100. dst->z = -z * n;
  101. dst->w = w * n;
  102. return true;
  103. }
  104. void Quaternion::multiply(const Quaternion& q)
  105. {
  106. multiply(*this, q, this);
  107. }
  108. void Quaternion::multiply(const Quaternion& q1, const Quaternion& q2, Quaternion* dst)
  109. {
  110. GP_ASSERT(dst);
  111. float x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
  112. float y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
  113. float z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
  114. float w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
  115. dst->x = x;
  116. dst->y = y;
  117. dst->z = z;
  118. dst->w = w;
  119. }
  120. void Quaternion::normalize()
  121. {
  122. normalize(this);
  123. }
  124. void Quaternion::normalize(Quaternion* dst) const
  125. {
  126. GP_ASSERT(dst);
  127. if (this != dst)
  128. {
  129. dst->x = x;
  130. dst->y = y;
  131. dst->z = z;
  132. dst->w = w;
  133. }
  134. float n = x * x + y * y + z * z + w * w;
  135. // Already normalized.
  136. if (n == 1.0f)
  137. return;
  138. n = sqrt(n);
  139. // Too close to zero.
  140. if (n < 0.000001f)
  141. return;
  142. n = 1.0f / n;
  143. dst->x *= n;
  144. dst->y *= n;
  145. dst->z *= n;
  146. dst->w *= n;
  147. }
  148. void Quaternion::set(float x, float y, float z, float w)
  149. {
  150. this->x = x;
  151. this->y = y;
  152. this->z = z;
  153. this->w = w;
  154. }
  155. void Quaternion::set(float* array)
  156. {
  157. GP_ASSERT(array);
  158. x = array[0];
  159. y = array[1];
  160. z = array[2];
  161. w = array[3];
  162. }
  163. void Quaternion::set(const Matrix& m)
  164. {
  165. Quaternion::createFromRotationMatrix(m, this);
  166. }
  167. void Quaternion::set(const Vector3& axis, float angle)
  168. {
  169. Quaternion::createFromAxisAngle(axis, angle, this);
  170. }
  171. void Quaternion::set(const Quaternion& q)
  172. {
  173. this->x = q.x;
  174. this->y = q.y;
  175. this->z = q.z;
  176. this->w = q.w;
  177. }
  178. void Quaternion::setIdentity()
  179. {
  180. x = 0.0f;
  181. y = 0.0f;
  182. z = 0.0f;
  183. w = 1.0f;
  184. }
  185. float Quaternion::toAxisAngle(Vector3* axis) const
  186. {
  187. GP_ASSERT(axis);
  188. Quaternion q(x, y, z, w);
  189. q.normalize();
  190. axis->x = q.x;
  191. axis->y = q.y;
  192. axis->z = q.z;
  193. axis->normalize();
  194. return (2.0f * acos(q.w));
  195. }
  196. void Quaternion::lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)
  197. {
  198. GP_ASSERT(dst);
  199. GP_ASSERT(!(t < 0.0f || t > 1.0f));
  200. if (t == 0.0f)
  201. {
  202. memcpy(dst, &q1, sizeof(float) * 4);
  203. return;
  204. }
  205. else if (t == 1.0f)
  206. {
  207. memcpy(dst, &q2, sizeof(float) * 4);
  208. return;
  209. }
  210. float t1 = 1.0f - t;
  211. dst->x = t1 * q1.x + t * q2.x;
  212. dst->y = t1 * q1.y + t * q2.y;
  213. dst->z = t1 * q1.z + t * q2.z;
  214. dst->w = t1 * q1.w + t * q2.w;
  215. }
  216. void Quaternion::slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)
  217. {
  218. GP_ASSERT(dst);
  219. slerp(q1.x, q1.y, q1.z, q1.w, q2.x, q2.y, q2.z, q2.w, t, &dst->x, &dst->y, &dst->z, &dst->w);
  220. }
  221. void Quaternion::squad(const Quaternion& q1, const Quaternion& q2, const Quaternion& s1, const Quaternion& s2, float t, Quaternion* dst)
  222. {
  223. GP_ASSERT(!(t < 0.0f || t > 1.0f));
  224. Quaternion dstQ(0.0f, 0.0f, 0.0f, 1.0f);
  225. Quaternion dstS(0.0f, 0.0f, 0.0f, 1.0f);
  226. slerpForSquad(q1, q2, t, &dstQ);
  227. slerpForSquad(s1, s2, t, &dstS);
  228. slerpForSquad(dstQ, dstS, 2.0f * t * (1.0f - t), dst);
  229. }
  230. void Quaternion::slerp(float q1x, float q1y, float q1z, float q1w, float q2x, float q2y, float q2z, float q2w, float t, float* dstx, float* dsty, float* dstz, float* dstw)
  231. {
  232. // Fast slerp implementation by kwhatmough:
  233. // It contains no division operations, no trig, no inverse trig
  234. // and no sqrt. Not only does this code tolerate small constraint
  235. // errors in the input quaternions, it actually corrects for them.
  236. GP_ASSERT(dstx && dsty && dstz && dstw);
  237. GP_ASSERT(!(t < 0.0f || t > 1.0f));
  238. if (t == 0.0f)
  239. {
  240. *dstx = q1x;
  241. *dsty = q1y;
  242. *dstz = q1z;
  243. *dstw = q1w;
  244. return;
  245. }
  246. else if (t == 1.0f)
  247. {
  248. *dstx = q2x;
  249. *dsty = q2y;
  250. *dstz = q2z;
  251. *dstw = q2w;
  252. return;
  253. }
  254. if (q1x == q2x && q1y == q2y && q1z == q2z && q1w == q2w)
  255. {
  256. *dstx = q1x;
  257. *dsty = q1y;
  258. *dstz = q1z;
  259. *dstw = q1w;
  260. return;
  261. }
  262. float halfY, alpha, beta;
  263. float u, f1, f2a, f2b;
  264. float ratio1, ratio2;
  265. float halfSecHalfTheta, versHalfTheta;
  266. float sqNotU, sqU;
  267. float cosTheta = q1w * q2w + q1x * q2x + q1y * q2y + q1z * q2z;
  268. // As usual in all slerp implementations, we fold theta.
  269. alpha = cosTheta >= 0 ? 1.0f : -1.0f;
  270. halfY = 1.0f + alpha * cosTheta;
  271. // Here we bisect the interval, so we need to fold t as well.
  272. f2b = t - 0.5f;
  273. u = f2b >= 0 ? f2b : -f2b;
  274. f2a = u - f2b;
  275. f2b += u;
  276. u += u;
  277. f1 = 1.0f - u;
  278. // One iteration of Newton to get 1-cos(theta / 2) to good accuracy.
  279. halfSecHalfTheta = 1.09f - (0.476537f - 0.0903321f * halfY) * halfY;
  280. halfSecHalfTheta *= 1.5f - halfY * halfSecHalfTheta * halfSecHalfTheta;
  281. versHalfTheta = 1.0f - halfY * halfSecHalfTheta;
  282. // Evaluate series expansions of the coefficients.
  283. sqNotU = f1 * f1;
  284. ratio2 = 0.0000440917108f * versHalfTheta;
  285. ratio1 = -0.00158730159f + (sqNotU - 16.0f) * ratio2;
  286. ratio1 = 0.0333333333f + ratio1 * (sqNotU - 9.0f) * versHalfTheta;
  287. ratio1 = -0.333333333f + ratio1 * (sqNotU - 4.0f) * versHalfTheta;
  288. ratio1 = 1.0f + ratio1 * (sqNotU - 1.0f) * versHalfTheta;
  289. sqU = u * u;
  290. ratio2 = -0.00158730159f + (sqU - 16.0f) * ratio2;
  291. ratio2 = 0.0333333333f + ratio2 * (sqU - 9.0f) * versHalfTheta;
  292. ratio2 = -0.333333333f + ratio2 * (sqU - 4.0f) * versHalfTheta;
  293. ratio2 = 1.0f + ratio2 * (sqU - 1.0f) * versHalfTheta;
  294. // Perform the bisection and resolve the folding done earlier.
  295. f1 *= ratio1 * halfSecHalfTheta;
  296. f2a *= ratio2;
  297. f2b *= ratio2;
  298. alpha *= f1 + f2a;
  299. beta = f1 + f2b;
  300. // Apply final coefficients to a and b as usual.
  301. float w = alpha * q1w + beta * q2w;
  302. float x = alpha * q1x + beta * q2x;
  303. float y = alpha * q1y + beta * q2y;
  304. float z = alpha * q1z + beta * q2z;
  305. // This final adjustment to the quaternion's length corrects for
  306. // any small constraint error in the inputs q1 and q2 But as you
  307. // can see, it comes at the cost of 9 additional multiplication
  308. // operations. If this error-correcting feature is not required,
  309. // the following code may be removed.
  310. f1 = 1.5f - 0.5f * (w * w + x * x + y * y + z * z);
  311. *dstw = w * f1;
  312. *dstx = x * f1;
  313. *dsty = y * f1;
  314. *dstz = z * f1;
  315. }
  316. void Quaternion::slerpForSquad(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)
  317. {
  318. GP_ASSERT(dst);
  319. // cos(omega) = q1 * q2;
  320. // slerp(q1, q2, t) = (q1*sin((1-t)*omega) + q2*sin(t*omega))/sin(omega);
  321. // q1 = +- q2, slerp(q1,q2,t) = q1.
  322. // This is a straight-foward implementation of the formula of slerp. It does not do any sign switching.
  323. float c = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
  324. if (fabs(c) >= 1.0f)
  325. {
  326. dst->x = q1.x;
  327. dst->y = q1.y;
  328. dst->z = q1.z;
  329. dst->w = q1.w;
  330. return;
  331. }
  332. float omega = acos(c);
  333. float s = sqrt(1.0f - c * c);
  334. if (fabs(s) <= 0.00001f)
  335. {
  336. dst->x = q1.x;
  337. dst->y = q1.y;
  338. dst->z = q1.z;
  339. dst->w = q1.w;
  340. return;
  341. }
  342. float r1 = sin((1 - t) * omega) / s;
  343. float r2 = sin(t * omega) / s;
  344. dst->x = (q1.x * r1 + q2.x * r2);
  345. dst->y = (q1.y * r1 + q2.y * r2);
  346. dst->z = (q1.z * r1 + q2.z * r2);
  347. dst->w = (q1.w * r1 + q2.w * r2);
  348. }
  349. }