Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

314 linhas
9.7 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://www.wtfpl.net/ for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <lol/main.h>
  14. namespace lol
  15. {
  16. static inline void MatrixToQuat(quat &that, mat3 const &m)
  17. {
  18. /* See http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/christian.htm for a version with no branches */
  19. float t = m[0][0] + m[1][1] + m[2][2];
  20. if (t > 0)
  21. {
  22. that.w = 0.5f * std::sqrt(1.0f + t);
  23. float s = 0.25f / that.w;
  24. that.x = s * (m[1][2] - m[2][1]);
  25. that.y = s * (m[2][0] - m[0][2]);
  26. that.z = s * (m[0][1] - m[1][0]);
  27. }
  28. else if (m[0][0] > m[1][1] && m[0][0] > m[2][2])
  29. {
  30. that.x = 0.5f * std::sqrt(1.0f + m[0][0] - m[1][1] - m[2][2]);
  31. float s = 0.25f / that.x;
  32. that.y = s * (m[0][1] + m[1][0]);
  33. that.z = s * (m[2][0] + m[0][2]);
  34. that.w = s * (m[1][2] - m[2][1]);
  35. }
  36. else if (m[1][1] > m[2][2])
  37. {
  38. that.y = 0.5f * std::sqrt(1.0f - m[0][0] + m[1][1] - m[2][2]);
  39. float s = 0.25f / that.y;
  40. that.x = s * (m[0][1] + m[1][0]);
  41. that.z = s * (m[1][2] + m[2][1]);
  42. that.w = s * (m[2][0] - m[0][2]);
  43. }
  44. else
  45. {
  46. that.z = 0.5f * std::sqrt(1.0f - m[0][0] - m[1][1] + m[2][2]);
  47. float s = 0.25f / that.z;
  48. that.x = s * (m[2][0] + m[0][2]);
  49. that.y = s * (m[1][2] + m[2][1]);
  50. that.w = s * (m[0][1] - m[1][0]);
  51. }
  52. }
  53. template<> quat::quat_t(mat3 const &m)
  54. {
  55. MatrixToQuat(*this, m);
  56. }
  57. template<> quat::quat_t(mat4 const &m)
  58. {
  59. MatrixToQuat(*this, mat3(m));
  60. }
  61. template<> quat quat::rotate(float degrees, vec3 const &v)
  62. {
  63. float half_angle = radians(degrees) * 0.5f;
  64. vec3 tmp = normalize(v) * sin(half_angle);
  65. return quat(cos(half_angle), tmp.x, tmp.y, tmp.z);
  66. }
  67. template<> quat quat::rotate(float degrees, float x, float y, float z)
  68. {
  69. return quat::rotate(degrees, vec3(x, y, z));
  70. }
  71. template<> quat quat::rotate(vec3 const &src, vec3 const &dst)
  72. {
  73. /* Algorithm directly taken from Sam Hocevar's article "Quaternion from
  74. * two vectors: the final version".
  75. * http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final */
  76. float magnitude = lol::sqrt(sqlength(src) * sqlength(dst));
  77. float real_part = magnitude + dot(src, dst);
  78. vec3 w;
  79. if (real_part < 1.e-6f * magnitude)
  80. {
  81. /* If src and dst are exactly opposite, rotate 180 degrees
  82. * around an arbitrary orthogonal axis. Axis normalisation
  83. * can happen later, when we normalise the quaternion. */
  84. real_part = 0.0f;
  85. w = abs(src.x) > abs(src.z) ? vec3(-src.y, src.x, 0.f)
  86. : vec3(0.f, -src.z, src.y);
  87. }
  88. else
  89. {
  90. /* Otherwise, build quaternion the standard way. */
  91. w = cross(src, dst);
  92. }
  93. return normalize(quat(real_part, w.x, w.y, w.z));
  94. }
  95. template<> quat slerp(quat const &qa, quat const &qb, float f)
  96. {
  97. float const magnitude = lol::sqrt(sqlength(qa) * sqlength(qb));
  98. float const product = lol::dot(qa, qb) / magnitude;
  99. /* If quaternions are equal or opposite, there is no need
  100. * to slerp anything, just return qa. */
  101. if (std::abs(product) >= 1.0f)
  102. return qa;
  103. float const sign = (product < 0.0f) ? -1.0f : 1.0f;
  104. float const theta = lol::acos(sign * product);
  105. float const s1 = lol::sin(sign * f * theta);
  106. float const s0 = lol::sin((1.0f - f) * theta);
  107. /* This is the same as 1/sin(theta) */
  108. float const d = 1.0f / lol::sqrt(1.f - product * product);
  109. return qa * (s0 * d) + qb * (s1 * d);
  110. }
  111. static inline vec3 quat_toeuler_generic(quat const &q, int i, int j, int k)
  112. {
  113. float n = norm(q);
  114. if (!n)
  115. return vec3::zero;
  116. /* (2 + i - j) % 3 means x-y-z direct order; otherwise indirect */
  117. float const sign = ((2 + i - j) % 3) ? 1.f : -1.f;
  118. vec3 ret;
  119. /* k == i means X-Y-X style Euler angles; otherwise we’re
  120. * actually handling X-Y-Z style Tait-Bryan angles. */
  121. if (k == i)
  122. {
  123. k = 3 - i - j;
  124. ret[0] = atan2(q[1 + i] * q[1 + j] + sign * (q.w * q[1 + k]),
  125. q.w * q[1 + j] - sign * (q[1 + i] * q[1 + k]));
  126. ret[1] = acos(2.f * (sq(q.w) + sq(q[1 + i])) - 1.f);
  127. ret[2] = atan2(q[1 + i] * q[1 + j] - sign * (q.w * q[1 + k]),
  128. q.w * q[1 + j] + sign * (q[1 + i] * q[1 + k]));
  129. }
  130. else
  131. {
  132. ret[0] = atan2(2.f * (q.w * q[1 + i] - sign * (q[1 + j] * q[1 + k])),
  133. 1.f - 2.f * (sq(q[1 + i]) + sq(q[1 + j])));
  134. ret[1] = asin(2.f * (q.w * q[1 + j] + sign * (q[1 + i] * q[1 + k])));
  135. ret[2] = atan2(2.f * (q.w * q[1 + k] - sign * (q[1 + j] * q[1 + i])),
  136. 1.f - 2.f * (sq(q[1 + k]) + sq(q[1 + j])));
  137. }
  138. return degrees(ret / n);
  139. }
  140. static inline mat3 mat3_fromeuler_generic(vec3 const &v, int i, int j, int k)
  141. {
  142. mat3 ret;
  143. vec3 const w = radians(v);
  144. float const s0 = sin(w[0]), c0 = cos(w[0]);
  145. float const s1 = sin(w[1]), c1 = cos(w[1]);
  146. float const s2 = sin(w[2]), c2 = cos(w[2]);
  147. /* (2 + i - j) % 3 means x-y-z direct order; otherwise indirect */
  148. float const sign = ((2 + i - j) % 3) ? 1.f : -1.f;
  149. /* k == i means X-Y-X style Euler angles; otherwise we’re
  150. * actually handling X-Y-Z style Tait-Bryan angles. */
  151. if (k == i)
  152. {
  153. k = 3 - i - j;
  154. ret[i][i] = c1;
  155. ret[i][j] = s0 * s1;
  156. ret[i][k] = - sign * (c0 * s1);
  157. ret[j][i] = s1 * s2;
  158. ret[j][j] = c0 * c2 - s0 * c1 * s2;
  159. ret[j][k] = sign * (s0 * c2 + c0 * c1 * s2);
  160. ret[k][i] = sign * (s1 * c2);
  161. ret[k][j] = - sign * (c0 * s2 + s0 * c1 * c2);
  162. ret[k][k] = - s0 * s2 + c0 * c1 * c2;
  163. }
  164. else
  165. {
  166. ret[i][i] = c1 * c2;
  167. ret[i][j] = sign * (c0 * s2) + s0 * s1 * c2;
  168. ret[i][k] = s0 * s2 - sign * (c0 * s1 * c2);
  169. ret[j][i] = - sign * (c1 * s2);
  170. ret[j][j] = c0 * c2 - sign * (s0 * s1 * s2);
  171. ret[j][k] = sign * (s0 * c2) + c0 * s1 * s2;
  172. ret[k][i] = sign * s1;
  173. ret[k][j] = - sign * (s0 * c1);
  174. ret[k][k] = c0 * c1;
  175. }
  176. return ret;
  177. }
  178. static inline quat quat_fromeuler_generic(vec3 const &v, int i, int j, int k)
  179. {
  180. vec3 const half_angles = radians(v * 0.5f);
  181. float const s0 = sin(half_angles[0]), c0 = cos(half_angles[0]);
  182. float const s1 = sin(half_angles[1]), c1 = cos(half_angles[1]);
  183. float const s2 = sin(half_angles[2]), c2 = cos(half_angles[2]);
  184. quat ret;
  185. /* (2 + i - j) % 3 means x-y-z direct order; otherwise indirect */
  186. float const sign = ((2 + i - j) % 3) ? 1.f : -1.f;
  187. /* k == i means X-Y-X style Euler angles; otherwise we’re
  188. * actually handling X-Y-Z style Tait-Bryan angles. */
  189. if (k == i)
  190. {
  191. k = 3 - i - j;
  192. ret[0] = c1 * (c0 * c2 - s0 * s2);
  193. ret[1 + i] = c1 * (c0 * s2 + s0 * c2);
  194. ret[1 + j] = s1 * (c0 * c2 + s0 * s2);
  195. ret[1 + k] = sign * (s1 * (s0 * c2 - c0 * s2));
  196. }
  197. else
  198. {
  199. ret[0] = c0 * c1 * c2 - sign * (s0 * s1 * s2);
  200. ret[1 + i] = s0 * c1 * c2 + sign * (c0 * s1 * s2);
  201. ret[1 + j] = c0 * s1 * c2 - sign * (s0 * c1 * s2);
  202. ret[1 + k] = c0 * c1 * s2 + sign * (s0 * s1 * c2);
  203. }
  204. return ret;
  205. }
  206. #define DEFINE_GENERIC_EULER_CONVERSIONS(a1, a2, a3) \
  207. DEFINE_GENERIC_EULER_CONVERSIONS_INNER(a1, a2, a3, a1##a2##a3) \
  208. #define DEFINE_GENERIC_EULER_CONVERSIONS_INNER(a1, a2, a3, name) \
  209. /* Create quaternions from Euler angles */ \
  210. template<> quat quat::fromeuler_##name(vec3 const &v) \
  211. { \
  212. int x = 0, y = 1, z = 2; UNUSED(x, y, z); \
  213. return quat_fromeuler_generic(v, a1, a2, a3); \
  214. } \
  215. \
  216. template<> quat quat::fromeuler_##name(float phi, float theta, float psi) \
  217. { \
  218. return quat::fromeuler_##name(vec3(phi, theta, psi)); \
  219. } \
  220. \
  221. /* Create 3×3 matrices from Euler angles */ \
  222. template<> mat3 mat3::fromeuler_##name(vec3 const &v) \
  223. { \
  224. int x = 0, y = 1, z = 2; UNUSED(x, y, z); \
  225. return mat3_fromeuler_generic(v, a1, a2, a3); \
  226. } \
  227. \
  228. template<> mat3 mat3::fromeuler_##name(float phi, float theta, float psi) \
  229. { \
  230. return mat3::fromeuler_##name(vec3(phi, theta, psi)); \
  231. } \
  232. \
  233. /* Create 4×4 matrices from Euler angles */ \
  234. template<> mat4 mat4::fromeuler_##name(vec3 const &v) \
  235. { \
  236. int x = 0, y = 1, z = 2; UNUSED(x, y, z); \
  237. return mat4(mat3_fromeuler_generic(v, a1, a2, a3), 1.f); \
  238. } \
  239. \
  240. template<> mat4 mat4::fromeuler_##name(float phi, float theta, float psi) \
  241. { \
  242. return mat4::fromeuler_##name(vec3(phi, theta, psi)); \
  243. } \
  244. \
  245. /* Retrieve Euler angles from a quaternion */ \
  246. template<> vec3 vec3::toeuler_##name(quat const &q) \
  247. { \
  248. int x = 0, y = 1, z = 2; UNUSED(x, y, z); \
  249. return quat_toeuler_generic(q, a1, a2, a3); \
  250. }
  251. DEFINE_GENERIC_EULER_CONVERSIONS(x, y, x)
  252. DEFINE_GENERIC_EULER_CONVERSIONS(x, z, x)
  253. DEFINE_GENERIC_EULER_CONVERSIONS(y, x, y)
  254. DEFINE_GENERIC_EULER_CONVERSIONS(y, z, y)
  255. DEFINE_GENERIC_EULER_CONVERSIONS(z, x, z)
  256. DEFINE_GENERIC_EULER_CONVERSIONS(z, y, z)
  257. DEFINE_GENERIC_EULER_CONVERSIONS(x, y, z)
  258. DEFINE_GENERIC_EULER_CONVERSIONS(x, z, y)
  259. DEFINE_GENERIC_EULER_CONVERSIONS(y, x, z)
  260. DEFINE_GENERIC_EULER_CONVERSIONS(y, z, x)
  261. DEFINE_GENERIC_EULER_CONVERSIONS(z, x, y)
  262. DEFINE_GENERIC_EULER_CONVERSIONS(z, y, x)
  263. #undef DEFINE_GENERIC_EULER_CONVERSIONS
  264. #undef DEFINE_GENERIC_EULER_CONVERSIONS_INNER
  265. } /* namespace lol */