Transform.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * A Transform_t class represents a spatial position and an
  3. * orientation.
  4. *
  5. */
  6. #ifndef GUL_MATH_Transform_t_H
  7. #define GUL_MATH_Transform_t_H
  8. #include <glm/glm.hpp>
  9. #include <glm/gtx/quaternion.hpp>
  10. #include <glm/gtx/matrix_decompose.hpp>
  11. namespace gul
  12. {
  13. /**
  14. * @brief The Transform_t struct
  15. *
  16. * The Transform_t class is similar to a Matrix Transform_t, but allows
  17. * you to provide the position,rotation and scaling factors instead
  18. * of setting up a full matrix.
  19. *
  20. */
  21. template<typename _T=float>
  22. struct Transform_t
  23. {
  24. using value_type = _T;
  25. using vec_type = glm::vec<3, value_type, glm::defaultp>;
  26. using quat_type = glm::qua<value_type, glm::defaultp>;
  27. using mat4_type = glm::mat<4, 4, value_type, glm::defaultp>;
  28. vec_type position;
  29. quat_type rotation;
  30. vec_type scale;
  31. explicit constexpr Transform_t() : position({0,0,0}),
  32. rotation({1.f,0.f,0.f,0.f}),
  33. scale({1,1,1})
  34. {
  35. }
  36. template<typename _t1>
  37. explicit constexpr Transform_t(glm::vec<3, _t1, glm::defaultp> const & _position) : position(_position),
  38. rotation({1.f,0.f,0.f,0.f}),
  39. scale({1,1,1})
  40. {
  41. }
  42. template<typename _t1>
  43. explicit constexpr Transform_t(glm::qua<_t1, glm::defaultp> const & _rotation) : position({0,0,0}),
  44. rotation(_rotation),
  45. scale({1,1,1})
  46. {
  47. }
  48. template<typename _t1>
  49. explicit constexpr Transform_t(glm::vec<3, _t1, glm::defaultp> const & _position,
  50. glm::qua<_t1, glm::defaultp> const & _rotation,
  51. glm::vec<3, _t1, glm::defaultp> const & _scale) : position(_position),
  52. rotation(_rotation),
  53. scale(_scale)
  54. {
  55. }
  56. template<typename _P>
  57. constexpr Transform_t(Transform_t<_P> const & P) : position(P.position),
  58. rotation(P.rotation),
  59. scale(P.scale)
  60. {
  61. }
  62. Transform_t(mat4_type const & M)
  63. {
  64. vec_type skew;
  65. typename mat4_type::col_type perspective;
  66. glm::decompose(M, scale, rotation, position, skew,perspective);
  67. }
  68. /**
  69. * @brief identity
  70. * @return
  71. *
  72. * Returns the identity Transform_t
  73. */
  74. static constexpr Transform_t identity()
  75. {
  76. return Transform_t();
  77. }
  78. /**
  79. * @brief translate
  80. * @param T
  81. * @return
  82. *
  83. * Translate the Transform_t by some vector
  84. */
  85. Transform_t& translate(vec_type const & T)
  86. {
  87. position += T;
  88. return *this;
  89. }
  90. /**
  91. * @brief translateLocal
  92. * @param direction
  93. * @return
  94. *
  95. * Translates the Transform_t based on the rotation of the
  96. * current Transform_t.
  97. */
  98. Transform_t& translateLocal(const vec_type & direction)
  99. {
  100. return translate( rotation * direction);
  101. }
  102. /**
  103. * @brief rotateGlobal
  104. * @param axis
  105. * @param AngleRadians
  106. * @return
  107. *
  108. * Rotate the Transform_t around a global axis by some angle
  109. */
  110. Transform_t& rotateGlobal(const vec_type & axis, value_type AngleRadians)
  111. {
  112. return rotateLocal(glm::conjugate(rotation) * axis, AngleRadians);
  113. return *this;
  114. }
  115. /**
  116. * @brief rotateLocal
  117. * @param axis
  118. * @param AngleRadians
  119. * @return
  120. *
  121. * Rotate the the Transform_t around a vector relative to
  122. * the local rotation of the Transform_t.
  123. */
  124. Transform_t& rotateLocal(const vec_type & axis, value_type AngleRadians)
  125. {
  126. rotation = glm::rotate( rotation, AngleRadians, axis );
  127. return *this;
  128. }
  129. /**
  130. * @brief setEuler
  131. * @param PitchYawRoll
  132. * @return
  133. *
  134. * Set the rotation using the euler angles
  135. */
  136. Transform_t& setEuler( const vec_type & PitchYawRoll )
  137. {
  138. rotation = quat_type(PitchYawRoll);
  139. return *this;
  140. }
  141. /**
  142. * @brief getMatrix
  143. * @return
  144. *
  145. * Returns the Transform_t as a Matrix
  146. */
  147. mat4_type getMatrix() const
  148. {
  149. #if 1
  150. auto M = mat4_cast(rotation);
  151. M[0] *= scale[0];
  152. M[1] *= scale[1];
  153. M[2] *= scale[2];
  154. M[3] = typename mat4_type::col_type(position,1.0f);
  155. return M;
  156. #else
  157. //return glm::translate(position) * mat4_type_cast(rotation) * glm::scale( mat4_type(1.0), scale);
  158. return glm::translate( mat4_type(1.0f), position) * mat4_type_cast(rotation) * glm::scale( mat4_type(1.0), scale);
  159. #endif
  160. }
  161. /**
  162. * @brief getViewMatrix
  163. * @return
  164. *
  165. * Returns the Transform_t as a view matrix. This is
  166. * used mostly for Computer Graphics, it is different
  167. * than getMatrix()
  168. *
  169. * The returned matrix is the camera matrix as if the
  170. * camera was looking down the +z axis of the Transform_t.
  171. */
  172. mat4_type getViewMatrix() const
  173. {
  174. return glm::lookAt( position, position + rotation * vec_type(0,0,1), rotation * vec_type(0,1,0) );
  175. }
  176. /**
  177. * @brief reverse
  178. * @return
  179. *
  180. * Returns the reverse quaternion of the Transform_t's rotation
  181. */
  182. quat_type reverse() const
  183. {
  184. return quat_type(rotation.w, -rotation.x, -rotation.y, -rotation.z);
  185. }
  186. /**
  187. * @brief lookat
  188. * @param at
  189. * @param up
  190. * @return
  191. *
  192. * Rotate the Transform_t so it looks at a particular point.
  193. */
  194. Transform_t& lookat( vec_type const & pointToLookAt, vec_type const & up)
  195. {
  196. #if 1
  197. rotation = glm::quatLookAt( glm::normalize(position-pointToLookAt) , up);
  198. #else
  199. vec_type z = -glm::normalize(position-pointToLookAt);
  200. vec_type x = glm::normalize(glm::cross(up,z));
  201. vec_type y = glm::cross(z,x);
  202. glm::mat3 R(x,y,z);
  203. rotation = quat_type_cast(R);
  204. #endif
  205. return *this;
  206. }
  207. // return the x/y/z axies of the Transform_t.
  208. // ie: the direction the local direction of the x-axis
  209. vec_type xAxis() const
  210. {
  211. return rotation * vec_type(1,0,0);
  212. }
  213. vec_type yAxis() const
  214. {
  215. return rotation * vec_type(0,1,0);
  216. }
  217. vec_type zAxis() const
  218. {
  219. return rotation * vec_type(0,0,1);
  220. }
  221. // returns various directions
  222. vec_type forward() const
  223. {
  224. return zAxis();
  225. }
  226. vec_type back() const
  227. {
  228. return -forward();
  229. }
  230. vec_type left() const
  231. {
  232. return xAxis();
  233. }
  234. vec_type right() const
  235. {
  236. return -left();
  237. }
  238. vec_type up() const
  239. {
  240. return yAxis();
  241. }
  242. vec_type down() const
  243. {
  244. return -up();
  245. }
  246. // A few constant Transform_ts which provide
  247. // rotations around paricular axes
  248. static constexpr Transform_t<value_type> R90x()
  249. {
  250. return Transform_t<value_type>( quat_type( { glm::half_pi<value_type>() ,0,0} ));
  251. }
  252. static constexpr Transform_t<value_type> R180x()
  253. {
  254. return Transform_t<value_type>( quat_type( { glm::pi<value_type>() ,0,0} ));
  255. }
  256. static constexpr Transform_t<value_type> R270x()
  257. {
  258. return Transform_t<value_type>( quat_type( { -glm::half_pi<value_type>() ,0,0} ));
  259. }
  260. static constexpr Transform_t<value_type> R90y()
  261. {
  262. return Transform_t<value_type>( quat_type( { 0,glm::half_pi<value_type>() ,0} ));
  263. }
  264. static constexpr Transform_t<value_type> R180y()
  265. {
  266. return Transform_t<value_type>( quat_type( { 0,glm::pi<value_type>() ,0} ));
  267. }
  268. static constexpr Transform_t<value_type> R270y()
  269. {
  270. return Transform_t<value_type>( quat_type( { 0,-glm::half_pi<value_type>() ,0} ));
  271. }
  272. static constexpr Transform_t<value_type> R90z()
  273. {
  274. return Transform_t<value_type>( quat_type( { 0,0,glm::half_pi<value_type>() } ));
  275. }
  276. static constexpr Transform_t<value_type> R180z()
  277. {
  278. return Transform_t<value_type>( quat_type( { 0,0,glm::pi<value_type>() } ));
  279. }
  280. static constexpr Transform_t<value_type> R270z()
  281. {
  282. return Transform_t( quat_type( { 0,0,-glm::half_pi<value_type>() } ));
  283. }
  284. };
  285. /**
  286. * @brief mix
  287. * @param L
  288. * @param R
  289. * @param t
  290. * @return
  291. *
  292. * performs the equivelant of glm::mix( ), smoothly interpolates
  293. * the Transform_t from L to R
  294. */
  295. template<typename T>
  296. inline Transform_t<T> mix( const Transform_t<T> & L, const Transform_t<T> & R, typename Transform_t<T>::value_type t)
  297. {
  298. return Transform_t<T>{
  299. glm::mix(L.position, R.position, t),
  300. glm::slerp(L.rotation, R.rotation, t),
  301. glm::mix(L.scale, R.scale,t)
  302. };
  303. }
  304. /**
  305. * @brief operator *
  306. * @param ps
  307. * @param ls
  308. * @return
  309. *
  310. * Transform a vector
  311. *
  312. * If you need to perform the same transformation on multiple vectors, it would be faster to
  313. * first get the matrix representation using getMatrix() then multiply the matrix by the vector.
  314. *
  315. */
  316. template<typename T>
  317. inline typename Transform_t<T>::vec_type operator * (const Transform_t<T> & ps, const typename Transform_t<T>::vec_type &ls)
  318. {
  319. return ps.position + glm::rotate(ps.rotation, ps.scale*ls);
  320. }
  321. template<typename T>
  322. inline Transform_t<T> operator * (const Transform_t<T> & ps, const Transform_t<T> & ls)
  323. {
  324. return
  325. Transform_t<T>(
  326. ps.position + ps.rotation * (ps.scale * ls.position),
  327. ps.rotation * ls.rotation,
  328. ps.scale * ls.scale
  329. );
  330. }
  331. template<typename T>
  332. inline Transform_t<T>& operator *= ( Transform_t<T> & ps, Transform_t<T> const & ls)
  333. {
  334. ps = ps * ls;
  335. return ps;
  336. }
  337. using Transform = Transform_t<float>;
  338. using fTransform = Transform_t<float>;
  339. using dTransform = Transform_t<double>;
  340. }
  341. #endif // Transform_t_H