2
0

Quat.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Math/Vec3.h>
  6. #include <Jolt/Math/Vec4.h>
  7. JPH_NAMESPACE_BEGIN
  8. /// Quaternion class, quaternions are 4 dimensional vectors which can describe rotations in 3 dimensional
  9. /// space if their length is 1.
  10. ///
  11. /// They are written as:
  12. ///
  13. /// \f$q = w + x \: i + y \: j + z \: k\f$
  14. ///
  15. /// or in vector notation:
  16. ///
  17. /// \f$q = [w, v] = [w, x, y, z]\f$
  18. ///
  19. /// Where:
  20. ///
  21. /// w = the real part
  22. /// v = the imaginary part, (x, y, z)
  23. ///
  24. /// Note that we store the quaternion in a Vec4 as [x, y, z, w] because that makes
  25. /// it easy to extract the rotation axis of the quaternion:
  26. ///
  27. /// q = [cos(angle / 2), sin(angle / 2) * rotation_axis]
  28. class [[nodiscard]] alignas(JPH_VECTOR_ALIGNMENT) Quat
  29. {
  30. public:
  31. JPH_OVERRIDE_NEW_DELETE
  32. ///@name Constructors
  33. ///@{
  34. inline Quat() = default; ///< Intentionally not initialized for performance reasons
  35. Quat(const Quat &inRHS) = default;
  36. Quat & operator = (const Quat &inRHS) = default;
  37. inline Quat(float inX, float inY, float inZ, float inW) : mValue(inX, inY, inZ, inW) { }
  38. inline explicit Quat(const Float4 &inV) : mValue(Vec4::sLoadFloat4(&inV)) { }
  39. inline explicit Quat(Vec4Arg inV) : mValue(inV) { }
  40. ///@}
  41. ///@name Tests
  42. ///@{
  43. /// Check if two quaternions are exactly equal
  44. inline bool operator == (QuatArg inRHS) const { return mValue == inRHS.mValue; }
  45. /// Check if two quaternions are different
  46. inline bool operator != (QuatArg inRHS) const { return mValue != inRHS.mValue; }
  47. /// If this quaternion is close to inRHS. Note that q and -q represent the same rotation, this is not checked here.
  48. inline bool IsClose(QuatArg inRHS, float inMaxDistSq = 1.0e-12f) const { return mValue.IsClose(inRHS.mValue, inMaxDistSq); }
  49. /// If the length of this quaternion is 1 +/- inTolerance
  50. inline bool IsNormalized(float inTolerance = 1.0e-5f) const { return mValue.IsNormalized(inTolerance); }
  51. /// If any component of this quaternion is a NaN (not a number)
  52. inline bool IsNaN() const { return mValue.IsNaN(); }
  53. ///@}
  54. ///@name Get components
  55. ///@{
  56. /// Get X component (imaginary part i)
  57. JPH_INLINE float GetX() const { return mValue.GetX(); }
  58. /// Get Y component (imaginary part j)
  59. JPH_INLINE float GetY() const { return mValue.GetY(); }
  60. /// Get Z component (imaginary part k)
  61. JPH_INLINE float GetZ() const { return mValue.GetZ(); }
  62. /// Get W component (real part)
  63. JPH_INLINE float GetW() const { return mValue.GetW(); }
  64. /// Get the imaginary part of the quaternion
  65. JPH_INLINE Vec3 GetXYZ() const { return Vec3(mValue); }
  66. /// Get the quaternion as a Vec4
  67. JPH_INLINE Vec4 GetXYZW() const { return mValue; }
  68. /// Set individual components
  69. JPH_INLINE void SetX(float inX) { mValue.SetX(inX); }
  70. JPH_INLINE void SetY(float inY) { mValue.SetY(inY); }
  71. JPH_INLINE void SetZ(float inZ) { mValue.SetZ(inZ); }
  72. JPH_INLINE void SetW(float inW) { mValue.SetW(inW); }
  73. /// Set all components
  74. JPH_INLINE void Set(float inX, float inY, float inZ, float inW) { mValue.Set(inX, inY, inZ, inW); }
  75. ///@}
  76. ///@name Default quaternions
  77. ///@{
  78. /// @return [0, 0, 0, 0]
  79. JPH_INLINE static Quat sZero() { return Quat(Vec4::sZero()); }
  80. /// @return [1, 0, 0, 0] (or in storage format Quat(0, 0, 0, 1))
  81. JPH_INLINE static Quat sIdentity() { return Quat(0, 0, 0, 1); }
  82. ///@}
  83. /// Rotation from axis and angle
  84. JPH_INLINE static Quat sRotation(Vec3Arg inAxis, float inAngle);
  85. /// Get axis and angle that represents this quaternion, outAngle will always be in the range \f$[0, \pi]\f$
  86. JPH_INLINE void GetAxisAngle(Vec3 &outAxis, float &outAngle) const;
  87. /// Create quaternion that rotates a vector from the direction of inFrom to the direction of inTo along the shortest path
  88. /// @see https://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
  89. JPH_INLINE static Quat sFromTo(Vec3Arg inFrom, Vec3Arg inTo);
  90. /// Random unit quaternion
  91. template <class Random>
  92. inline static Quat sRandom(Random &inRandom);
  93. /// Conversion from Euler angles. Rotation order is X then Y then Z (RotZ * RotY * RotX). Angles in radians.
  94. inline static Quat sEulerAngles(Vec3Arg inAngles);
  95. /// Conversion to Euler angles. Rotation order is X then Y then Z (RotZ * RotY * RotX). Angles in radians.
  96. inline Vec3 GetEulerAngles() const;
  97. ///@name Length / normalization operations
  98. ///@{
  99. /// Squared length of quaternion.
  100. /// @return Squared length of quaternion (\f$|v|^2\f$)
  101. JPH_INLINE float LengthSq() const { return mValue.LengthSq(); }
  102. /// Length of quaternion.
  103. /// @return Length of quaternion (\f$|v|\f$)
  104. JPH_INLINE float Length() const { return mValue.Length(); }
  105. /// Normalize the quaternion (make it length 1)
  106. JPH_INLINE Quat Normalized() const { return Quat(mValue.Normalized()); }
  107. ///@}
  108. ///@name Additions / multiplications
  109. ///@{
  110. JPH_INLINE void operator += (QuatArg inRHS) { mValue += inRHS.mValue; }
  111. JPH_INLINE void operator -= (QuatArg inRHS) { mValue -= inRHS.mValue; }
  112. JPH_INLINE void operator *= (float inValue) { mValue *= inValue; }
  113. JPH_INLINE void operator /= (float inValue) { mValue /= inValue; }
  114. JPH_INLINE Quat operator - () const { return Quat(-mValue); }
  115. JPH_INLINE Quat operator + (QuatArg inRHS) const { return Quat(mValue + inRHS.mValue); }
  116. JPH_INLINE Quat operator - (QuatArg inRHS) const { return Quat(mValue - inRHS.mValue); }
  117. JPH_INLINE Quat operator * (QuatArg inRHS) const;
  118. JPH_INLINE Quat operator * (float inValue) const { return Quat(mValue * inValue); }
  119. inline friend Quat operator * (float inValue, QuatArg inRHS) { return Quat(inRHS.mValue * inValue); }
  120. JPH_INLINE Quat operator / (float inValue) const { return Quat(mValue / inValue); }
  121. ///@}
  122. /// Rotate a vector by this quaternion
  123. JPH_INLINE Vec3 operator * (Vec3Arg inValue) const;
  124. /// Multiply a quaternion with imaginary components and no real component (x, y, z, 0) with a quaternion
  125. static JPH_INLINE Quat sMultiplyImaginary(Vec3Arg inLHS, QuatArg inRHS);
  126. /// Rotate a vector by the inverse of this quaternion
  127. JPH_INLINE Vec3 InverseRotate(Vec3Arg inValue) const;
  128. /// Rotate a the vector (1, 0, 0) with this quaternion
  129. JPH_INLINE Vec3 RotateAxisX() const;
  130. /// Rotate a the vector (0, 1, 0) with this quaternion
  131. JPH_INLINE Vec3 RotateAxisY() const;
  132. /// Rotate a the vector (0, 0, 1) with this quaternion
  133. JPH_INLINE Vec3 RotateAxisZ() const;
  134. /// Dot product
  135. JPH_INLINE float Dot(QuatArg inRHS) const { return mValue.Dot(inRHS.mValue); }
  136. /// The conjugate [w, -x, -y, -z] is the same as the inverse for unit quaternions
  137. JPH_INLINE Quat Conjugated() const { return Quat(mValue.FlipSign<-1, -1, -1, 1>()); }
  138. /// Get inverse quaternion
  139. JPH_INLINE Quat Inversed() const { return Conjugated() / Length(); }
  140. /// Ensures that the W component is positive by negating the entire quaternion if it is not. This is useful when you want to store a quaternion as a 3 vector by discarding W and reconstructing it as sqrt(1 - x^2 - y^2 - z^2).
  141. JPH_INLINE Quat EnsureWPositive() const { return Quat(Vec4::sXor(mValue, Vec4::sAnd(mValue.SplatW(), UVec4::sReplicate(0x80000000).ReinterpretAsFloat()))); }
  142. /// Get a quaternion that is perpendicular to this quaternion
  143. JPH_INLINE Quat GetPerpendicular() const { return Quat(mValue.Swizzle<SWIZZLE_Y, SWIZZLE_X, SWIZZLE_W, SWIZZLE_Z>().FlipSign<1, -1, 1, -1>()); }
  144. /// Get rotation angle around inAxis (uses Swing Twist Decomposition to get the twist quaternion and uses q(axis, angle) = [cos(angle / 2), axis * sin(angle / 2)])
  145. JPH_INLINE float GetRotationAngle(Vec3Arg inAxis) const { return GetW() == 0.0f? JPH_PI : 2.0f * ATan(GetXYZ().Dot(inAxis) / GetW()); }
  146. /// Swing Twist Decomposition: any quaternion can be split up as:
  147. ///
  148. /// \f[q = q_{swing} \: q_{twist}\f]
  149. ///
  150. /// where \f$q_{twist}\f$ rotates only around axis v.
  151. ///
  152. /// \f$q_{twist}\f$ is:
  153. ///
  154. /// \f[q_{twist} = \frac{[q_w, q_{ijk} \cdot v \: v]}{\left|[q_w, q_{ijk} \cdot v \: v]\right|}\f]
  155. ///
  156. /// where q_w is the real part of the quaternion and q_i the imaginary part (a 3 vector).
  157. ///
  158. /// The swing can then be calculated as:
  159. ///
  160. /// \f[q_{swing} = q \: q_{twist}^* \f]
  161. ///
  162. /// Where \f$q_{twist}^*\f$ = complex conjugate of \f$q_{twist}\f$
  163. JPH_INLINE Quat GetTwist(Vec3Arg inAxis) const;
  164. /// Decomposes quaternion into swing and twist component:
  165. ///
  166. /// \f$q = q_{swing} \: q_{twist}\f$
  167. ///
  168. /// where \f$q_{swing} \: \hat{x} = q_{twist} \: \hat{y} = q_{twist} \: \hat{z} = 0\f$
  169. ///
  170. /// In other words:
  171. ///
  172. /// - \f$q_{twist}\f$ only rotates around the X-axis.
  173. /// - \f$q_{swing}\f$ only rotates around the Y and Z-axis.
  174. ///
  175. /// @see Gino van den Bergen - Rotational Joint Limits in Quaternion Space - GDC 2016
  176. JPH_INLINE void GetSwingTwist(Quat &outSwing, Quat &outTwist) const;
  177. /// Linear interpolation between two quaternions (for small steps).
  178. /// @param inFraction is in the range [0, 1]
  179. /// @param inDestination The destination quaternion
  180. /// @return (1 - inFraction) * this + fraction * inDestination
  181. JPH_INLINE Quat LERP(QuatArg inDestination, float inFraction) const;
  182. /// Spherical linear interpolation between two quaternions.
  183. /// @param inFraction is in the range [0, 1]
  184. /// @param inDestination The destination quaternion
  185. /// @return When fraction is zero this quaternion is returned, when fraction is 1 inDestination is returned.
  186. /// When fraction is between 0 and 1 an interpolation along the shortest path is returned.
  187. JPH_INLINE Quat SLERP(QuatArg inDestination, float inFraction) const;
  188. /// Load 3 floats from memory (X, Y and Z component and then calculates W) reads 32 bits extra which it doesn't use
  189. static JPH_INLINE Quat sLoadFloat3Unsafe(const Float3 &inV);
  190. /// Store as 3 floats to memory (X, Y and Z component). Ensures that W is positive before storing.
  191. JPH_INLINE void StoreFloat3(Float3 *outV) const;
  192. /// Store as 4 floats
  193. JPH_INLINE void StoreFloat4(Float4 *outV) const;
  194. /// Compress a unit quaternion to a 32 bit value, precision is around 0.5 degree
  195. JPH_INLINE uint32 CompressUnitQuat() const { return mValue.CompressUnitVector(); }
  196. /// Decompress a unit quaternion from a 32 bit value
  197. JPH_INLINE static Quat sDecompressUnitQuat(uint32 inValue) { return Quat(Vec4::sDecompressUnitVector(inValue)); }
  198. /// To String
  199. friend ostream & operator << (ostream &inStream, QuatArg inQ) { inStream << inQ.mValue; return inStream; }
  200. /// 4 vector that stores [x, y, z, w] parts of the quaternion
  201. Vec4 mValue;
  202. };
  203. static_assert(std::is_trivial<Quat>(), "Is supposed to be a trivial type!");
  204. JPH_NAMESPACE_END
  205. #include "Quat.inl"