💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

467 lines
11 KiB

  1. /*
  2. * Copyright (C) 2020 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_MATH_QUATERNION_FUNCTIONS_HPP
  20. #define ANTKEEPER_MATH_QUATERNION_FUNCTIONS_HPP
  21. #include "math/matrix-type.hpp"
  22. #include "math/quaternion-type.hpp"
  23. #include "math/vector-type.hpp"
  24. #include "math/vector-functions.hpp"
  25. #include <cmath>
  26. namespace math {
  27. /// @addtogroup quaternion
  28. /// @{
  29. /**
  30. * Adds two quaternions.
  31. *
  32. * @param x First quaternion.
  33. * @param y Second quaternion.
  34. * @return Sum of the two quaternions.
  35. */
  36. template <class T>
  37. quaternion<T> add(const quaternion<T>& x, const quaternion<T>& y);
  38. /**
  39. * Calculates the conjugate of a quaternion.
  40. *
  41. * @param x Quaternion from which the conjugate will be calculated.
  42. * @return Conjugate of the quaternion.
  43. */
  44. template <class T>
  45. quaternion<T> conjugate(const quaternion<T>& x);
  46. /**
  47. * Calculates the dot product of two quaternions.
  48. *
  49. * @param x First quaternion.
  50. * @param y Second quaternion.
  51. * @return Dot product of the two quaternions.
  52. */
  53. template <class T>
  54. T dot(const quaternion<T>& x, const quaternion<T>& y);
  55. /**
  56. * Divides a quaternion by a scalar.
  57. *
  58. * @param q Quaternion.
  59. * @param s Scalar.
  60. * @return Result of the division.
  61. */
  62. template <class T>
  63. quaternion<T> div(const quaternion<T>& q, T s);
  64. /**
  65. * Calculates the length of a quaternion.
  66. *
  67. * @param x Quaternion to calculate the length of.
  68. * @return Length of the quaternion.
  69. */
  70. template <class T>
  71. T length(const quaternion<T>& x);
  72. /**
  73. * Calculates the squared length of a quaternion. The squared length can be calculated faster than the length because a call to `std::sqrt` is saved.
  74. *
  75. * @param x Quaternion to calculate the squared length of.
  76. * @return Squared length of the quaternion.
  77. */
  78. template <class T>
  79. T length_squared(const quaternion<T>& x);
  80. /**
  81. * Performs linear interpolation between two quaternions.
  82. *
  83. * @param x First quaternion.
  84. * @param y Second quaternion.
  85. * @param a Interpolation factor.
  86. * @return Interpolated quaternion.
  87. */
  88. template <class T>
  89. quaternion<T> lerp(const quaternion<T>& x, const quaternion<T>& y, T a);
  90. /**
  91. * Creates a unit quaternion rotation using forward and up vectors.
  92. *
  93. * @param forward Unit forward vector.
  94. * @param up Unit up vector.
  95. * @return Unit rotation quaternion.
  96. */
  97. template <class T>
  98. quaternion<T> look_rotation(const vector<T, 3>& forward, vector<T, 3> up);
  99. /**
  100. * Converts a quaternion to a rotation matrix.
  101. *
  102. * @param q Unit quaternion.
  103. * @return Matrix representing the rotation described by `q`.
  104. */
  105. template <class T>
  106. matrix<T, 3, 3> matrix_cast(const quaternion<T>& q);
  107. /**
  108. * Multiplies two quaternions.
  109. *
  110. * @param x First quaternion.
  111. * @param y Second quaternion.
  112. * @return Product of the two quaternions.
  113. */
  114. template <class T>
  115. quaternion<T> mul(const quaternion<T>& x, const quaternion<T>& y);
  116. /**
  117. * Multiplies a quaternion by a scalar.
  118. *
  119. * @param q Quaternion.
  120. * @param s Scalar.
  121. * @return Product of the quaternion and scalar.
  122. */
  123. template <class T>
  124. quaternion<T> mul(const quaternion<T>& q, T s);
  125. /**
  126. * Rotates a 3-dimensional vector by a quaternion.
  127. *
  128. * @param q Unit quaternion.
  129. * @param v Vector.
  130. * @return Rotated vector.
  131. */
  132. template <class T>
  133. vector<T, 3> mul(const quaternion<T>& q, const vector<T, 3>& v);
  134. /**
  135. * Negates a quaternion.
  136. */
  137. template <class T>
  138. quaternion<T> negate(const quaternion<T>& x);
  139. /**
  140. * Performs normalized linear interpolation between two quaternions.
  141. *
  142. * @param x First quaternion.
  143. * @param y Second quaternion.
  144. * @param a Interpolation factor.
  145. * @return Interpolated quaternion.
  146. */
  147. template <class T>
  148. quaternion<T> nlerp(const quaternion<T>& x, const quaternion<T>& y, T a);
  149. /**
  150. * Normalizes a quaternion.
  151. */
  152. template <class T>
  153. quaternion<T> normalize(const quaternion<T>& x);
  154. /**
  155. * Creates a rotation from an angle and axis.
  156. *
  157. * @param angle Angle of rotation (in radians).
  158. * @param axis Axis of rotation
  159. * @return Quaternion representing the rotation.
  160. */
  161. template <class T>
  162. quaternion<T> angle_axis(T angle, const vector<T, 3>& axis);
  163. /**
  164. * Calculates the minimum rotation between two normalized direction vectors.
  165. *
  166. * @param source Normalized source direction.
  167. * @param destination Normalized destination direction.
  168. * @return Quaternion representing the minimum rotation between the source and destination vectors.
  169. */
  170. template <class T>
  171. quaternion<T> rotation(const vector<T, 3>& source, const vector<T, 3>& destination);
  172. /**
  173. * Performs spherical linear interpolation between two quaternions.
  174. *
  175. * @param x First quaternion.
  176. * @param y Second quaternion.
  177. * @param a Interpolation factor.
  178. * @return Interpolated quaternion.
  179. */
  180. template <class T>
  181. quaternion<T> slerp(const quaternion<T>& x, const quaternion<T>& y, T a);
  182. /**
  183. * Subtracts a quaternion from another quaternion.
  184. *
  185. * @param x First quaternion.
  186. * @param y Second quaternion.
  187. * @return Difference between the quaternions.
  188. */
  189. template <class T>
  190. quaternion<T> sub(const quaternion<T>& x, const quaternion<T>& y);
  191. /**
  192. * Converts a 3x3 rotation matrix to a quaternion.
  193. *
  194. * @param m Rotation matrix.
  195. * @return Unit quaternion representing the rotation described by `m`.
  196. */
  197. template <class T>
  198. quaternion<T> quaternion_cast(const matrix<T, 3, 3>& m);
  199. template <class T>
  200. inline quaternion<T> add(const quaternion<T>& x, const quaternion<T>& y)
  201. {
  202. return {x.w + y.w, x.x + y.x, x.y + y.y, x.z + y.z};
  203. }
  204. template <class T>
  205. inline quaternion<T> conjugate(const quaternion<T>& x)
  206. {
  207. return {x.w, -x.x, -x.y, -x.z};
  208. }
  209. template <class T>
  210. inline T dot(const quaternion<T>& x, const quaternion<T>& y)
  211. {
  212. return {x.w * y.w + x.x * y.x + x.y * y.y + x.z * y.z};
  213. }
  214. template <class T>
  215. inline quaternion<T> div(const quaternion<T>& q, T s)
  216. {
  217. return {q.w / s, q.x / s, q.y / s, q.z / s}
  218. }
  219. template <class T>
  220. inline T length(const quaternion<T>& x)
  221. {
  222. return std::sqrt(x.w * x.w + x.x * x.x + x.y * x.y + x.z * x.z);
  223. }
  224. template <class T>
  225. inline T length_squared(const quaternion<T>& x)
  226. {
  227. return x.w * x.w + x.x * x.x + x.y * x.y + x.z * x.z;
  228. }
  229. template <class T>
  230. inline quaternion<T> lerp(const quaternion<T>& x, const quaternion<T>& y, T a)
  231. {
  232. return
  233. {
  234. (y.w - x.w) * a + x.w,
  235. (y.x - x.x) * a + x.x,
  236. (y.y - x.y) * a + x.y,
  237. (y.z - x.z) * a + x.z
  238. };
  239. }
  240. template <class T>
  241. quaternion<T> look_rotation(const vector<T, 3>& forward, vector<T, 3> up)
  242. {
  243. vector<T, 3> right = normalize(cross(forward, up));
  244. up = cross(right, forward);
  245. matrix<T, 3, 3> m =
  246. {{
  247. {right[0], up[0], -forward[0]},
  248. {right[1], up[1], -forward[1]},
  249. {right[2], up[2], -forward[2]}
  250. }};
  251. // Convert to quaternion
  252. return normalize(quaternion_cast(m));
  253. }
  254. template <class T>
  255. matrix<T, 3, 3> matrix_cast(const quaternion<T>& q)
  256. {
  257. T wx = q.w * q.x;
  258. T wy = q.w * q.y;
  259. T wz = q.w * q.z;
  260. T xx = q.x * q.x;
  261. T xy = q.x * q.y;
  262. T xz = q.x * q.z;
  263. T yy = q.y * q.y;
  264. T yz = q.y * q.z;
  265. T zz = q.z * q.z;
  266. return
  267. {{
  268. {T(1) - (yy + zz) * T(2), (xy + wz) * T(2), (xz - wy) * T(2)},
  269. {(xy - wz) * T(2), T(1) - (xx + zz) * T(2), (yz + wx) * T(2)},
  270. {(xz + wy) * T(2), (yz - wx) * T(2), T(1) - (xx + yy) * T(2)}
  271. }};
  272. }
  273. template <class T>
  274. quaternion<T> mul(const quaternion<T>& x, const quaternion<T>& y)
  275. {
  276. return
  277. {
  278. -x.x * y.x - x.y * y.y - x.z * y.z + x.w * y.w,
  279. x.x * y.w + x.y * y.z - x.z * y.y + x.w * y.x,
  280. -x.x * y.z + x.y * y.w + x.z * y.x + x.w * y.y,
  281. x.x * y.y - x.y * y.x + x.z * y.w + x.w * y.z
  282. };
  283. }
  284. template <class T>
  285. inline quaternion<T> mul(const quaternion<T>& q, T s)
  286. {
  287. return {q.w * s, q.x * s, q.y * s, q.z * s};
  288. }
  289. template <class T>
  290. vector<T, 3> mul(const quaternion<T>& q, const vector<T, 3>& v)
  291. {
  292. const T r = q.w; // Real part
  293. const vector<T, 3>& i = reinterpret_cast<const vector<T, 3>&>(q.x); // Imaginary part
  294. return i * dot(i, v) * T(2) + v * (r * r - dot(i, i)) + cross(i, v) * r * T(2);
  295. }
  296. template <class T>
  297. inline quaternion<T> negate(const quaternion<T>& x)
  298. {
  299. return {-x.w, -x.x, -x.y, -x.z};
  300. }
  301. template <class T>
  302. quaternion<T> nlerp(const quaternion<T>& x, const quaternion<T>& y, T a)
  303. {
  304. if (dot(x, y) < T(0))
  305. {
  306. return normalize(add(mul(x, T(1) - a), mul(y, -a)));
  307. }
  308. else
  309. {
  310. return normalize(add(mul(x, T(1) - a), mul(y, a)));
  311. }
  312. }
  313. template <class T>
  314. inline quaternion<T> normalize(const quaternion<T>& x)
  315. {
  316. return mul(x, T(1) / length(x));
  317. }
  318. template <class T>
  319. quaternion<T> angle_axis(T angle, const vector<T, 3>& axis)
  320. {
  321. T s = std::sin(angle * T(0.5));
  322. return {static_cast<T>(std::cos(angle * T(0.5))), axis.x * s, axis.y * s, axis.z * s};
  323. }
  324. template <class T>
  325. quaternion<T> rotation(const vector<T, 3>& source, const vector<T, 3>& destination)
  326. {
  327. quaternion<T> q;
  328. q.w = dot(source, destination);
  329. reinterpret_cast<vector<T, 3>&>(q.x) = cross(source, destination);
  330. q.w += length(q);
  331. return normalize(q);
  332. }
  333. template <class T>
  334. quaternion<T> slerp(const quaternion<T>& x, const quaternion<T>& y, T a)
  335. {
  336. T cos_theta = dot(x, y);
  337. constexpr T epsilon = T(0.0005);
  338. if (cos_theta > T(1) - epsilon)
  339. {
  340. return normalize(lerp(x, y, a));
  341. }
  342. cos_theta = std::max<T>(T(-1), std::min<T>(T(1), cos_theta));
  343. T theta = static_cast<T>(std::acos(cos_theta)) * a;
  344. quaternion<T> z = normalize(sub(y, mul(x, cos_theta)));
  345. return add(mul(x, static_cast<T>(std::cos(theta))), mul(z, static_cast<T>(std::sin(theta))));
  346. }
  347. template <class T>
  348. inline quaternion<T> sub(const quaternion<T>& x, const quaternion<T>& y)
  349. {
  350. return {x.w - y.w, x.x - y.x, x.y - y.y, x.z - y.z};
  351. }
  352. template <class T>
  353. quaternion<T> quaternion_cast(const matrix<T, 3, 3>& m)
  354. {
  355. T r;
  356. vector<T, 3> i;
  357. T trace = m[0][0] + m[1][1] + m[2][2];
  358. if (trace > T(0))
  359. {
  360. T s = T(0.5) / std::sqrt(trace + T(1));
  361. r = T(0.25) / s;
  362. i =
  363. {
  364. (m[2][1] - m[1][2]) * s,
  365. (m[0][2] - m[2][0]) * s,
  366. (m[1][0] - m[0][1]) * s
  367. };
  368. }
  369. else
  370. {
  371. if (m[0][0] > m[1][1] && m[0][0] > m[2][2])
  372. {
  373. T s = T(2) * std::sqrt(T(1) + m[0][0] - m[1][1] - m[2][2]);
  374. r = (m[2][1] - m[1][2]) / s;
  375. i =
  376. {
  377. T(0.25) * s,
  378. (m[0][1] + m[1][0]) / s,
  379. (m[0][2] + m[2][0]) / s
  380. };
  381. }
  382. else if (m[1][1] > m[2][2])
  383. {
  384. T s = T(2) * std::sqrt(T(1) + m[1][1] - m[0][0] - m[2][2]);
  385. r = (m[0][2] - m[2][0]) / s;
  386. i =
  387. {
  388. (m[0][1] + m[1][0]) / s,
  389. T(0.25) * s,
  390. (m[1][2] + m[2][1]) / s
  391. };
  392. }
  393. else
  394. {
  395. T s = T(2) * std::sqrt(T(1) + m[2][2] - m[0][0] - m[1][1]);
  396. r = (m[1][0] - m[0][1]) / s;
  397. i =
  398. {
  399. (m[0][2] + m[2][0]) / s,
  400. (m[1][2] + m[2][1]) / s,
  401. T(0.25) * s
  402. };
  403. }
  404. }
  405. return {r, i.x, i.y, i.z};
  406. }
  407. /// @}
  408. } // namespace math
  409. #endif // ANTKEEPER_MATH_QUATERNION_FUNCTIONS_HPP