SwingTwistConstraint.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/Physics/Constraints/SwingTwistConstraint.h>
  5. #include <Jolt/Physics/Body/Body.h>
  6. #include <Jolt/ObjectStream/TypeDeclarations.h>
  7. #include <Jolt/Core/StreamIn.h>
  8. #include <Jolt/Core/StreamOut.h>
  9. #ifdef JPH_DEBUG_RENDERER
  10. #include <Jolt/Renderer/DebugRenderer.h>
  11. #endif // JPH_DEBUG_RENDERER
  12. JPH_NAMESPACE_BEGIN
  13. JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(SwingTwistConstraintSettings)
  14. {
  15. JPH_ADD_BASE_CLASS(SwingTwistConstraintSettings, TwoBodyConstraintSettings)
  16. JPH_ADD_ENUM_ATTRIBUTE(SwingTwistConstraintSettings, mSpace)
  17. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mPosition1)
  18. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mTwistAxis1)
  19. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mPlaneAxis1)
  20. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mPosition2)
  21. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mTwistAxis2)
  22. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mPlaneAxis2)
  23. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mNormalHalfConeAngle)
  24. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mPlaneHalfConeAngle)
  25. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mTwistMinAngle)
  26. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mTwistMaxAngle)
  27. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mMaxFrictionTorque)
  28. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mSwingMotorSettings)
  29. JPH_ADD_ATTRIBUTE(SwingTwistConstraintSettings, mTwistMotorSettings)
  30. }
  31. void SwingTwistConstraintSettings::SaveBinaryState(StreamOut &inStream) const
  32. {
  33. ConstraintSettings::SaveBinaryState(inStream);
  34. inStream.Write(mSpace);
  35. inStream.Write(mPosition1);
  36. inStream.Write(mTwistAxis1);
  37. inStream.Write(mPlaneAxis1);
  38. inStream.Write(mPosition2);
  39. inStream.Write(mTwistAxis2);
  40. inStream.Write(mPlaneAxis2);
  41. inStream.Write(mNormalHalfConeAngle);
  42. inStream.Write(mPlaneHalfConeAngle);
  43. inStream.Write(mTwistMinAngle);
  44. inStream.Write(mTwistMaxAngle);
  45. inStream.Write(mMaxFrictionTorque);
  46. mSwingMotorSettings.SaveBinaryState(inStream);
  47. mTwistMotorSettings.SaveBinaryState(inStream);
  48. }
  49. void SwingTwistConstraintSettings::RestoreBinaryState(StreamIn &inStream)
  50. {
  51. ConstraintSettings::RestoreBinaryState(inStream);
  52. inStream.Read(mSpace);
  53. inStream.Read(mPosition1);
  54. inStream.Read(mTwistAxis1);
  55. inStream.Read(mPlaneAxis1);
  56. inStream.Read(mPosition2);
  57. inStream.Read(mTwistAxis2);
  58. inStream.Read(mPlaneAxis2);
  59. inStream.Read(mNormalHalfConeAngle);
  60. inStream.Read(mPlaneHalfConeAngle);
  61. inStream.Read(mTwistMinAngle);
  62. inStream.Read(mTwistMaxAngle);
  63. inStream.Read(mMaxFrictionTorque);
  64. mSwingMotorSettings.RestoreBinaryState(inStream);
  65. mTwistMotorSettings.RestoreBinaryState(inStream);
  66. }
  67. TwoBodyConstraint *SwingTwistConstraintSettings::Create(Body &inBody1, Body &inBody2) const
  68. {
  69. return new SwingTwistConstraint(inBody1, inBody2, *this);
  70. }
  71. void SwingTwistConstraint::UpdateLimits()
  72. {
  73. // Pass limits on to swing twist constraint part
  74. mSwingTwistConstraintPart.SetLimits(mTwistMinAngle, mTwistMaxAngle, mPlaneHalfConeAngle, mNormalHalfConeAngle);
  75. }
  76. SwingTwistConstraint::SwingTwistConstraint(Body &inBody1, Body &inBody2, const SwingTwistConstraintSettings &inSettings) :
  77. TwoBodyConstraint(inBody1, inBody2, inSettings),
  78. mLocalSpacePosition1(inSettings.mPosition1),
  79. mLocalSpacePosition2(inSettings.mPosition2),
  80. mNormalHalfConeAngle(inSettings.mNormalHalfConeAngle),
  81. mPlaneHalfConeAngle(inSettings.mPlaneHalfConeAngle),
  82. mTwistMinAngle(inSettings.mTwistMinAngle),
  83. mTwistMaxAngle(inSettings.mTwistMaxAngle),
  84. mMaxFrictionTorque(inSettings.mMaxFrictionTorque),
  85. mSwingMotorSettings(inSettings.mSwingMotorSettings),
  86. mTwistMotorSettings(inSettings.mTwistMotorSettings)
  87. {
  88. // Calculate rotation needed to go from constraint space to body1 local space
  89. Vec3 normal_axis1 = inSettings.mPlaneAxis1.Cross(inSettings.mTwistAxis1);
  90. Mat44 c_to_b1(Vec4(inSettings.mTwistAxis1, 0), Vec4(normal_axis1, 0), Vec4(inSettings.mPlaneAxis1, 0), Vec4(0, 0, 0, 1));
  91. mConstraintToBody1 = c_to_b1.GetQuaternion();
  92. // Calculate rotation needed to go from constraint space to body2 local space
  93. Vec3 normal_axis2 = inSettings.mPlaneAxis2.Cross(inSettings.mTwistAxis2);
  94. Mat44 c_to_b2(Vec4(inSettings.mTwistAxis2, 0), Vec4(normal_axis2, 0), Vec4(inSettings.mPlaneAxis2, 0), Vec4(0, 0, 0, 1));
  95. mConstraintToBody2 = c_to_b2.GetQuaternion();
  96. if (inSettings.mSpace == EConstraintSpace::WorldSpace)
  97. {
  98. // If all properties were specified in world space, take them to local space now
  99. mLocalSpacePosition1 = inBody1.GetInverseCenterOfMassTransform() * mLocalSpacePosition1;
  100. mConstraintToBody1 = inBody1.GetRotation().Conjugated() * mConstraintToBody1;
  101. mLocalSpacePosition2 = inBody2.GetInverseCenterOfMassTransform() * mLocalSpacePosition2;
  102. mConstraintToBody2 = inBody2.GetRotation().Conjugated() * mConstraintToBody2;
  103. }
  104. UpdateLimits();
  105. }
  106. Quat SwingTwistConstraint::GetRotationInConstraintSpace() const
  107. {
  108. // Let b1, b2 be the center of mass transform of body1 and body2 (For body1 this is mBody1->GetCenterOfMassTransform())
  109. // Let c1, c2 be the transform that takes a vector from constraint space to local space of body1 and body2 (For body1 this is Mat44::sRotationTranslation(mConstraintToBody1, mLocalSpacePosition1))
  110. // Let q be the rotation of the constraint in constraint space
  111. // b2 takes a vector from the local space of body2 to world space
  112. // To express this in terms of b1: b2 = b1 * c1 * q * c2^-1
  113. // c2^-1 goes from local body 2 space to constraint space
  114. // q rotates the constraint
  115. // c1 goes from constraint space to body 1 local space
  116. // b1 goes from body 1 local space to world space
  117. // So when the body rotations are given, q = (b1 * c1)^-1 * b2 c2
  118. // Or: q = (q1 * c1)^-1 * (q2 * c2) if we're only interested in rotations
  119. Quat constraint_body1_to_world = mBody1->GetRotation() * mConstraintToBody1;
  120. Quat constraint_body2_to_world = mBody2->GetRotation() * mConstraintToBody2;
  121. return constraint_body1_to_world.Conjugated() * constraint_body2_to_world;
  122. }
  123. void SwingTwistConstraint::SetSwingMotorState(EMotorState inState)
  124. {
  125. JPH_ASSERT(inState == EMotorState::Off || mSwingMotorSettings.IsValid());
  126. if (mSwingMotorState != inState)
  127. {
  128. mSwingMotorState = inState;
  129. // Ensure that warm starting next frame doesn't apply any impulses (motor parts are repurposed for different modes)
  130. for (AngleConstraintPart &c : mMotorConstraintPart)
  131. c.Deactivate();
  132. }
  133. }
  134. void SwingTwistConstraint::SetTwistMotorState(EMotorState inState)
  135. {
  136. JPH_ASSERT(inState == EMotorState::Off || mTwistMotorSettings.IsValid());
  137. if (mTwistMotorState != inState)
  138. {
  139. mTwistMotorState = inState;
  140. // Ensure that warm starting next frame doesn't apply any impulses (motor parts are repurposed for different modes)
  141. mMotorConstraintPart[0].Deactivate();
  142. }
  143. }
  144. void SwingTwistConstraint::SetTargetOrientationCS(QuatArg inOrientation)
  145. {
  146. Quat q_swing, q_twist;
  147. inOrientation.GetSwingTwist(q_swing, q_twist);
  148. bool swing_y_clamped, swing_z_clamped, twist_clamped;
  149. mSwingTwistConstraintPart.ClampSwingTwist(q_swing, swing_y_clamped, swing_z_clamped, q_twist, twist_clamped);
  150. if (swing_y_clamped || swing_z_clamped || twist_clamped)
  151. mTargetOrientation = q_swing * q_twist;
  152. else
  153. mTargetOrientation = inOrientation;
  154. }
  155. void SwingTwistConstraint::SetupVelocityConstraint(float inDeltaTime)
  156. {
  157. // Setup point constraint
  158. Mat44 rotation1 = Mat44::sRotation(mBody1->GetRotation());
  159. Mat44 rotation2 = Mat44::sRotation(mBody2->GetRotation());
  160. mPointConstraintPart.CalculateConstraintProperties(*mBody1, rotation1, mLocalSpacePosition1, *mBody2, rotation2, mLocalSpacePosition2);
  161. // GetRotationInConstraintSpace written out since we reuse the sub expressions
  162. Quat constraint_body1_to_world = mBody1->GetRotation() * mConstraintToBody1;
  163. Quat constraint_body2_to_world = mBody2->GetRotation() * mConstraintToBody2;
  164. Quat q = constraint_body1_to_world.Conjugated() * constraint_body2_to_world;
  165. // Calculate constraint properties for the swing twist limit
  166. mSwingTwistConstraintPart.CalculateConstraintProperties(inDeltaTime, *mBody1, *mBody2, q, constraint_body1_to_world);
  167. if (mSwingMotorState != EMotorState::Off || mTwistMotorState != EMotorState::Off || mMaxFrictionTorque > 0.0f)
  168. {
  169. // Calculate rotation motor axis
  170. Mat44 ws_axis = Mat44::sRotation(constraint_body2_to_world);
  171. for (int i = 0; i < 3; ++i)
  172. mWorldSpaceMotorAxis[i] = ws_axis.GetColumn3(i);
  173. Vec3 rotation_error;
  174. if (mSwingMotorState == EMotorState::Position || mTwistMotorState == EMotorState::Position)
  175. {
  176. // Get target orientation along the shortest path from q
  177. Quat target_orientation = q.Dot(mTargetOrientation) > 0.0f? mTargetOrientation : -mTargetOrientation;
  178. // The definition of the constraint rotation q:
  179. // R2 * ConstraintToBody2 = R1 * ConstraintToBody1 * q (1)
  180. //
  181. // R2' is the rotation of body 2 when reaching the target_orientation:
  182. // R2' * ConstraintToBody2 = R1 * ConstraintToBody1 * target_orientation (2)
  183. //
  184. // The difference in body 2 space:
  185. // R2' = R2 * diff_body2 (3)
  186. //
  187. // We want to specify the difference in the constraint space of body 2:
  188. // diff_body2 = ConstraintToBody2 * diff * ConstraintToBody2^* (4)
  189. //
  190. // Extracting R2' from 2: R2' = R1 * ConstraintToBody1 * target_orientation * ConstraintToBody2^* (5)
  191. // Combining 3 & 4: R2' = R2 * ConstraintToBody2 * diff * ConstraintToBody2^* (6)
  192. // Combining 1 & 6: R2' = R1 * ConstraintToBody1 * q * diff * ConstraintToBody2^* (7)
  193. // Combining 5 & 7: R1 * ConstraintToBody1 * target_orientation * ConstraintToBody2^* = R1 * ConstraintToBody1 * q * diff * ConstraintToBody2^*
  194. // <=> target_orientation = q * diff
  195. // <=> diff = q^* * target_orientation
  196. Quat diff = q.Conjugated() * target_orientation;
  197. // Approximate error angles
  198. // The imaginary part of a quaternion is rotation_axis * sin(angle / 2)
  199. // If angle is small, sin(x) = x so angle[i] ~ 2.0f * rotation_axis[i]
  200. // We'll be making small time steps, so if the angle is not small at least the sign will be correct and we'll move in the right direction
  201. rotation_error = -2.0f * diff.GetXYZ();
  202. }
  203. // Swing motor
  204. switch (mSwingMotorState)
  205. {
  206. case EMotorState::Off:
  207. if (mMaxFrictionTorque > 0.0f)
  208. {
  209. // Enable friction
  210. for (int i = 1; i < 3; ++i)
  211. mMotorConstraintPart[i].CalculateConstraintProperties(inDeltaTime, *mBody1, *mBody2, mWorldSpaceMotorAxis[i], 0.0f);
  212. }
  213. else
  214. {
  215. // Disable friction
  216. for (AngleConstraintPart &c : mMotorConstraintPart)
  217. c.Deactivate();
  218. }
  219. break;
  220. case EMotorState::Velocity:
  221. // Use motor to create angular velocity around desired axis
  222. for (int i = 1; i < 3; ++i)
  223. mMotorConstraintPart[i].CalculateConstraintProperties(inDeltaTime, *mBody1, *mBody2, mWorldSpaceMotorAxis[i], -mTargetAngularVelocity[i]);
  224. break;
  225. case EMotorState::Position:
  226. // Use motor to drive rotation error to zero
  227. for (int i = 1; i < 3; ++i)
  228. mMotorConstraintPart[i].CalculateConstraintProperties(inDeltaTime, *mBody1, *mBody2, mWorldSpaceMotorAxis[i], 0.0f, rotation_error[i], mSwingMotorSettings.mFrequency, mSwingMotorSettings.mDamping);
  229. break;
  230. }
  231. // Twist motor
  232. switch (mTwistMotorState)
  233. {
  234. case EMotorState::Off:
  235. if (mMaxFrictionTorque > 0.0f)
  236. {
  237. // Enable friction
  238. mMotorConstraintPart[0].CalculateConstraintProperties(inDeltaTime, *mBody1, *mBody2, mWorldSpaceMotorAxis[0], 0.0f);
  239. }
  240. else
  241. {
  242. // Disable friction
  243. mMotorConstraintPart[0].Deactivate();
  244. }
  245. break;
  246. case EMotorState::Velocity:
  247. // Use motor to create angular velocity around desired axis
  248. mMotorConstraintPart[0].CalculateConstraintProperties(inDeltaTime, *mBody1, *mBody2, mWorldSpaceMotorAxis[0], -mTargetAngularVelocity[0]);
  249. break;
  250. case EMotorState::Position:
  251. // Use motor to drive rotation error to zero
  252. mMotorConstraintPart[0].CalculateConstraintProperties(inDeltaTime, *mBody1, *mBody2, mWorldSpaceMotorAxis[0], 0.0f, rotation_error[0], mTwistMotorSettings.mFrequency, mTwistMotorSettings.mDamping);
  253. break;
  254. }
  255. }
  256. else
  257. {
  258. // Disable rotation motor
  259. for (AngleConstraintPart &c : mMotorConstraintPart)
  260. c.Deactivate();
  261. }
  262. }
  263. void SwingTwistConstraint::WarmStartVelocityConstraint(float inWarmStartImpulseRatio)
  264. {
  265. // Warm starting: Apply previous frame impulse
  266. for (AngleConstraintPart &c : mMotorConstraintPart)
  267. c.WarmStart(*mBody1, *mBody2, inWarmStartImpulseRatio);
  268. mSwingTwistConstraintPart.WarmStart(*mBody1, *mBody2, inWarmStartImpulseRatio);
  269. mPointConstraintPart.WarmStart(*mBody1, *mBody2, inWarmStartImpulseRatio);
  270. }
  271. bool SwingTwistConstraint::SolveVelocityConstraint(float inDeltaTime)
  272. {
  273. bool impulse = false;
  274. // Solve twist rotation motor
  275. if (mMotorConstraintPart[0].IsActive())
  276. {
  277. // Twist limits
  278. float min_twist_limit, max_twist_limit;
  279. if (mTwistMotorState == EMotorState::Off)
  280. {
  281. max_twist_limit = inDeltaTime * mMaxFrictionTorque;
  282. min_twist_limit = -max_twist_limit;
  283. }
  284. else
  285. {
  286. min_twist_limit = inDeltaTime * mTwistMotorSettings.mMinTorqueLimit;
  287. max_twist_limit = inDeltaTime * mTwistMotorSettings.mMaxTorqueLimit;
  288. }
  289. impulse |= mMotorConstraintPart[0].SolveVelocityConstraint(*mBody1, *mBody2, mWorldSpaceMotorAxis[0], min_twist_limit, max_twist_limit);
  290. }
  291. // Solve swing rotation motor
  292. if (mMotorConstraintPart[1].IsActive())
  293. {
  294. // Swing parts should turn on / off together
  295. JPH_ASSERT(mMotorConstraintPart[2].IsActive());
  296. // Swing limits
  297. float min_swing_limit, max_swing_limit;
  298. if (mSwingMotorState == EMotorState::Off)
  299. {
  300. max_swing_limit = inDeltaTime * mMaxFrictionTorque;
  301. min_swing_limit = -max_swing_limit;
  302. }
  303. else
  304. {
  305. min_swing_limit = inDeltaTime * mSwingMotorSettings.mMinTorqueLimit;
  306. max_swing_limit = inDeltaTime * mSwingMotorSettings.mMaxTorqueLimit;
  307. }
  308. for (int i = 1; i < 3; ++i)
  309. impulse |= mMotorConstraintPart[i].SolveVelocityConstraint(*mBody1, *mBody2, mWorldSpaceMotorAxis[i], min_swing_limit, max_swing_limit);
  310. }
  311. else
  312. {
  313. // Swing parts should turn on / off together
  314. JPH_ASSERT(!mMotorConstraintPart[2].IsActive());
  315. }
  316. // Solve rotation limits
  317. impulse |= mSwingTwistConstraintPart.SolveVelocityConstraint(*mBody1, *mBody2);
  318. // Solve position constraint
  319. impulse |= mPointConstraintPart.SolveVelocityConstraint(*mBody1, *mBody2);
  320. return impulse;
  321. }
  322. bool SwingTwistConstraint::SolvePositionConstraint(float inDeltaTime, float inBaumgarte)
  323. {
  324. bool impulse = false;
  325. // Solve rotation violations
  326. Quat q = GetRotationInConstraintSpace();
  327. impulse |= mSwingTwistConstraintPart.SolvePositionConstraint(*mBody1, *mBody2, q, mConstraintToBody1, mConstraintToBody2, inBaumgarte);
  328. // Solve position violations
  329. mPointConstraintPart.CalculateConstraintProperties(*mBody1, Mat44::sRotation(mBody1->GetRotation()), mLocalSpacePosition1, *mBody2, Mat44::sRotation(mBody2->GetRotation()), mLocalSpacePosition2);
  330. impulse |= mPointConstraintPart.SolvePositionConstraint(*mBody1, *mBody2, inBaumgarte);
  331. return impulse;
  332. }
  333. #ifdef JPH_DEBUG_RENDERER
  334. void SwingTwistConstraint::DrawConstraint(DebugRenderer *inRenderer) const
  335. {
  336. // Get constraint properties in world space
  337. Mat44 transform1 = mBody1->GetCenterOfMassTransform();
  338. Vec3 position1 = transform1 * mLocalSpacePosition1;
  339. Quat rotation1 = mBody1->GetRotation() * mConstraintToBody1;
  340. Quat rotation2 = mBody2->GetRotation() * mConstraintToBody2;
  341. // Draw constraint orientation
  342. inRenderer->DrawCoordinateSystem(Mat44::sRotationTranslation(rotation1, position1), mDrawConstraintSize);
  343. // Draw current swing and twist
  344. Quat q = GetRotationInConstraintSpace();
  345. Quat q_swing, q_twist;
  346. q.GetSwingTwist(q_swing, q_twist);
  347. inRenderer->DrawLine(position1, position1 + mDrawConstraintSize * (rotation1 * q_twist).RotateAxisY(), Color::sWhite);
  348. inRenderer->DrawLine(position1, position1 + mDrawConstraintSize * (rotation1 * q_swing).RotateAxisX(), Color::sWhite);
  349. if (mSwingMotorState == EMotorState::Velocity || mTwistMotorState == EMotorState::Velocity)
  350. {
  351. // Draw target angular velocity
  352. inRenderer->DrawArrow(position1, position1 + rotation2 * mTargetAngularVelocity, Color::sRed, 0.1f);
  353. }
  354. if (mSwingMotorState == EMotorState::Position || mTwistMotorState == EMotorState::Position)
  355. {
  356. // Draw motor swing and twist
  357. Quat swing, twist;
  358. mTargetOrientation.GetSwingTwist(swing, twist);
  359. inRenderer->DrawLine(position1, position1 + mDrawConstraintSize * (rotation1 * twist).RotateAxisY(), Color::sYellow);
  360. inRenderer->DrawLine(position1, position1 + mDrawConstraintSize * (rotation1 * swing).RotateAxisX(), Color::sCyan);
  361. }
  362. }
  363. void SwingTwistConstraint::DrawConstraintLimits(DebugRenderer *inRenderer) const
  364. {
  365. // Get matrix that transforms from constraint space to world space
  366. Mat44 constraint_to_world = Mat44::sRotationTranslation(mBody1->GetRotation() * mConstraintToBody1, mBody1->GetCenterOfMassTransform() * mLocalSpacePosition1);
  367. // Draw limits
  368. inRenderer->DrawSwingLimits(constraint_to_world, mPlaneHalfConeAngle, mNormalHalfConeAngle, mDrawConstraintSize, Color::sGreen, DebugRenderer::ECastShadow::Off);
  369. inRenderer->DrawPie(constraint_to_world.GetTranslation(), mDrawConstraintSize, constraint_to_world.GetAxisX(), constraint_to_world.GetAxisY(), mTwistMinAngle, mTwistMaxAngle, Color::sPurple, DebugRenderer::ECastShadow::Off);
  370. }
  371. #endif // JPH_DEBUG_RENDERER
  372. void SwingTwistConstraint::SaveState(StateRecorder &inStream) const
  373. {
  374. TwoBodyConstraint::SaveState(inStream);
  375. mPointConstraintPart.SaveState(inStream);
  376. mSwingTwistConstraintPart.SaveState(inStream);
  377. for (const AngleConstraintPart &c : mMotorConstraintPart)
  378. c.SaveState(inStream);
  379. inStream.Write(mSwingMotorState);
  380. inStream.Write(mTwistMotorState);
  381. inStream.Write(mTargetAngularVelocity);
  382. inStream.Write(mTargetOrientation);
  383. }
  384. void SwingTwistConstraint::RestoreState(StateRecorder &inStream)
  385. {
  386. TwoBodyConstraint::RestoreState(inStream);
  387. mPointConstraintPart.RestoreState(inStream);
  388. mSwingTwistConstraintPart.RestoreState(inStream);
  389. for (AngleConstraintPart &c : mMotorConstraintPart)
  390. c.RestoreState(inStream);
  391. inStream.Read(mSwingMotorState);
  392. inStream.Read(mTwistMotorState);
  393. inStream.Read(mTargetAngularVelocity);
  394. inStream.Read(mTargetOrientation);
  395. }
  396. Ref<ConstraintSettings> SwingTwistConstraint::GetConstraintSettings() const
  397. {
  398. SwingTwistConstraintSettings *settings = new SwingTwistConstraintSettings;
  399. ToConstraintSettings(*settings);
  400. settings->mSpace = EConstraintSpace::LocalToBodyCOM;
  401. settings->mPosition1 = mLocalSpacePosition1;
  402. settings->mTwistAxis1 = mConstraintToBody1.RotateAxisX();
  403. settings->mPlaneAxis1 = mConstraintToBody1.RotateAxisZ();
  404. settings->mPosition2 = mLocalSpacePosition2;
  405. settings->mTwistAxis2 = mConstraintToBody2.RotateAxisX();
  406. settings->mPlaneAxis2 = mConstraintToBody2.RotateAxisZ();
  407. settings->mNormalHalfConeAngle = mNormalHalfConeAngle;
  408. settings->mPlaneHalfConeAngle = mPlaneHalfConeAngle;
  409. settings->mTwistMinAngle = mTwistMinAngle;
  410. settings->mTwistMaxAngle = mTwistMaxAngle;
  411. settings->mMaxFrictionTorque = mMaxFrictionTorque;
  412. settings->mSwingMotorSettings = mSwingMotorSettings;
  413. settings->mTwistMotorSettings = mTwistMotorSettings;
  414. return settings;
  415. }
  416. JPH_NAMESPACE_END