quaternion.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. Quaternion qFromBasis(Vector3 bx, Vector3 by, Vector3 bz) {
  147. float w = sqrtf(1 + bx.x + by.y + bz.z) * .5f;
  148. float invw4 = 1.f / (4.0 * w);
  149. Quaternion q = (Quaternion){
  150. .real = w,
  151. .i = (by.z - bz.y) * invw4,
  152. .j = (bz.x - bx.z) * invw4,
  153. .k = (bx.y - by.x) * invw4,
  154. };
  155. return q;
  156. }
  157. // Applies the full conjugate multiplication qvq*
  158. void qNonUnitToMatrix(Quaternion q, Matrix* out) {
  159. float s2 = q.real * q.real;
  160. float x2 = q.i * q.i;
  161. float y2 = q.j * q.j;
  162. float z2 = q.k * q.k;
  163. float sx = 2.0 * q.real * q.i;
  164. float sy = 2.0 * q.real * q.j;
  165. float sz = 2.0 * q.real * q.k;
  166. float xy = 2.0 * q.i * q.j;
  167. float xz = 2.0 * q.i * q.k;
  168. float yz = 2.0 * q.j * q.k;
  169. out->m[0] = s2 + x2 - y2 - z2;
  170. out->m[1] = xy + sz;
  171. out->m[2] = xz - sy;
  172. out->m[3] = 0;
  173. out->m[4] = xy - sz;
  174. out->m[5] = s2 - x2 + y2 - z2;
  175. out->m[6] = yz + sx;
  176. out->m[7] = 0;
  177. out->m[8] = xz + sy;
  178. out->m[9] = yz - sx;
  179. out->m[10] = s2 - x2 - y2 + z2;
  180. out->m[11] = 0;
  181. out->m[12] = 0;
  182. out->m[13] = 0;
  183. out->m[14] = 0;
  184. out->m[15] = 1;
  185. }
  186. void qUnitToMatrix(Quaternion q, Matrix* out) {
  187. float x2 = q.i + q.i;
  188. float y2 = q.j + q.j;
  189. float z2 = q.k + q.k;
  190. float xx = q.i * x2;
  191. float yy = q.j * y2;
  192. float zz = q.k * z2;
  193. float sx = q.real * x2;
  194. float sy = q.real * y2;
  195. float sz = q.real * z2;
  196. float yx = q.j * x2;
  197. float zx = q.k * x2;
  198. float zy = q.k * y2;
  199. out->m[0] = 1.0f - yy - zz;
  200. out->m[1] = yx + sz;
  201. out->m[2] = zx - sy;
  202. out->m[3] = 0;
  203. out->m[4] = yx - sz;
  204. out->m[5] = 1.0f - xx - zz;
  205. out->m[6] = zy + sx;
  206. out->m[7] = 0;
  207. out->m[8] = zx + sy;
  208. out->m[9] = zy - sx;
  209. out->m[10] = 1.0f - xx - yy;
  210. out->m[11] = 0;
  211. out->m[12] = 0;
  212. out->m[13] = 0;
  213. out->m[14] = 0;
  214. out->m[15] = 1.0f;
  215. }
  216. void qUnitToMatrix3(Quaternion q, Matrix3* out) {
  217. float x2 = 2.0 * q.i * q.i;
  218. float y2 = 2.0 * q.j * q.j;
  219. float z2 = 2.0 * q.k * q.k;
  220. float sx = 2.0 * q.real * q.i;
  221. float sy = 2.0 * q.real * q.j;
  222. float sz = 2.0 * q.real * q.k;
  223. float xy = 2.0 * q.i * q.j;
  224. float xz = 2.0 * q.i * q.k;
  225. float yz = 2.0 * q.j * q.k;
  226. out->m[0] = 1.0 - y2 - z2;
  227. out->m[1] = xy + sz;
  228. out->m[2] = xz - sy;
  229. out->m[3] = xy - sz;
  230. out->m[4] = 1.0 - x2 - z2;
  231. out->m[5] = yz + sx;
  232. out->m[6] = xz + sy;
  233. out->m[7] = yz - sx;
  234. out->m[8] = 1.0 - x2 - y2;
  235. }