SixDOFConstraint.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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/Physics/Constraints/TwoBodyConstraint.h>
  6. #include <Jolt/Physics/Constraints/MotorSettings.h>
  7. #include <Jolt/Physics/Constraints/ConstraintPart/PointConstraintPart.h>
  8. #include <Jolt/Physics/Constraints/ConstraintPart/AxisConstraintPart.h>
  9. #include <Jolt/Physics/Constraints/ConstraintPart/AngleConstraintPart.h>
  10. #include <Jolt/Physics/Constraints/ConstraintPart/RotationEulerConstraintPart.h>
  11. #include <Jolt/Physics/Constraints/ConstraintPart/SwingTwistConstraintPart.h>
  12. JPH_NAMESPACE_BEGIN
  13. /// 6 Degree Of Freedom Constraint setup structure. Allows control over each of the 6 degrees of freedom.
  14. class JPH_EXPORT SixDOFConstraintSettings final : public TwoBodyConstraintSettings
  15. {
  16. public:
  17. JPH_DECLARE_SERIALIZABLE_VIRTUAL(JPH_EXPORT, SixDOFConstraintSettings)
  18. /// Constraint is split up into translation/rotation around X, Y and Z axis.
  19. enum EAxis
  20. {
  21. TranslationX,
  22. TranslationY,
  23. TranslationZ,
  24. RotationX,
  25. RotationY,
  26. RotationZ,
  27. Num,
  28. NumTranslation = TranslationZ + 1,
  29. };
  30. // See: ConstraintSettings::SaveBinaryState
  31. virtual void SaveBinaryState(StreamOut &inStream) const override;
  32. /// Create an instance of this constraint
  33. virtual TwoBodyConstraint * Create(Body &inBody1, Body &inBody2) const override;
  34. /// This determines in which space the constraint is setup, all properties below should be in the specified space
  35. EConstraintSpace mSpace = EConstraintSpace::WorldSpace;
  36. /// Body 1 constraint reference frame (space determined by mSpace)
  37. RVec3 mPosition1 = RVec3::sZero();
  38. Vec3 mAxisX1 = Vec3::sAxisX();
  39. Vec3 mAxisY1 = Vec3::sAxisY();
  40. /// Body 2 constraint reference frame (space determined by mSpace)
  41. RVec3 mPosition2 = RVec3::sZero();
  42. Vec3 mAxisX2 = Vec3::sAxisX();
  43. Vec3 mAxisY2 = Vec3::sAxisY();
  44. /// Friction settings.
  45. /// For translation: Max friction force in N. 0 = no friction.
  46. /// For rotation: Max friction torque in Nm. 0 = no friction.
  47. float mMaxFriction[EAxis::Num] = { 0, 0, 0, 0, 0, 0 };
  48. /// The type of swing constraint that we want to use.
  49. ESwingType mSwingType = ESwingType::Cone;
  50. /// Limits.
  51. /// For translation: Min and max linear limits in m (0 is frame of body 1 and 2 coincide).
  52. /// For rotation: Min and max angular limits in rad (0 is frame of body 1 and 2 coincide). See comments at Axis enum for limit ranges.
  53. ///
  54. /// Remove degree of freedom by setting min = FLT_MAX and max = -FLT_MAX. The constraint will be driven to 0 for this axis.
  55. ///
  56. /// Free movement over an axis is allowed when min = -FLT_MAX and max = FLT_MAX.
  57. ///
  58. /// Rotation limit around X-Axis: When limited, should be \f$\in [-\pi, \pi]\f$. Can be asymmetric around zero.
  59. ///
  60. /// Rotation limit around Y-Z Axis: Forms a pyramid or cone shaped limit:
  61. /// * For pyramid, should be \f$\in [-\pi, \pi]\f$ and does not need to be symmetrical around zero.
  62. /// * For cone should be \f$\in [0, \pi]\f$ and needs to be symmetrical around zero (min limit is assumed to be -max limit).
  63. float mLimitMin[EAxis::Num] = { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX };
  64. float mLimitMax[EAxis::Num] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
  65. /// When enabled, this makes the limits soft. When the constraint exceeds the limits, a spring force will pull it back.
  66. /// Only soft translation limits are supported, soft rotation limits are not currently supported.
  67. SpringSettings mLimitsSpringSettings[EAxis::NumTranslation];
  68. /// Make axis free (unconstrained)
  69. void MakeFreeAxis(EAxis inAxis) { mLimitMin[inAxis] = -FLT_MAX; mLimitMax[inAxis] = FLT_MAX; }
  70. bool IsFreeAxis(EAxis inAxis) const { return mLimitMin[inAxis] == -FLT_MAX && mLimitMax[inAxis] == FLT_MAX; }
  71. /// Make axis fixed (fixed at value 0)
  72. void MakeFixedAxis(EAxis inAxis) { mLimitMin[inAxis] = FLT_MAX; mLimitMax[inAxis] = -FLT_MAX; }
  73. bool IsFixedAxis(EAxis inAxis) const { return mLimitMin[inAxis] >= mLimitMax[inAxis]; }
  74. /// Set a valid range for the constraint (if inMax < inMin, the axis will become fixed)
  75. void SetLimitedAxis(EAxis inAxis, float inMin, float inMax) { mLimitMin[inAxis] = inMin; mLimitMax[inAxis] = inMax; }
  76. /// Motor settings for each axis
  77. MotorSettings mMotorSettings[EAxis::Num];
  78. protected:
  79. // See: ConstraintSettings::RestoreBinaryState
  80. virtual void RestoreBinaryState(StreamIn &inStream) override;
  81. };
  82. /// 6 Degree Of Freedom Constraint. Allows control over each of the 6 degrees of freedom.
  83. class JPH_EXPORT SixDOFConstraint final : public TwoBodyConstraint
  84. {
  85. public:
  86. JPH_OVERRIDE_NEW_DELETE
  87. /// Get Axis from settings class
  88. using EAxis = SixDOFConstraintSettings::EAxis;
  89. /// Construct six DOF constraint
  90. SixDOFConstraint(Body &inBody1, Body &inBody2, const SixDOFConstraintSettings &inSettings);
  91. /// Generic interface of a constraint
  92. virtual EConstraintSubType GetSubType() const override { return EConstraintSubType::SixDOF; }
  93. virtual void NotifyShapeChanged(const BodyID &inBodyID, Vec3Arg inDeltaCOM) override;
  94. virtual void SetupVelocityConstraint(float inDeltaTime) override;
  95. virtual void ResetWarmStart() override;
  96. virtual void WarmStartVelocityConstraint(float inWarmStartImpulseRatio) override;
  97. virtual bool SolveVelocityConstraint(float inDeltaTime) override;
  98. virtual bool SolvePositionConstraint(float inDeltaTime, float inBaumgarte) override;
  99. #ifdef JPH_DEBUG_RENDERER
  100. virtual void DrawConstraint(DebugRenderer *inRenderer) const override;
  101. virtual void DrawConstraintLimits(DebugRenderer *inRenderer) const override;
  102. #endif // JPH_DEBUG_RENDERER
  103. virtual void SaveState(StateRecorder &inStream) const override;
  104. virtual void RestoreState(StateRecorder &inStream) override;
  105. virtual Ref<ConstraintSettings> GetConstraintSettings() const override;
  106. // See: TwoBodyConstraint
  107. virtual Mat44 GetConstraintToBody1Matrix() const override { return Mat44::sRotationTranslation(mConstraintToBody1, mLocalSpacePosition1); }
  108. virtual Mat44 GetConstraintToBody2Matrix() const override { return Mat44::sRotationTranslation(mConstraintToBody2, mLocalSpacePosition2); }
  109. /// Update the translation limits for this constraint
  110. void SetTranslationLimits(Vec3Arg inLimitMin, Vec3Arg inLimitMax);
  111. /// Update the rotational limits for this constraint
  112. void SetRotationLimits(Vec3Arg inLimitMin, Vec3Arg inLimitMax);
  113. /// Get constraint Limits
  114. float GetLimitsMin(EAxis inAxis) const { return mLimitMin[inAxis]; }
  115. float GetLimitsMax(EAxis inAxis) const { return mLimitMax[inAxis]; }
  116. Vec3 GetTranslationLimitsMin() const { return Vec3::sLoadFloat3Unsafe(*reinterpret_cast<const Float3 *>(&mLimitMin[EAxis::TranslationX])); }
  117. Vec3 GetTranslationLimitsMax() const { return Vec3::sLoadFloat3Unsafe(*reinterpret_cast<const Float3 *>(&mLimitMax[EAxis::TranslationX])); }
  118. Vec3 GetRotationLimitsMin() const { return Vec3::sLoadFloat3Unsafe(*reinterpret_cast<const Float3 *>(&mLimitMin[EAxis::RotationX])); }
  119. Vec3 GetRotationLimitsMax() const { return Vec3::sLoadFloat3Unsafe(*reinterpret_cast<const Float3 *>(&mLimitMax[EAxis::RotationX])); }
  120. /// Check which axis are fixed/free
  121. inline bool IsFixedAxis(EAxis inAxis) const { return (mFixedAxis & (1 << inAxis)) != 0; }
  122. inline bool IsFreeAxis(EAxis inAxis) const { return (mFreeAxis & (1 << inAxis)) != 0; }
  123. /// Update the limits spring settings
  124. const SpringSettings & GetLimitsSpringSettings(EAxis inAxis) const { JPH_ASSERT(inAxis < EAxis::NumTranslation); return mLimitsSpringSettings[inAxis]; }
  125. void SetLimitsSpringSettings(EAxis inAxis, const SpringSettings& inLimitsSpringSettings) { JPH_ASSERT(inAxis < EAxis::NumTranslation); mLimitsSpringSettings[inAxis] = inLimitsSpringSettings; CacheHasSpringLimits(); }
  126. /// Set the max friction for each axis
  127. void SetMaxFriction(EAxis inAxis, float inFriction);
  128. float GetMaxFriction(EAxis inAxis) const { return mMaxFriction[inAxis]; }
  129. /// Get rotation of constraint in constraint space
  130. Quat GetRotationInConstraintSpace() const;
  131. /// Motor settings
  132. MotorSettings & GetMotorSettings(EAxis inAxis) { return mMotorSettings[inAxis]; }
  133. const MotorSettings & GetMotorSettings(EAxis inAxis) const { return mMotorSettings[inAxis]; }
  134. /// Motor controls.
  135. /// Translation motors work in constraint space of body 1.
  136. /// Rotation motors work in constraint space of body 2 (!).
  137. void SetMotorState(EAxis inAxis, EMotorState inState);
  138. EMotorState GetMotorState(EAxis inAxis) const { return mMotorState[inAxis]; }
  139. /// Set the target velocity in body 1 constraint space
  140. Vec3 GetTargetVelocityCS() const { return mTargetVelocity; }
  141. void SetTargetVelocityCS(Vec3Arg inVelocity) { mTargetVelocity = inVelocity; }
  142. /// Set the target angular velocity in body 2 constraint space (!)
  143. void SetTargetAngularVelocityCS(Vec3Arg inAngularVelocity) { mTargetAngularVelocity = inAngularVelocity; }
  144. Vec3 GetTargetAngularVelocityCS() const { return mTargetAngularVelocity; }
  145. /// Set the target position in body 1 constraint space
  146. Vec3 GetTargetPositionCS() const { return mTargetPosition; }
  147. void SetTargetPositionCS(Vec3Arg inPosition) { mTargetPosition = inPosition; }
  148. /// Set the target orientation in body 1 constraint space
  149. void SetTargetOrientationCS(QuatArg inOrientation);
  150. Quat GetTargetOrientationCS() const { return mTargetOrientation; }
  151. /// Set the target orientation in body space (R2 = R1 * inOrientation, where R1 and R2 are the world space rotations for body 1 and 2).
  152. /// Solve: R2 * ConstraintToBody2 = R1 * ConstraintToBody1 * q (see SwingTwistConstraint::GetSwingTwist) and R2 = R1 * inOrientation for q.
  153. void SetTargetOrientationBS(QuatArg inOrientation) { SetTargetOrientationCS(mConstraintToBody1.Conjugated() * inOrientation * mConstraintToBody2); }
  154. ///@name Get Lagrange multiplier from last physics update (the linear/angular impulse applied to satisfy the constraint)
  155. inline Vec3 GetTotalLambdaPosition() const { return IsTranslationFullyConstrained()? mPointConstraintPart.GetTotalLambda() : Vec3(mTranslationConstraintPart[0].GetTotalLambda(), mTranslationConstraintPart[1].GetTotalLambda(), mTranslationConstraintPart[2].GetTotalLambda()); }
  156. inline Vec3 GetTotalLambdaRotation() const { return IsRotationFullyConstrained()? mRotationConstraintPart.GetTotalLambda() : Vec3(mSwingTwistConstraintPart.GetTotalTwistLambda(), mSwingTwistConstraintPart.GetTotalSwingYLambda(), mSwingTwistConstraintPart.GetTotalSwingZLambda()); }
  157. inline Vec3 GetTotalLambdaMotorTranslation() const { return Vec3(mMotorTranslationConstraintPart[0].GetTotalLambda(), mMotorTranslationConstraintPart[1].GetTotalLambda(), mMotorTranslationConstraintPart[2].GetTotalLambda()); }
  158. inline Vec3 GetTotalLambdaMotorRotation() const { return Vec3(mMotorRotationConstraintPart[0].GetTotalLambda(), mMotorRotationConstraintPart[1].GetTotalLambda(), mMotorRotationConstraintPart[2].GetTotalLambda()); }
  159. private:
  160. // Calculate properties needed for the position constraint
  161. inline void GetPositionConstraintProperties(Vec3 &outR1PlusU, Vec3 &outR2, Vec3 &outU) const;
  162. // Sanitize the translation limits
  163. inline void UpdateTranslationLimits();
  164. // Propagate the rotation limits to the constraint part
  165. inline void UpdateRotationLimits();
  166. // Update the cached state of which axis are free and which ones are fixed
  167. inline void UpdateFixedFreeAxis();
  168. // Cache the state of mTranslationMotorActive
  169. void CacheTranslationMotorActive();
  170. // Cache the state of mRotationMotorActive
  171. void CacheRotationMotorActive();
  172. // Cache the state of mRotationPositionMotorActive
  173. void CacheRotationPositionMotorActive();
  174. /// Cache the state of mHasSpringLimits
  175. void CacheHasSpringLimits();
  176. // Constraint settings helper functions
  177. inline bool IsTranslationConstrained() const { return (mFreeAxis & 0b111) != 0b111; }
  178. inline bool IsTranslationFullyConstrained() const { return (mFixedAxis & 0b111) == 0b111 && !mHasSpringLimits; }
  179. inline bool IsRotationConstrained() const { return (mFreeAxis & 0b111000) != 0b111000; }
  180. inline bool IsRotationFullyConstrained() const { return (mFixedAxis & 0b111000) == 0b111000; }
  181. inline bool HasFriction(EAxis inAxis) const { return !IsFixedAxis(inAxis) && mMaxFriction[inAxis] > 0.0f; }
  182. // CONFIGURATION PROPERTIES FOLLOW
  183. // Local space constraint positions
  184. Vec3 mLocalSpacePosition1;
  185. Vec3 mLocalSpacePosition2;
  186. // Transforms from constraint space to body space
  187. Quat mConstraintToBody1;
  188. Quat mConstraintToBody2;
  189. // Limits
  190. uint8 mFreeAxis = 0; // Bitmask of free axis (bit 0 = TranslationX)
  191. uint8 mFixedAxis = 0; // Bitmask of fixed axis (bit 0 = TranslationX)
  192. bool mTranslationMotorActive = false; // If any of the translational frictions / motors are active
  193. bool mRotationMotorActive = false; // If any of the rotational frictions / motors are active
  194. uint8 mRotationPositionMotorActive = 0; // Bitmask of axis that have position motor active (bit 0 = RotationX)
  195. bool mHasSpringLimits = false; // If any of the limit springs have a non-zero frequency/stiffness
  196. float mLimitMin[EAxis::Num];
  197. float mLimitMax[EAxis::Num];
  198. SpringSettings mLimitsSpringSettings[EAxis::NumTranslation];
  199. // Motor settings for each axis
  200. MotorSettings mMotorSettings[EAxis::Num];
  201. // Friction settings for each axis
  202. float mMaxFriction[EAxis::Num];
  203. // Motor controls
  204. EMotorState mMotorState[EAxis::Num] = { EMotorState::Off, EMotorState::Off, EMotorState::Off, EMotorState::Off, EMotorState::Off, EMotorState::Off };
  205. Vec3 mTargetVelocity = Vec3::sZero();
  206. Vec3 mTargetAngularVelocity = Vec3::sZero();
  207. Vec3 mTargetPosition = Vec3::sZero();
  208. Quat mTargetOrientation = Quat::sIdentity();
  209. // RUN TIME PROPERTIES FOLLOW
  210. // Constraint space axis in world space
  211. Vec3 mTranslationAxis[3];
  212. Vec3 mRotationAxis[3];
  213. // Translation displacement (valid when translation axis has a range limit)
  214. float mDisplacement[3];
  215. // Individual constraint parts for translation, or a combined point constraint part if all axis are fixed
  216. AxisConstraintPart mTranslationConstraintPart[3];
  217. PointConstraintPart mPointConstraintPart;
  218. // Individual constraint parts for rotation or a combined constraint part if rotation is fixed
  219. SwingTwistConstraintPart mSwingTwistConstraintPart;
  220. RotationEulerConstraintPart mRotationConstraintPart;
  221. // Motor or friction constraints
  222. AxisConstraintPart mMotorTranslationConstraintPart[3];
  223. AngleConstraintPart mMotorRotationConstraintPart[3];
  224. };
  225. JPH_NAMESPACE_END