quaternion.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. Quaternion qAdd(Quaternion l, Quaternion r) {
  2. return vAdd4(l, r);
  3. }
  4. Quaternion qSub(Quaternion l, Quaternion r) {
  5. return vSub4(l, r);
  6. }
  7. Quaternion qScale(Quaternion q, float s) {
  8. return (Quaternion){.i = q.i*s, .j = q.j*s, .k = q.k*s, .real = q.real*s };
  9. }
  10. Quaternion qMul(Quaternion l, Quaternion r) {
  11. return (Quaternion){
  12. .i = r.real*l.i + r.i*l.real + l.j*r.k - l.k*r.j,
  13. .j = l.real*r.j - l.i*r.k + l.j*r.real + l.k*r.i,
  14. .k = l.real*r.k + l.i*r.j - l.j*r.i + l.k*r.real,
  15. .real = l.real*r.real - l.i*r.i - l.j*r.j - l.k*r.k
  16. };
  17. }
  18. Quaternion qDiv(Quaternion n, Quaternion d) {
  19. float m = vDot4(d, d);
  20. return (Quaternion){
  21. .i = (d.real*n.i - d.i*n.real - d.k*n.k + d.k*n.j ) / m,
  22. .j = (d.real*n.j + d.i*n.k - d.k*n.real - d.k*n.i ) / m,
  23. .k = (d.real*n.k - d.i*n.j - d.k*n.i - d.k*n.real) / m,
  24. .real = (n.real*d.real + n.i*d.i + n.j*d.j + n.k*d.k) / m
  25. };
  26. }
  27. // rotate one quaternion by another
  28. // aka "conjugation"
  29. Quaternion qRot(Quaternion l, Quaternion r) {
  30. return qMul(qConj(l), qMul(r, l));
  31. }
  32. Vector3 qRot3(Vector3 a, Quaternion r) {
  33. Vector4 a4 = {a.x, a.y, a.z, 0.0};
  34. a4 = qMul(qMul(r, a4), qConj(r));
  35. return (Vector3){a4.x, a4.y, a4.z};
  36. }
  37. /*
  38. Quaternion qConjugation(Quaternion a, Quaternion r) {
  39. return qMul(qMul(r, a), qInv(r));
  40. }
  41. */
  42. // create a quaternion representing a rotation of theta around vector r
  43. Quaternion qFromRTheta(Vector3 r, float theta) {
  44. float tm2p = fmod(fmod(theta, F_2PI) + F_2PI, F_2PI);
  45. if(tm2p < 0.0001 || tm2p > 6.2831) {
  46. return (Quaternion){
  47. .real = 1,
  48. .i = 0,
  49. .j = 0,
  50. .k = 0
  51. };
  52. }
  53. float t_2 = tm2p / 2.0f;
  54. float st_2, ct_2;
  55. sincosf(t_2, &st_2, &ct_2);
  56. return (Quaternion){
  57. .real = ct_2,
  58. .i = st_2 * r.x,
  59. .j = st_2 * r.y,
  60. .k = st_2 * r.z
  61. };
  62. }
  63. // transform a quaternion back into axis-angle representation
  64. // the axis may not be numerically stable if the rotation represented by the quaternion is very small
  65. // this is an inherent property of quaterions, not a deficiency in the function below
  66. void qToRTheta(Quaternion q, Vector3* r, float* theta) {
  67. // float l2 = q.x * q.x + q.y * q.y + q.z * q.z;
  68. float l = sqrtf(1.f - (q.w * q.w));
  69. *theta = 2.f * acos(q.w); // original algorithm from the internet
  70. if(fabs(l) > 0.0001) {
  71. // *theta = -2.f * acos(q.w); // algorithm that works; maybe left-handed vs right-handed?
  72. r->x = q.x / l;
  73. r->y = q.y / l;
  74. r->z = q.z / l;
  75. }
  76. else {
  77. // *theta = 0;
  78. r->x = q.x;
  79. r->y = q.y;
  80. r->z = q.z;
  81. }
  82. }
  83. // conjugate
  84. Quaternion qConj(Quaternion q) {
  85. return (Quaternion){
  86. .i = -q.i,
  87. .j = -q.j,
  88. .k = -q.k,
  89. .real = q.real
  90. };
  91. }
  92. // inverse
  93. Quaternion qInv(Quaternion q) {
  94. float m = vDot4(q, q);
  95. return (Quaternion){
  96. .i = -q.i / m,
  97. .j = -q.j / m,
  98. .k = -q.k / m,
  99. .real = q.real / m
  100. };
  101. }
  102. Quaternion qUnit(Quaternion q) {
  103. return vNorm4(q);
  104. }
  105. // aliases of the same thing for conceptual convenience
  106. float qMod(Quaternion q) {
  107. return vMag4(q);
  108. }
  109. float qMag(Quaternion q) {
  110. return vMag4(q);
  111. }
  112. float qLen(Quaternion q) {
  113. return vMag4(q);
  114. }
  115. Quaternion qNorm(Quaternion q) {
  116. return vNorm4(q);
  117. }
  118. Quaternion qSlerp(Quaternion a, Quaternion b, float t) {
  119. float d = vDot4(a, b);
  120. if(d >= 1.0) return a;
  121. if (d < 0.0f) { // reverse direction for the shorter way
  122. d = -d;
  123. b.x = -b.x;
  124. b.y = -b.y;
  125. b.z = -b.z;
  126. b.w = -b.w;
  127. }
  128. float th = acosf(d);
  129. float inv_s_th = 1.0 / sinf(th);
  130. float ca = sin((1.0 - t) * th) * inv_s_th;
  131. float cb = sin(t * th) * inv_s_th;
  132. return (Quaternion){
  133. .x = a.x * ca + b.x * cb,
  134. .y = a.y * ca + b.y * cb,
  135. .z = a.z * ca + b.z * cb,
  136. .w = a.w * ca + b.w * cb,
  137. };
  138. }
  139. Quaternion qNlerp(Quaternion a, Quaternion b, float t) {
  140. return qNorm(vLerp4(a, b, t));
  141. }
  142. float qAngleBetween(Quaternion a, Quaternion b) {
  143. float g = vDot4(a, b);
  144. return acos(2.f * g * g - 1.f);
  145. }
  146. // WARNING: these vectors cannot represent a reflection about any axis.
  147. // det(M4(bx,by,bz)) cannot equal -1, even if the vectors are all orthogonal.
  148. // Very few places on the internet talk about this, and never with sufficient
  149. // emphasis, espectially not SO. The matrix formed by the vectors must be
  150. // "special orthogonal", not simply orthogonal to each other.
  151. //
  152. // If your quaternions are coming out invalid, especially after some cross
  153. // products or 90-degree rotations through swapping, try inverting one axis.
  154. //
  155. Quaternion qFromBasis(Vector3 bx, Vector3 by, Vector3 bz) {
  156. Quaternion q;
  157. float trace = bx.x + by.y + bz.z;
  158. if(trace > 0) {
  159. float s = sqrtf(trace + 1.f) * 2.f;
  160. float invs = 1.f / s;
  161. q.w = 0.25f * s;
  162. q.x = (by.z - bz.y) * invs;
  163. q.y = (bz.x - bx.z) * invs;
  164. q.z = (bx.y - by.x) * invs;
  165. } else if((bx.x > by.y) && (bx.x > bz.z)) {
  166. float s = sqrtf(1.0f + bx.x - by.y - bz.z) * 2.f;
  167. float invs = 1.f / s;
  168. q.w = (by.z - bz.y) * invs;
  169. q.x = 0.25f * s;
  170. q.y = (by.x + bx.y) * invs;
  171. q.z = (bz.x + bx.z) * invs;
  172. } else if(by.y > bz.z) {
  173. float s = sqrtf(1.0f + by.y - bx.x - bz.z) * 2.f;
  174. float invs = 1.f / s;
  175. q.w = (bz.x - bx.z) * invs;
  176. q.x = (by.x + bx.y) * invs;
  177. q.y = 0.25f * s;
  178. q.z = (bz.y + by.z) * invs;
  179. } else {
  180. float s = sqrtf(1.0f + bz.z - bx.x - by.y) * 2.f;
  181. float invs = 1.f / s;
  182. q.w = (bx.y - by.x) * invs;
  183. q.x = (bz.x + bx.z) * invs;
  184. q.y = (bz.y + by.z) * invs;
  185. q.z = 0.25f * s;
  186. }
  187. return q;
  188. }
  189. // Applies the full conjugate multiplication qvq*
  190. void qNonUnitToMatrix(Quaternion q, Matrix* out) {
  191. float s2 = q.real * q.real;
  192. float x2 = q.i * q.i;
  193. float y2 = q.j * q.j;
  194. float z2 = q.k * q.k;
  195. float sx = 2.0 * q.real * q.i;
  196. float sy = 2.0 * q.real * q.j;
  197. float sz = 2.0 * q.real * q.k;
  198. float xy = 2.0 * q.i * q.j;
  199. float xz = 2.0 * q.i * q.k;
  200. float yz = 2.0 * q.j * q.k;
  201. out->m[0] = s2 + x2 - y2 - z2;
  202. out->m[1] = xy + sz;
  203. out->m[2] = xz - sy;
  204. out->m[3] = 0;
  205. out->m[4] = xy - sz;
  206. out->m[5] = s2 - x2 + y2 - z2;
  207. out->m[6] = yz + sx;
  208. out->m[7] = 0;
  209. out->m[8] = xz + sy;
  210. out->m[9] = yz - sx;
  211. out->m[10] = s2 - x2 - y2 + z2;
  212. out->m[11] = 0;
  213. out->m[12] = 0;
  214. out->m[13] = 0;
  215. out->m[14] = 0;
  216. out->m[15] = 1;
  217. }
  218. void qUnitToMatrix(Quaternion q, Matrix* out) {
  219. float x2 = q.i + q.i;
  220. float y2 = q.j + q.j;
  221. float z2 = q.k + q.k;
  222. float xx = q.i * x2;
  223. float yy = q.j * y2;
  224. float zz = q.k * z2;
  225. float sx = q.real * x2;
  226. float sy = q.real * y2;
  227. float sz = q.real * z2;
  228. float yx = q.j * x2;
  229. float zx = q.k * x2;
  230. float zy = q.k * y2;
  231. out->m[0] = 1.0f - yy - zz;
  232. out->m[1] = yx + sz;
  233. out->m[2] = zx - sy;
  234. out->m[3] = 0;
  235. out->m[4] = yx - sz;
  236. out->m[5] = 1.0f - xx - zz;
  237. out->m[6] = zy + sx;
  238. out->m[7] = 0;
  239. out->m[8] = zx + sy;
  240. out->m[9] = zy - sx;
  241. out->m[10] = 1.0f - xx - yy;
  242. out->m[11] = 0;
  243. out->m[12] = 0;
  244. out->m[13] = 0;
  245. out->m[14] = 0;
  246. out->m[15] = 1.0f;
  247. }
  248. void qUnitToMatrix3(Quaternion q, Matrix3* out) {
  249. float x2 = 2.0 * q.i * q.i;
  250. float y2 = 2.0 * q.j * q.j;
  251. float z2 = 2.0 * q.k * q.k;
  252. float sx = 2.0 * q.real * q.i;
  253. float sy = 2.0 * q.real * q.j;
  254. float sz = 2.0 * q.real * q.k;
  255. float xy = 2.0 * q.i * q.j;
  256. float xz = 2.0 * q.i * q.k;
  257. float yz = 2.0 * q.j * q.k;
  258. out->m[0] = 1.0 - y2 - z2;
  259. out->m[1] = xy + sz;
  260. out->m[2] = xz - sy;
  261. out->m[3] = xy - sz;
  262. out->m[4] = 1.0 - x2 - z2;
  263. out->m[5] = yz + sx;
  264. out->m[6] = xz + sy;
  265. out->m[7] = yz - sx;
  266. out->m[8] = 1.0 - x2 - y2;
  267. }