Transform.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Math/Common.h>
  7. namespace anki {
  8. /// @addtogroup math
  9. /// @{
  10. /// Transformation
  11. template<typename T>
  12. class TTransform
  13. {
  14. public:
  15. /// @name Constructors
  16. /// @{
  17. constexpr TTransform()
  18. : m_origin(T(0))
  19. , m_rotation(TMat<T, 3, 4>::getIdentity())
  20. , m_scale(T(1), T(1), T(1), T(0))
  21. {
  22. }
  23. TTransform(const TTransform& b)
  24. : m_origin(b.m_origin)
  25. , m_rotation(b.m_rotation)
  26. , m_scale(b.m_scale)
  27. {
  28. check();
  29. }
  30. explicit TTransform(const TMat<T, 4, 4>& m4)
  31. {
  32. const TVec<T, 3> s0 = m4.getColumn(0).xyz();
  33. const TVec<T, 3> s1 = m4.getColumn(1).xyz();
  34. const TVec<T, 3> s2 = m4.getColumn(2).xyz();
  35. m_scale = TVec<T, 4>(s0.length(), s1.length(), s2.length(), T(0));
  36. m_rotation.setColumns(s0 / m_scale.x(), s1 / m_scale.x(), s2 / m_scale.x(), TVec<T, 3>(T(0)));
  37. m_origin = m4.getTranslationPart().xyz0();
  38. check();
  39. }
  40. TTransform(const TVec<T, 4>& origin, const TMat<T, 3, 4>& rotation, const TVec<T, 4>& scale)
  41. : m_origin(origin)
  42. , m_rotation(rotation)
  43. , m_scale(scale)
  44. {
  45. check();
  46. }
  47. TTransform(const TVec<T, 3>& origin, const TMat<T, 3, 3>& rotation, const TVec<T, 3>& scale)
  48. : TTransform(origin.xyz0(), TMat<T, 3, 4>(TVec<T, 3>(T(0)), rotation), scale.xyz0())
  49. {
  50. check();
  51. }
  52. /// @}
  53. /// @name Accessors
  54. /// @{
  55. [[nodiscard]] const TVec<T, 4>& getOrigin() const
  56. {
  57. return m_origin;
  58. }
  59. void setOrigin(const TVec<T, 4>& o)
  60. {
  61. m_origin = o;
  62. check();
  63. }
  64. void setOrigin(const TVec<T, 3>& o)
  65. {
  66. m_origin = o.xyz0();
  67. }
  68. [[nodiscard]] const TMat<T, 3, 4>& getRotation() const
  69. {
  70. return m_rotation;
  71. }
  72. void setRotation(const TMat<T, 3, 4>& r)
  73. {
  74. m_rotation = r;
  75. }
  76. void setRotation(const TMat<T, 3, 3>& r)
  77. {
  78. m_rotation.setRotationPart(r);
  79. m_rotation.setTranslationPart(TVec<T, 3>(T(0)));
  80. }
  81. [[nodiscard]] const TVec<T, 4>& getScale() const
  82. {
  83. return m_scale;
  84. }
  85. void setScale(const TVec<T, 4>& s)
  86. {
  87. m_scale = s;
  88. check();
  89. }
  90. void setScale(const TVec<T, 3>& s)
  91. {
  92. m_scale = s.xyz0();
  93. check();
  94. }
  95. /// @}
  96. /// @name Operators with same type
  97. /// @{
  98. TTransform& operator=(const TTransform& b)
  99. {
  100. m_origin = b.m_origin;
  101. m_rotation = b.m_rotation;
  102. m_scale = b.m_scale;
  103. check();
  104. return *this;
  105. }
  106. Bool operator==(const TTransform& b) const
  107. {
  108. return m_origin == b.m_origin && m_rotation == b.m_rotation && m_scale == b.m_scale;
  109. }
  110. Bool operator!=(const TTransform& b) const
  111. {
  112. return !operator==(b);
  113. }
  114. /// @}
  115. /// @name Other
  116. /// @{
  117. void setIdentity()
  118. {
  119. (*this) = getIdentity();
  120. }
  121. [[nodiscard]] static TTransform getIdentity()
  122. {
  123. return TTransform();
  124. }
  125. /// @copybrief combineTTransformations
  126. [[nodiscard]] TTransform combineTransformations(const TTransform& b) const
  127. {
  128. check();
  129. const TTransform& a = *this;
  130. TTransform out;
  131. out.m_origin = TVec<T, 4>(a.m_rotation * (b.m_origin * a.m_scale), T(0)) + a.m_origin;
  132. out.m_rotation = a.m_rotation.combineTransformations(b.m_rotation);
  133. out.m_scale = a.m_scale * b.m_scale;
  134. return out;
  135. }
  136. /// Get the inverse transformation. Its faster that inverting a Mat4
  137. [[nodiscard]] TTransform invert() const
  138. {
  139. TTransform o;
  140. o.m_rotation = m_rotation;
  141. o.m_rotation.transposeRotationPart();
  142. o.m_scale = TVec<T, 4>(T(1), T(1), T(1), T(0)) / m_scale.xyz1();
  143. o.m_origin = -(o.m_rotation * (o.m_scale * m_origin)).xyz0();
  144. o.check();
  145. return o;
  146. }
  147. /// Transform a TVec3
  148. [[nodiscard]] TVec<T, 3> transform(const TVec<T, 3>& b) const
  149. {
  150. check();
  151. return (m_rotation.getRotationPart() * (b * m_scale.xyz())) + m_origin.xyz();
  152. }
  153. /// Transform a TVec4. SIMD optimized
  154. [[nodiscard]] TVec<T, 4> transform(const TVec<T, 4>& b) const
  155. {
  156. check();
  157. TVec<T, 4> out = TVec<T, 4>(m_rotation * (b * m_scale), T(0)) + m_origin;
  158. return out;
  159. }
  160. template<U kVecComponentCount>
  161. [[nodiscard]] TTransform lookAt(const TVec<T, kVecComponentCount>& refPoint, const TVec<T, kVecComponentCount>& up) const
  162. {
  163. const TVec<T, 4> j = up.xyz0();
  164. const TVec<T, 4> vdir = (refPoint.xyz0() - m_origin).normalize();
  165. const TVec<T, 4> vup = (j - vdir * j.dot(vdir)).normalize();
  166. const TVec<T, 4> vside = vdir.cross(vup);
  167. TTransform out;
  168. out.m_origin = m_origin;
  169. out.m_scale = m_scale;
  170. out.m_rotation.setColumns(vside.xyz(), vup.xyz(), (-vdir).xyz());
  171. return out;
  172. }
  173. [[nodiscard]] String toString() const requires(std::is_floating_point<T>::value)
  174. {
  175. String str;
  176. String b = String("origin: ") + m_origin.toString();
  177. str += b;
  178. str += "\nrotation:\n";
  179. b = m_rotation.toString();
  180. str += b;
  181. str += "\n";
  182. b = String().sprintf("scale: %f %f %f", m_scale.x(), m_scale.y(), m_scale.z());
  183. str += b;
  184. return str;
  185. }
  186. [[nodiscard]] Bool hasUniformScale() const
  187. {
  188. return m_scale.x() == m_scale.y() && m_scale.x() == m_scale.z();
  189. }
  190. /// @}
  191. private:
  192. /// @name Data
  193. /// @{
  194. TVec<T, 4> m_origin; ///< The rotation
  195. TMat<T, 3, 4> m_rotation; ///< The translation
  196. TVec<T, 4> m_scale; ///< The scaling
  197. /// @}
  198. void check() const
  199. {
  200. ANKI_ASSERT(m_origin.w() == T(0));
  201. using TT = TVec<T, 3>;
  202. [[maybe_unused]] TT t; // Shut up the compiler regarding TT
  203. ANKI_ASSERT(m_scale.w() == T(0) && m_scale.xyz() > TT(T(0)));
  204. }
  205. };
  206. /// F32 transformation
  207. using Transform = TTransform<F32>;
  208. /// F64 transformation
  209. using DTransform = TTransform<F64>;
  210. /// @}
  211. } // end namespace anki