quaternion.inl - Engine C API Reference

quaternion.inl
  1. #include "vector3.h"
  2. #include "matrix4x4.h"
  3. namespace stingray_plugin_foundation {
  4. // Operators
  5. __forceinline Quaternion operator +(const Quaternion &q) {
  6. return q;
  7. }
  8. __forceinline Quaternion operator -(const Quaternion &q) {
  9. return quaternion(-q.x, -q.y, -q.z, q.w);
  10. }
  11. __forceinline Quaternion operator +(const Quaternion &lhs, const Quaternion &rhs) {
  12. return quaternion(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z, lhs.w+rhs.w);
  13. }
  14. __forceinline Quaternion operator -(const Quaternion &lhs, const Quaternion &rhs) {
  15. return quaternion(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-rhs.w);
  16. }
  17. __forceinline Quaternion operator *(const Quaternion &lhs, const Quaternion &rhs) {
  18. return quaternion(
  19. lhs.w*rhs.x + lhs.x*rhs.w + lhs.y*rhs.z - lhs.z*rhs.y,
  20. lhs.w*rhs.y + lhs.y*rhs.w + lhs.z*rhs.x - lhs.x*rhs.z,
  21. lhs.w*rhs.z + lhs.z*rhs.w + lhs.x*rhs.y - lhs.y*rhs.x,
  22. lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z*rhs.z
  23. );
  24. }
  25. __forceinline Quaternion operator *(const Quaternion &lhs, float rhs) {
  26. return quaternion(lhs.x*rhs, lhs.y*rhs, lhs.z*rhs, lhs.w*rhs);
  27. }
  28. __forceinline Quaternion operator *(float lhs, const Quaternion &rhs) {
  29. return rhs * lhs;
  30. }
  31. __forceinline Quaternion operator /(const Quaternion &lhs, float rhs) {
  32. return quaternion(lhs.x/rhs, lhs.y/rhs, lhs.z/rhs, lhs.w/rhs);
  33. }
  34. __forceinline void operator +=(Quaternion &lhs, const Quaternion &rhs) {
  35. lhs.x+=rhs.x; lhs.y+=rhs.y; lhs.z+=rhs.z; lhs.w+=rhs.w;
  36. }
  37. __forceinline void operator -=(Quaternion &lhs, const Quaternion &rhs) {
  38. lhs.x-=rhs.x; lhs.y-=rhs.y; lhs.z-=rhs.z; lhs.w-=rhs.w;
  39. }
  40. __forceinline void operator *=(Quaternion &lhs, const Quaternion &rhs) {
  41. lhs.x*=rhs.x; lhs.y*=rhs.y; lhs.z*=rhs.z; lhs.w*=rhs.w;
  42. }
  43. __forceinline void operator *=(Quaternion &lhs, float rhs) {
  44. lhs.x*=rhs; lhs.y*=rhs; lhs.z*=rhs; lhs.w*=rhs;
  45. }
  46. __forceinline bool operator==(const Quaternion &lhs, const Quaternion &rhs)
  47. {
  48. return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w;
  49. }
  50. __forceinline bool operator!=(const Quaternion &lhs, const Quaternion &rhs)
  51. {
  52. return !(lhs == rhs);
  53. }
  54. __forceinline bool operator< (const Quaternion &lhs, const Quaternion &rhs)
  55. {
  56. if (lhs.x != rhs.x) return lhs.x < rhs.x;
  57. if (lhs.y != rhs.y) return lhs.y < rhs.y;
  58. if (lhs.z != rhs.z) return lhs.z < rhs.z;
  59. return lhs.w < rhs.w;
  60. }
  61. __forceinline bool operator<=(const Quaternion &lhs, const Quaternion &rhs)
  62. {
  63. return (lhs < rhs) || (lhs == rhs);
  64. }
  65. __forceinline bool operator> (const Quaternion &lhs, const Quaternion &rhs)
  66. {
  67. return (rhs < lhs);
  68. }
  69. __forceinline bool operator>=(const Quaternion &lhs, const Quaternion &rhs)
  70. {
  71. return !(lhs < rhs);
  72. }
  73. // Creation Methods
  74. __forceinline Quaternion quaternion(const float * list) {
  75. Quaternion q = { *list, *(list+1), *(list+2), *(list+3) };
  76. return q;
  77. }
  78. __forceinline Quaternion quaternion(float x, float y, float z, float w) {
  79. Quaternion q = { x, y, z, w };
  80. return q;
  81. }
  82. __forceinline const Quaternion &quaternion_identity() {
  83. static Quaternion q = { 0.f, 0.f, 0.f, 1.f };
  84. return q;
  85. }
  86. __forceinline Quaternion quaternion(const Vector3 &axis, float theta) {
  87. Quaternion q;
  88. float halftheta = theta * 0.5f;
  89. float cos_ht = cosf( halftheta );
  90. float sin_ht = sinf( halftheta );
  91. q.x = axis.x * sin_ht;
  92. q.y = axis.y * sin_ht;
  93. q.z = axis.z * sin_ht;
  94. q.w = cos_ht;
  95. return q;
  96. }
  97. // Methods
  98. __forceinline Quaternion normalize(const Quaternion &q) {
  99. float l = math::square_root( dot(q,q) );
  100. if(l == 0.0f)
  101. return quaternion(0.f, 0.f, 0.f, 1.f);
  102. else {
  103. float c = 1.0f / l;
  104. return quaternion(q.x*c, q.y*c, q.z*c, q.w*c);
  105. }
  106. }
  107. __forceinline Quaternion inverse(const Quaternion &q) {
  108. float l = dot(q,q);
  109. if (l == 0.0f)
  110. l = 1.0f;
  111. float norminv = -1.0f / l;
  112. return quaternion(q.x*norminv, q.y*norminv, q.z*norminv, q.w*-norminv);
  113. }
  114. __forceinline Quaternion conjugate(const Quaternion &q) {
  115. return quaternion(-q.x, -q.y, -q.z, q.w);
  116. }
  117. __forceinline float dot(const Quaternion &q1, const Quaternion &q2) {
  118. return q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
  119. }
  120. __forceinline Quaternion slerp(const Quaternion &from, const Quaternion &to, float t) {
  121. Quaternion q;
  122. Quaternion q3;
  123. float d = dot(from, to);
  124. if (d < 0) {
  125. d = -d;
  126. q3 = to * -1.0f;
  127. } else
  128. q3 = to;
  129. // Use linear interpolation for small angles.
  130. if (d < 0.95f) {
  131. float clamped_dot = math::clamp(d, -1.0f, 1.0f);
  132. float angle = acosf(clamped_dot);
  133. float sina, sinat, sinaomt;
  134. sina = sinf(angle);
  135. sinat = sinf(angle*t);
  136. sinaomt = sinf(angle*(1-t));
  137. q = (from*sinaomt+q3*sinat)/sina;
  138. } else
  139. q = nlerp(from, q3,t);
  140. return q;
  141. }
  142. __forceinline Quaternion nlerp(const Quaternion &from, const Quaternion &to, float t) {
  143. Quaternion q;
  144. if(dot(from, to) < 0)
  145. q = ((to + from) * t) - from;
  146. else
  147. q = from + ((to - from) * t);
  148. return normalize(q);
  149. }
  150. // lerp for quaternions defaults to nlerp
  151. __forceinline Quaternion lerp(const Quaternion &from, const Quaternion &to, float t) {
  152. Quaternion q;
  153. if(dot(from, to) < 0)
  154. q = ((to + from) * t) - from;
  155. else
  156. q = from + ((to - from) * t);
  157. return normalize(q);
  158. }
  159. // Scales the angle in the rotation the quaternion represents by t.
  160. __forceinline Quaternion scale_angle(const Quaternion &from, float t)
  161. {
  162. Vector3 axis;
  163. float theta;
  164. decompose(from, &axis, &theta);
  165. return quaternion(axis, theta*t);
  166. }
  167. __forceinline bool is_zero(const Quaternion &q)
  168. {
  169. return q.x == 0 && q.y == 0 && q.z == 0 && q.w == 0;
  170. }
  171. __forceinline float norm(const Quaternion &q)
  172. {
  173. return math::square_root(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
  174. }
  175. __forceinline float one_norm(const Quaternion &q)
  176. {
  177. return math::abs(q.x) + math::abs(q.y) + math::abs(q.z) + math::abs(q.w);
  178. }
  179. __forceinline float infinity_norm(const Quaternion &q)
  180. {
  181. return math::max<float>(
  182. math::max<float>(math::abs(q.x),
  183. math::abs(q.y)),
  184. math::max<float>(math::abs(q.z),
  185. math::abs(q.w)) );
  186. }
  187. __forceinline Vector3 rotate(const Quaternion &q, const Vector3 &v)
  188. {
  189. Quaternion v_quat = quaternion(v.x, v.y, v.z, 0.0f);
  190. Quaternion result(q * v_quat * conjugate(q));
  191. return vector3(result.x, result.y, result.z);
  192. }
  193. // Conversion Methods
  194. __forceinline Matrix4x4 matrix4x4(const Quaternion &q) {
  195. const float d = dot(q,q);
  196. float s;
  197. if(d)
  198. s = 2.0f / d;
  199. else
  200. s = 1.0f;
  201. const float xs = q.x * s;
  202. const float ys = q.y * s;
  203. const float zs = q.z * s;
  204. const float wx = q.w * xs;
  205. const float wy = q.w * ys;
  206. const float wz = q.w * zs;
  207. const float xx = q.x * xs;
  208. const float xy = q.x * ys;
  209. const float xz = q.x * zs;
  210. const float yy = q.y * ys;
  211. const float yz = q.y * zs;
  212. const float zz = q.z * zs;
  213. Matrix4x4 m = {
  214. (1.0f - yy - zz), (xy + wz), (xz - wy), 0.0f,
  215. (xy - wz), (1.0f - xx - zz), (yz + wx), 0.0f,
  216. (xz + wy), (yz - wx), (1.0f - xx - yy), 0.0f,
  217. 0.f, 0.f, 0.f, 1.f
  218. };
  219. return m;
  220. }
  221. __forceinline Matrix4x4 matrix4x4(const Quaternion &q, const Vector3 &p)
  222. {
  223. const float d = dot(q,q);
  224. float s;
  225. if(d)
  226. s = 2.0f / d;
  227. else
  228. s = 1.0f;
  229. const float xs = q.x * s;
  230. const float ys = q.y * s;
  231. const float zs = q.z * s;
  232. const float wx = q.w * xs;
  233. const float wy = q.w * ys;
  234. const float wz = q.w * zs;
  235. const float xx = q.x * xs;
  236. const float xy = q.x * ys;
  237. const float xz = q.x * zs;
  238. const float yy = q.y * ys;
  239. const float yz = q.y * zs;
  240. const float zz = q.z * zs;
  241. Matrix4x4 m = {
  242. (1.0f - yy - zz), (xy + wz), (xz - wy), 0.0f,
  243. (xy - wz), (1.0f - xx - zz), (yz + wx), 0.0f,
  244. (xz + wy), (yz - wx), (1.0f - xx - yy), 0.0f,
  245. p.x, p.y, p.z, 1.f
  246. };
  247. return m;
  248. }
  249. __forceinline void decompose(const Quaternion &q, Vector3 *axis, float *theta)
  250. {
  251. Vector3 a = vector3(q.x, q.y, q.z);
  252. float s = length(a);
  253. float c = q.w;
  254. float half_theta = atan2f(s, c);
  255. *theta = half_theta * 2.0f;
  256. *axis = s ? a / s : vector3(1,0,0);
  257. }
  258. __forceinline float angle(const Quaternion &q)
  259. {
  260. Vector3 a = vector3(q.x, q.y, q.z);
  261. float s = length(a);
  262. float c = q.w;
  263. float half_theta = atan2f(s, c);
  264. return half_theta * 2.0f;
  265. }
  266. __forceinline void lerp(const Matrix4x4 &m1, const Matrix4x4 &m2, float t, Matrix4x4 &m)
  267. {
  268. Vector3 p = lerp(translation(m1), translation(m2), t);
  269. Quaternion q = lerp(quaternion(m1), quaternion(m2), t);
  270. m = matrix4x4(q, p);
  271. }
  272. inline Quaternion quaternion_orthogonal(const Matrix4x4 &mat) {
  273. static const int kx = 0;
  274. static const int ky = 1;
  275. static const int kz = 2;
  276. static const int kw = 3;
  277. struct ShadowMatrix {
  278. float m[4][4];
  279. };
  280. const ShadowMatrix* m = reinterpret_cast<const ShadowMatrix*>(&mat);
  281. Quaternion r;
  282. float *q = reinterpret_cast<float *>(&r);
  283. // This code can be optimized for m[kw][kw] = 1, which
  284. // should always be true. This optimization is excluded
  285. // here for clarity.
  286. float trace = m->m[kx][kx] + m->m[ky][ky] + m->m[kz][kz] + m->m[kw][kw];
  287. float four_d;
  288. int i,j,k;
  289. if (trace >= 1.0) // w >= 0.5
  290. {
  291. four_d = 2.0f*math::square_root(trace);
  292. q[kw] = -four_d / 4.0f;
  293. const float one_over_coeff = 1.0f / four_d;
  294. q[kx] = (m->m[kz][ky] - m->m[ky][kz])*one_over_coeff;
  295. q[ky] = (m->m[kx][kz] - m->m[kz][kx])*one_over_coeff;
  296. q[kz] = (m->m[ky][kx] - m->m[kx][ky])*one_over_coeff;
  297. }
  298. else
  299. {
  300. // Find the largest component
  301. if (m->m[kx][kx] > m->m[ky][ky])
  302. i = kx;
  303. else
  304. i = ky;
  305. if (m->m[kz][kz] > m->m[i][i])
  306. i = kz;
  307. // Set j and k to next two components
  308. j = (1 << i) & 3;
  309. k = (1 << j) & 3;
  310. four_d = 2.0f*math::square_root(m->m[i][i] - m->m[j][j] - m->m[k][k] + 1.0f );
  311. q[i] = four_d/4.0f;
  312. const float one_over_coeff = 1.0f / four_d;
  313. q[j] = (m->m[j][i] + m->m[i][j])*one_over_coeff;
  314. q[k] = (m->m[k][i] + m->m[i][k])*one_over_coeff;
  315. q[kw] = -(m->m[k][j] - m->m[j][k])*one_over_coeff;
  316. }
  317. return r;
  318. }
  319. inline Quaternion quaternion(const Matrix4x4 &mat)
  320. {
  321. static const int kx = 0;
  322. static const int ky = 1;
  323. static const int kz = 2;
  324. static const int kw = 3;
  325. const Vector3 scale = stingray_plugin_foundation::scale(mat);
  326. const float *s = reinterpret_cast<const float *>(&scale);
  327. // If scale is small return an identity quaternion
  328. const float eps = 1e-5;
  329. if (scale.x > -eps && scale.x < eps || scale.y > -eps && scale.y < eps || scale.z > -eps && scale.z < eps)
  330. return quaternion_identity();
  331. struct ShadowMatrix {
  332. float m[4][4];
  333. };
  334. const ShadowMatrix* m = reinterpret_cast<const ShadowMatrix*>(&mat);
  335. Quaternion r;
  336. float *q = reinterpret_cast<float *>(&r);
  337. // This code can be optimized for m[kw][kw] = 1, which
  338. // should always be true. This optimization is excluded
  339. // here for clarity.
  340. const float trace = m->m[kx][kx] / s[kx] + m->m[ky][ky] / s[ky] + m->m[kz][kz] / s[kz] + m->m[kw][kw];
  341. if (trace >= 1.0) // w >= 0.5
  342. {
  343. const float four_d = 2.0f*math::square_root(trace);
  344. q[kw] = -four_d / 4.0f;
  345. const float one_over_coeff = 1.0f / four_d;
  346. q[kx] = (m->m[kz][ky] / s[kz] - m->m[ky][kz] / s[ky])*one_over_coeff;
  347. q[ky] = (m->m[kx][kz] / s[kx] - m->m[kz][kx] / s[kz])*one_over_coeff;
  348. q[kz] = (m->m[ky][kx] / s[ky] - m->m[kx][ky] / s[kx])*one_over_coeff;
  349. }
  350. else
  351. {
  352. // Find the largest component
  353. int i;
  354. if (m->m[kx][kx] / s[kx] > m->m[ky][ky] / s[ky])
  355. i = kx;
  356. else
  357. i = ky;
  358. if (m->m[kz][kz] / s[kz] > m->m[i][i] / s[i])
  359. i = kz;
  360. // Set j and k to next two components
  361. const int j = (1 << i) & 3;
  362. const int k = (1 << j) & 3;
  363. const float four_d = 2.0f*math::square_root(m->m[i][i] / s[i] - m->m[j][j] / s[j] - m->m[k][k] / s[k] + 1.0f );
  364. q[i] = four_d/4.0f;
  365. const float one_over_coeff = 1.0f / four_d;
  366. q[j] = (m->m[j][i] / s[j] + m->m[i][j] / s[i])*one_over_coeff;
  367. q[k] = (m->m[k][i] / s[k] + m->m[i][k] / s[i])*one_over_coeff;
  368. q[kw] = -(m->m[k][j] / s[k] - m->m[j][k] / s[j])*one_over_coeff;
  369. }
  370. return r;
  371. }
  372. inline Quaternion quaternion(const Matrix3x3 &mat)
  373. {
  374. static const int kx = 0;
  375. static const int ky = 1;
  376. static const int kz = 2;
  377. static const int kw = 3;
  378. struct ShadowMatrix {
  379. float m[3][3];
  380. };
  381. const ShadowMatrix* m = reinterpret_cast<const ShadowMatrix*>(&mat);
  382. Quaternion r;
  383. float *q = reinterpret_cast<float *>(&r);
  384. float trace = m->m[kx][kx] + m->m[ky][ky] + m->m[kz][kz] + 1;
  385. float four_d;
  386. int i,j,k;
  387. if (trace >= 1.0) // w >= 0.5
  388. {
  389. four_d = 2.0f*math::square_root(trace);
  390. q[kw] = -four_d / 4.0f;
  391. const float one_over_coeff = 1.0f / four_d;
  392. q[kx] = (m->m[kz][ky] - m->m[ky][kz])*one_over_coeff;
  393. q[ky] = (m->m[kx][kz] - m->m[kz][kx])*one_over_coeff;
  394. q[kz] = (m->m[ky][kx] - m->m[kx][ky])*one_over_coeff;
  395. }
  396. else
  397. {
  398. // Find the largest component
  399. if (m->m[kx][kx] > m->m[ky][ky])
  400. i = kx;
  401. else
  402. i = ky;
  403. if (m->m[kz][kz] > m->m[i][i])
  404. i = kz;
  405. // Set j and k to next two components
  406. j = (1 << i) & 3;
  407. k = (1 << j) & 3;
  408. four_d = 2.0f*math::square_root(m->m[i][i] - m->m[j][j] - m->m[k][k] + 1.0f );
  409. q[i] = four_d/4.0f;
  410. const float one_over_coeff = 1.0f / four_d;
  411. q[j] = (m->m[j][i] + m->m[i][j])*one_over_coeff;
  412. q[k] = (m->m[k][i] + m->m[i][k])*one_over_coeff;
  413. q[kw] = -(m->m[k][j] - m->m[j][k])*one_over_coeff;
  414. }
  415. return r;
  416. }
  417. inline Quaternion quaternion(const Vector3 &y, const Vector3 &z)
  418. {
  419. Vector3 x = cross(y,z);
  420. Matrix4x4 tm = matrix4x4_identity();
  421. x_axis(tm) = x;
  422. y_axis(tm) = y;
  423. z_axis(tm) = z;
  424. return quaternion_orthogonal(tm);
  425. }
  426. }