Transform.h 9.2 KB

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