Ragdoll.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #include <Jolt/Physics/Ragdoll/Ragdoll.h>
  6. #include <Jolt/Physics/Constraints/SwingTwistConstraint.h>
  7. #include <Jolt/Physics/Constraints/HingeConstraint.h>
  8. #include <Jolt/Physics/PhysicsSystem.h>
  9. #include <Jolt/Physics/Body/BodyLockMulti.h>
  10. #include <Jolt/Physics/Collision/GroupFilterTable.h>
  11. #include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
  12. #include <Jolt/Physics/Collision/CollideShape.h>
  13. #include <Jolt/Physics/Collision/CollisionDispatch.h>
  14. #include <Jolt/ObjectStream/TypeDeclarations.h>
  15. #include <Jolt/Core/StreamIn.h>
  16. #include <Jolt/Core/StreamOut.h>
  17. JPH_NAMESPACE_BEGIN
  18. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(RagdollSettings::Part)
  19. {
  20. JPH_ADD_BASE_CLASS(RagdollSettings::Part, BodyCreationSettings)
  21. JPH_ADD_ATTRIBUTE(RagdollSettings::Part, mToParent)
  22. }
  23. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(RagdollSettings::AdditionalConstraint)
  24. {
  25. JPH_ADD_ATTRIBUTE(RagdollSettings::AdditionalConstraint, mBodyIdx)
  26. JPH_ADD_ATTRIBUTE(RagdollSettings::AdditionalConstraint, mConstraint)
  27. }
  28. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(RagdollSettings)
  29. {
  30. JPH_ADD_ATTRIBUTE(RagdollSettings, mSkeleton)
  31. JPH_ADD_ATTRIBUTE(RagdollSettings, mParts)
  32. JPH_ADD_ATTRIBUTE(RagdollSettings, mAdditionalConstraints)
  33. }
  34. static inline BodyInterface &sRagdollGetBodyInterface(PhysicsSystem *inSystem, bool inLockBodies)
  35. {
  36. return inLockBodies? inSystem->GetBodyInterface() : inSystem->GetBodyInterfaceNoLock();
  37. }
  38. static inline const BodyLockInterface &sRagdollGetBodyLockInterface(const PhysicsSystem *inSystem, bool inLockBodies)
  39. {
  40. return inLockBodies? static_cast<const BodyLockInterface &>(inSystem->GetBodyLockInterface()) : static_cast<const BodyLockInterface &>(inSystem->GetBodyLockInterfaceNoLock());
  41. }
  42. bool RagdollSettings::Stabilize()
  43. {
  44. // Based on: Stop my Constraints from Blowing Up! - Oliver Strunk (Havok)
  45. // Do 2 things:
  46. // 1. Limit the mass ratios between parents and children (slide 16)
  47. // 2. Increase the inertia of parents so that they're bigger or equal to the sum of their children (slide 34)
  48. // If we don't have any joints there's nothing to stabilize
  49. if (mSkeleton->GetJointCount() == 0)
  50. return true;
  51. // The skeleton can contain one or more static bodies. We can't modify the mass for those so we start a new stabilization chain for each joint under a static body until we reach the next static body.
  52. // This array keeps track of which joints have been processed.
  53. Array<bool> visited;
  54. visited.resize(mSkeleton->GetJointCount());
  55. for (size_t v = 0; v < visited.size(); ++v)
  56. {
  57. // Mark static bodies as visited so we won't process these
  58. Part &p = mParts[v];
  59. bool has_mass_properties = p.HasMassProperties();
  60. visited[v] = !has_mass_properties;
  61. if (has_mass_properties && p.mOverrideMassProperties != EOverrideMassProperties::MassAndInertiaProvided)
  62. {
  63. // Mass properties not yet calculated, do it now
  64. p.mMassPropertiesOverride = p.GetMassProperties();
  65. p.mOverrideMassProperties = EOverrideMassProperties::MassAndInertiaProvided;
  66. }
  67. }
  68. // Find first unvisited part that either has no parent or that has a parent that was visited
  69. for (int first_idx = 0; first_idx < mSkeleton->GetJointCount(); ++first_idx)
  70. {
  71. int first_idx_parent = mSkeleton->GetJoint(first_idx).mParentJointIndex;
  72. if (!visited[first_idx] && (first_idx_parent == -1 || visited[first_idx_parent]))
  73. {
  74. // Find all children of first_idx and their children up to the next static part
  75. int next_to_process = 0;
  76. Array<int> indices;
  77. indices.reserve(mSkeleton->GetJointCount());
  78. visited[first_idx] = true;
  79. indices.push_back(first_idx);
  80. do
  81. {
  82. int parent_idx = indices[next_to_process++];
  83. for (int child_idx = 0; child_idx < mSkeleton->GetJointCount(); ++child_idx)
  84. if (!visited[child_idx] && mSkeleton->GetJoint(child_idx).mParentJointIndex == parent_idx)
  85. {
  86. visited[child_idx] = true;
  87. indices.push_back(child_idx);
  88. }
  89. } while (next_to_process < (int)indices.size());
  90. // If there's only 1 body, we can't redistribute mass
  91. if (indices.size() == 1)
  92. continue;
  93. const float cMinMassRatio = 0.8f;
  94. const float cMaxMassRatio = 1.2f;
  95. // Ensure that the mass ratio from parent to child is within a range
  96. float total_mass_ratio = 1.0f;
  97. Array<float> mass_ratios;
  98. mass_ratios.resize(mSkeleton->GetJointCount());
  99. mass_ratios[indices[0]] = 1.0f;
  100. for (int i = 1; i < (int)indices.size(); ++i)
  101. {
  102. int child_idx = indices[i];
  103. int parent_idx = mSkeleton->GetJoint(child_idx).mParentJointIndex;
  104. float ratio = mParts[child_idx].mMassPropertiesOverride.mMass / mParts[parent_idx].mMassPropertiesOverride.mMass;
  105. mass_ratios[child_idx] = mass_ratios[parent_idx] * Clamp(ratio, cMinMassRatio, cMaxMassRatio);
  106. total_mass_ratio += mass_ratios[child_idx];
  107. }
  108. // Calculate total mass of this chain
  109. float total_mass = 0.0f;
  110. for (int idx : indices)
  111. total_mass += mParts[idx].mMassPropertiesOverride.mMass;
  112. // Calculate how much mass belongs to a ratio of 1
  113. float ratio_to_mass = total_mass / total_mass_ratio;
  114. // Adjust all masses and inertia tensors for the new mass
  115. for (int i : indices)
  116. {
  117. Part &p = mParts[i];
  118. float old_mass = p.mMassPropertiesOverride.mMass;
  119. float new_mass = mass_ratios[i] * ratio_to_mass;
  120. p.mMassPropertiesOverride.mMass = new_mass;
  121. p.mMassPropertiesOverride.mInertia *= new_mass / old_mass;
  122. p.mMassPropertiesOverride.mInertia.SetColumn4(3, Vec4(0, 0, 0, 1));
  123. }
  124. const float cMaxInertiaIncrease = 2.0f;
  125. // Get the principal moments of inertia for all parts
  126. struct Principal
  127. {
  128. Mat44 mRotation;
  129. Vec3 mDiagonal;
  130. float mChildSum = 0.0f;
  131. };
  132. Array<Principal> principals;
  133. principals.resize(mParts.size());
  134. for (int i : indices)
  135. if (!mParts[i].mMassPropertiesOverride.DecomposePrincipalMomentsOfInertia(principals[i].mRotation, principals[i].mDiagonal))
  136. {
  137. JPH_ASSERT(false, "Failed to decompose the inertia tensor!");
  138. return false;
  139. }
  140. // Calculate sum of child inertias
  141. // Walk backwards so we sum the leaves first
  142. for (int i = (int)indices.size() - 1; i > 0; --i)
  143. {
  144. int child_idx = indices[i];
  145. int parent_idx = mSkeleton->GetJoint(child_idx).mParentJointIndex;
  146. principals[parent_idx].mChildSum += principals[child_idx].mDiagonal[0] + principals[child_idx].mChildSum;
  147. }
  148. // Adjust inertia tensors for all parts
  149. for (int i : indices)
  150. {
  151. Part &p = mParts[i];
  152. Principal &principal = principals[i];
  153. if (principal.mChildSum != 0.0f)
  154. {
  155. // Calculate minimum inertia this object should have based on it children
  156. float minimum = min(cMaxInertiaIncrease * principal.mDiagonal[0], principal.mChildSum);
  157. principal.mDiagonal = Vec3::sMax(principal.mDiagonal, Vec3::sReplicate(minimum));
  158. // Recalculate moment of inertia in body space
  159. p.mMassPropertiesOverride.mInertia = principal.mRotation * Mat44::sScale(principal.mDiagonal) * principal.mRotation.Inversed3x3();
  160. }
  161. }
  162. }
  163. }
  164. return true;
  165. }
  166. void RagdollSettings::DisableParentChildCollisions(const Mat44 *inJointMatrices, float inMinSeparationDistance)
  167. {
  168. int joint_count = mSkeleton->GetJointCount();
  169. JPH_ASSERT(joint_count == (int)mParts.size());
  170. // Create a group filter table that disables collisions between parent and child
  171. Ref<GroupFilterTable> group_filter = new GroupFilterTable(joint_count);
  172. for (int joint_idx = 0; joint_idx < joint_count; ++joint_idx)
  173. {
  174. int parent_joint = mSkeleton->GetJoint(joint_idx).mParentJointIndex;
  175. if (parent_joint >= 0)
  176. group_filter->DisableCollision(joint_idx, parent_joint);
  177. }
  178. // If joint matrices are provided
  179. if (inJointMatrices != nullptr)
  180. {
  181. // Loop over all joints
  182. for (int j1 = 0; j1 < joint_count; ++j1)
  183. {
  184. // Shape and transform for joint 1
  185. const Part &part1 = mParts[j1];
  186. const Shape *shape1 = part1.GetShape();
  187. Vec3 scale1;
  188. Mat44 com1 = (inJointMatrices[j1].PreTranslated(shape1->GetCenterOfMass())).Decompose(scale1);
  189. // Loop over all other joints
  190. for (int j2 = j1 + 1; j2 < joint_count; ++j2)
  191. if (group_filter->IsCollisionEnabled(j1, j2)) // Only if collision is still enabled we need to test
  192. {
  193. // Shape and transform for joint 2
  194. const Part &part2 = mParts[j2];
  195. const Shape *shape2 = part2.GetShape();
  196. Vec3 scale2;
  197. Mat44 com2 = (inJointMatrices[j2].PreTranslated(shape2->GetCenterOfMass())).Decompose(scale2);
  198. // Collision settings
  199. CollideShapeSettings settings;
  200. settings.mActiveEdgeMode = EActiveEdgeMode::CollideWithAll;
  201. settings.mBackFaceMode = EBackFaceMode::CollideWithBackFaces;
  202. settings.mMaxSeparationDistance = inMinSeparationDistance;
  203. // Only check if one of the two bodies can become dynamic
  204. if (part1.HasMassProperties() || part2.HasMassProperties())
  205. {
  206. // If there is a collision, disable the collision between the joints
  207. AnyHitCollisionCollector<CollideShapeCollector> collector;
  208. if (part1.HasMassProperties()) // Ensure that the first shape is always a dynamic one (we can't check mesh vs convex but we can check convex vs mesh)
  209. CollisionDispatch::sCollideShapeVsShape(shape1, shape2, scale1, scale2, com1, com2, SubShapeIDCreator(), SubShapeIDCreator(), settings, collector);
  210. else
  211. CollisionDispatch::sCollideShapeVsShape(shape2, shape1, scale2, scale1, com2, com1, SubShapeIDCreator(), SubShapeIDCreator(), settings, collector);
  212. if (collector.HadHit())
  213. group_filter->DisableCollision(j1, j2);
  214. }
  215. }
  216. }
  217. }
  218. // Loop over the body parts and assign them a sub group ID and the group filter
  219. for (int joint_idx = 0; joint_idx < joint_count; ++joint_idx)
  220. {
  221. Part &part = mParts[joint_idx];
  222. part.mCollisionGroup.SetSubGroupID(joint_idx);
  223. part.mCollisionGroup.SetGroupFilter(group_filter);
  224. }
  225. }
  226. void RagdollSettings::SaveBinaryState(StreamOut &inStream, bool inSaveShapes, bool inSaveGroupFilter) const
  227. {
  228. BodyCreationSettings::ShapeToIDMap shape_to_id;
  229. BodyCreationSettings::MaterialToIDMap material_to_id;
  230. BodyCreationSettings::GroupFilterToIDMap group_filter_to_id;
  231. // Save skeleton
  232. mSkeleton->SaveBinaryState(inStream);
  233. // Save parts
  234. inStream.Write((uint32)mParts.size());
  235. for (const Part &p : mParts)
  236. {
  237. // Write body creation settings
  238. p.SaveWithChildren(inStream, inSaveShapes? &shape_to_id : nullptr, inSaveShapes? &material_to_id : nullptr, inSaveGroupFilter? &group_filter_to_id : nullptr);
  239. // Save constraint
  240. inStream.Write(p.mToParent != nullptr);
  241. if (p.mToParent != nullptr)
  242. p.mToParent->SaveBinaryState(inStream);
  243. }
  244. // Save additional constraints
  245. inStream.Write((uint32)mAdditionalConstraints.size());
  246. for (const AdditionalConstraint &c : mAdditionalConstraints)
  247. {
  248. // Save bodies indices
  249. inStream.Write(c.mBodyIdx);
  250. // Save constraint
  251. c.mConstraint->SaveBinaryState(inStream);
  252. }
  253. }
  254. RagdollSettings::RagdollResult RagdollSettings::sRestoreFromBinaryState(StreamIn &inStream)
  255. {
  256. RagdollResult result;
  257. // Restore skeleton
  258. Skeleton::SkeletonResult skeleton_result = Skeleton::sRestoreFromBinaryState(inStream);
  259. if (skeleton_result.HasError())
  260. {
  261. result.SetError(skeleton_result.GetError());
  262. return result;
  263. }
  264. // Create ragdoll
  265. Ref<RagdollSettings> ragdoll = new RagdollSettings();
  266. ragdoll->mSkeleton = skeleton_result.Get();
  267. BodyCreationSettings::IDToShapeMap id_to_shape;
  268. BodyCreationSettings::IDToMaterialMap id_to_material;
  269. BodyCreationSettings::IDToGroupFilterMap id_to_group_filter;
  270. // Reserve some memory to avoid frequent reallocations
  271. id_to_shape.reserve(1024);
  272. id_to_material.reserve(128);
  273. id_to_group_filter.reserve(128);
  274. // Read parts
  275. uint32 len = 0;
  276. inStream.Read(len);
  277. ragdoll->mParts.resize(len);
  278. for (Part &p : ragdoll->mParts)
  279. {
  280. // Read creation settings
  281. BodyCreationSettings::BCSResult bcs_result = BodyCreationSettings::sRestoreWithChildren(inStream, id_to_shape, id_to_material, id_to_group_filter);
  282. if (bcs_result.HasError())
  283. {
  284. result.SetError(bcs_result.GetError());
  285. return result;
  286. }
  287. static_cast<BodyCreationSettings &>(p) = bcs_result.Get();
  288. // Read constraint
  289. bool has_constraint = false;
  290. inStream.Read(has_constraint);
  291. if (has_constraint)
  292. {
  293. ConstraintSettings::ConstraintResult constraint_result = ConstraintSettings::sRestoreFromBinaryState(inStream);
  294. if (constraint_result.HasError())
  295. {
  296. result.SetError(constraint_result.GetError());
  297. return result;
  298. }
  299. p.mToParent = DynamicCast<TwoBodyConstraintSettings>(constraint_result.Get());
  300. }
  301. }
  302. // Read additional constraints
  303. len = 0;
  304. inStream.Read(len);
  305. ragdoll->mAdditionalConstraints.resize(len);
  306. for (AdditionalConstraint &c : ragdoll->mAdditionalConstraints)
  307. {
  308. // Read body indices
  309. inStream.Read(c.mBodyIdx);
  310. // Read constraint
  311. ConstraintSettings::ConstraintResult constraint_result = ConstraintSettings::sRestoreFromBinaryState(inStream);
  312. if (constraint_result.HasError())
  313. {
  314. result.SetError(constraint_result.GetError());
  315. return result;
  316. }
  317. c.mConstraint = DynamicCast<TwoBodyConstraintSettings>(constraint_result.Get());
  318. }
  319. // Create mapping tables
  320. ragdoll->CalculateBodyIndexToConstraintIndex();
  321. ragdoll->CalculateConstraintIndexToBodyIdxPair();
  322. result.Set(ragdoll);
  323. return result;
  324. }
  325. Ragdoll *RagdollSettings::CreateRagdoll(CollisionGroup::GroupID inCollisionGroup, uint64 inUserData, PhysicsSystem *inSystem) const
  326. {
  327. Ragdoll *r = new Ragdoll(inSystem);
  328. r->mRagdollSettings = this;
  329. r->mBodyIDs.reserve(mParts.size());
  330. r->mConstraints.reserve(mParts.size() + mAdditionalConstraints.size());
  331. // Create bodies and constraints
  332. BodyInterface &bi = inSystem->GetBodyInterface();
  333. Body **bodies = (Body **)JPH_STACK_ALLOC(mParts.size() * sizeof(Body *));
  334. int joint_idx = 0;
  335. for (const Part &p : mParts)
  336. {
  337. Body *body2 = bi.CreateBody(p);
  338. if (body2 == nullptr)
  339. {
  340. // Out of bodies, failed to create ragdoll
  341. delete r;
  342. return nullptr;
  343. }
  344. body2->GetCollisionGroup().SetGroupID(inCollisionGroup);
  345. body2->SetUserData(inUserData);
  346. // Temporarily store body pointer for hooking up constraints
  347. bodies[joint_idx] = body2;
  348. // Create constraint
  349. if (p.mToParent != nullptr)
  350. {
  351. Body *body1 = bodies[mSkeleton->GetJoint(joint_idx).mParentJointIndex];
  352. r->mConstraints.push_back(p.mToParent->Create(*body1, *body2));
  353. }
  354. // Store body ID and constraint in parallel arrays
  355. r->mBodyIDs.push_back(body2->GetID());
  356. ++joint_idx;
  357. }
  358. // Add additional constraints
  359. for (const AdditionalConstraint &c : mAdditionalConstraints)
  360. {
  361. Body *body1 = bodies[c.mBodyIdx[0]];
  362. Body *body2 = bodies[c.mBodyIdx[1]];
  363. r->mConstraints.push_back(c.mConstraint->Create(*body1, *body2));
  364. }
  365. return r;
  366. }
  367. void RagdollSettings::CalculateBodyIndexToConstraintIndex()
  368. {
  369. mBodyIndexToConstraintIndex.clear();
  370. mBodyIndexToConstraintIndex.reserve(mParts.size());
  371. int constraint_index = 0;
  372. for (const Part &p : mParts)
  373. {
  374. if (p.mToParent != nullptr)
  375. mBodyIndexToConstraintIndex.push_back(constraint_index++);
  376. else
  377. mBodyIndexToConstraintIndex.push_back(-1);
  378. }
  379. }
  380. void RagdollSettings::CalculateConstraintIndexToBodyIdxPair()
  381. {
  382. mConstraintIndexToBodyIdxPair.clear();
  383. mConstraintIndexToBodyIdxPair.reserve(mParts.size() + mAdditionalConstraints.size());
  384. // Add constraints between parts
  385. int joint_idx = 0;
  386. for (const Part &p : mParts)
  387. {
  388. if (p.mToParent != nullptr)
  389. {
  390. int parent_joint_idx = mSkeleton->GetJoint(joint_idx).mParentJointIndex;
  391. mConstraintIndexToBodyIdxPair.emplace_back(parent_joint_idx, joint_idx);
  392. }
  393. ++joint_idx;
  394. }
  395. // Add additional constraints
  396. for (const AdditionalConstraint &c : mAdditionalConstraints)
  397. mConstraintIndexToBodyIdxPair.emplace_back(c.mBodyIdx[0], c.mBodyIdx[1]);
  398. }
  399. Ragdoll::~Ragdoll()
  400. {
  401. // Destroy all bodies
  402. mSystem->GetBodyInterface().DestroyBodies(mBodyIDs.data(), (int)mBodyIDs.size());
  403. }
  404. void Ragdoll::AddToPhysicsSystem(EActivation inActivationMode, bool inLockBodies)
  405. {
  406. // Scope for JPH_STACK_ALLOC
  407. {
  408. // Create copy of body ids since they will be shuffled
  409. int num_bodies = (int)mBodyIDs.size();
  410. BodyID *bodies = (BodyID *)JPH_STACK_ALLOC(num_bodies * sizeof(BodyID));
  411. memcpy(bodies, mBodyIDs.data(), num_bodies * sizeof(BodyID));
  412. // Insert bodies as a batch
  413. BodyInterface &bi = sRagdollGetBodyInterface(mSystem, inLockBodies);
  414. BodyInterface::AddState add_state = bi.AddBodiesPrepare(bodies, num_bodies);
  415. bi.AddBodiesFinalize(bodies, num_bodies, add_state, inActivationMode);
  416. }
  417. // Add all constraints
  418. mSystem->AddConstraints((Constraint **)mConstraints.data(), (int)mConstraints.size());
  419. }
  420. void Ragdoll::RemoveFromPhysicsSystem(bool inLockBodies)
  421. {
  422. // Remove all constraints before removing the bodies
  423. mSystem->RemoveConstraints((Constraint **)mConstraints.data(), (int)mConstraints.size());
  424. // Scope for JPH_STACK_ALLOC
  425. {
  426. // Create copy of body ids since they will be shuffled
  427. int num_bodies = (int)mBodyIDs.size();
  428. BodyID *bodies = (BodyID *)JPH_STACK_ALLOC(num_bodies * sizeof(BodyID));
  429. memcpy(bodies, mBodyIDs.data(), num_bodies * sizeof(BodyID));
  430. // Remove all bodies as a batch
  431. sRagdollGetBodyInterface(mSystem, inLockBodies).RemoveBodies(bodies, num_bodies);
  432. }
  433. }
  434. void Ragdoll::Activate(bool inLockBodies)
  435. {
  436. sRagdollGetBodyInterface(mSystem, inLockBodies).ActivateBodies(mBodyIDs.data(), (int)mBodyIDs.size());
  437. }
  438. bool Ragdoll::IsActive(bool inLockBodies) const
  439. {
  440. // Lock the bodies
  441. int body_count = (int)mBodyIDs.size();
  442. BodyLockMultiRead lock(sRagdollGetBodyLockInterface(mSystem, inLockBodies), mBodyIDs.data(), body_count);
  443. // Test if any body is active
  444. for (int b = 0; b < body_count; ++b)
  445. {
  446. const Body *body = lock.GetBody(b);
  447. if (body->IsActive())
  448. return true;
  449. }
  450. return false;
  451. }
  452. void Ragdoll::SetGroupID(CollisionGroup::GroupID inGroupID, bool inLockBodies)
  453. {
  454. // Lock the bodies
  455. int body_count = (int)mBodyIDs.size();
  456. BodyLockMultiWrite lock(sRagdollGetBodyLockInterface(mSystem, inLockBodies), mBodyIDs.data(), body_count);
  457. // Update group ID
  458. for (int b = 0; b < body_count; ++b)
  459. {
  460. Body *body = lock.GetBody(b);
  461. body->GetCollisionGroup().SetGroupID(inGroupID);
  462. }
  463. }
  464. void Ragdoll::SetPose(const SkeletonPose &inPose, bool inLockBodies)
  465. {
  466. JPH_ASSERT(inPose.GetSkeleton() == mRagdollSettings->mSkeleton);
  467. SetPose(inPose.GetRootOffset(), inPose.GetJointMatrices().data(), inLockBodies);
  468. }
  469. void Ragdoll::SetPose(RVec3Arg inRootOffset, const Mat44 *inJointMatrices, bool inLockBodies)
  470. {
  471. // Move bodies instantly into the correct position
  472. BodyInterface &bi = sRagdollGetBodyInterface(mSystem, inLockBodies);
  473. for (int i = 0; i < (int)mBodyIDs.size(); ++i)
  474. {
  475. const Mat44 &joint = inJointMatrices[i];
  476. bi.SetPositionAndRotation(mBodyIDs[i], inRootOffset + joint.GetTranslation(), joint.GetQuaternion(), EActivation::DontActivate);
  477. }
  478. }
  479. void Ragdoll::GetPose(SkeletonPose &outPose, bool inLockBodies)
  480. {
  481. JPH_ASSERT(outPose.GetSkeleton() == mRagdollSettings->mSkeleton);
  482. RVec3 root_offset;
  483. GetPose(root_offset, outPose.GetJointMatrices().data(), inLockBodies);
  484. outPose.SetRootOffset(root_offset);
  485. }
  486. void Ragdoll::GetPose(RVec3 &outRootOffset, Mat44 *outJointMatrices, bool inLockBodies)
  487. {
  488. // Lock the bodies
  489. int body_count = (int)mBodyIDs.size();
  490. if (body_count == 0)
  491. return;
  492. BodyLockMultiRead lock(sRagdollGetBodyLockInterface(mSystem, inLockBodies), mBodyIDs.data(), body_count);
  493. // Get root matrix
  494. const Body *root = lock.GetBody(0);
  495. RMat44 root_transform = root->GetWorldTransform();
  496. outRootOffset = root_transform.GetTranslation();
  497. outJointMatrices[0] = Mat44(root_transform.GetColumn4(0), root_transform.GetColumn4(1), root_transform.GetColumn4(2), Vec4(0, 0, 0, 1));
  498. // Get other matrices
  499. for (int b = 1; b < body_count; ++b)
  500. {
  501. const Body *body = lock.GetBody(b);
  502. RMat44 transform = body->GetWorldTransform();
  503. outJointMatrices[b] = Mat44(transform.GetColumn4(0), transform.GetColumn4(1), transform.GetColumn4(2), Vec4(Vec3(transform.GetTranslation() - outRootOffset), 1));
  504. }
  505. }
  506. void Ragdoll::ResetWarmStart()
  507. {
  508. for (TwoBodyConstraint *c : mConstraints)
  509. c->ResetWarmStart();
  510. }
  511. void Ragdoll::DriveToPoseUsingKinematics(const SkeletonPose &inPose, float inDeltaTime, bool inLockBodies)
  512. {
  513. JPH_ASSERT(inPose.GetSkeleton() == mRagdollSettings->mSkeleton);
  514. DriveToPoseUsingKinematics(inPose.GetRootOffset(), inPose.GetJointMatrices().data(), inDeltaTime, inLockBodies);
  515. }
  516. void Ragdoll::DriveToPoseUsingKinematics(RVec3Arg inRootOffset, const Mat44 *inJointMatrices, float inDeltaTime, bool inLockBodies)
  517. {
  518. // Move bodies into the correct position using kinematics
  519. BodyInterface &bi = sRagdollGetBodyInterface(mSystem, inLockBodies);
  520. for (int i = 0; i < (int)mBodyIDs.size(); ++i)
  521. {
  522. const Mat44 &joint = inJointMatrices[i];
  523. bi.MoveKinematic(mBodyIDs[i], inRootOffset + joint.GetTranslation(), joint.GetQuaternion(), inDeltaTime);
  524. }
  525. }
  526. void Ragdoll::DriveToPoseUsingMotors(const SkeletonPose &inPose)
  527. {
  528. JPH_ASSERT(inPose.GetSkeleton() == mRagdollSettings->mSkeleton);
  529. // Move bodies into the correct position using constraints
  530. for (int i = 0; i < (int)inPose.GetJointMatrices().size(); ++i)
  531. {
  532. int constraint_idx = mRagdollSettings->GetConstraintIndexForBodyIndex(i);
  533. if (constraint_idx >= 0)
  534. {
  535. // Get desired rotation of this body relative to its parent
  536. const SkeletalAnimation::JointState &joint_state = inPose.GetJoint(i);
  537. // Drive constraint to target
  538. TwoBodyConstraint *constraint = mConstraints[constraint_idx];
  539. EConstraintSubType sub_type = constraint->GetSubType();
  540. if (sub_type == EConstraintSubType::SwingTwist)
  541. {
  542. SwingTwistConstraint *st_constraint = static_cast<SwingTwistConstraint *>(constraint);
  543. st_constraint->SetSwingMotorState(EMotorState::Position);
  544. st_constraint->SetTwistMotorState(EMotorState::Position);
  545. st_constraint->SetTargetOrientationBS(joint_state.mRotation);
  546. }
  547. else if (sub_type == EConstraintSubType::Hinge)
  548. {
  549. HingeConstraint *h_constraint = static_cast<HingeConstraint *>(constraint);
  550. h_constraint->SetMotorState(EMotorState::Position);
  551. h_constraint->SetTargetOrientationBS(joint_state.mRotation);
  552. }
  553. else
  554. JPH_ASSERT(false, "Constraint type not implemented!");
  555. }
  556. }
  557. }
  558. void Ragdoll::SetLinearAndAngularVelocity(Vec3Arg inLinearVelocity, Vec3Arg inAngularVelocity, bool inLockBodies)
  559. {
  560. BodyInterface &bi = sRagdollGetBodyInterface(mSystem, inLockBodies);
  561. for (BodyID body_id : mBodyIDs)
  562. bi.SetLinearAndAngularVelocity(body_id, inLinearVelocity, inAngularVelocity);
  563. }
  564. void Ragdoll::SetLinearVelocity(Vec3Arg inLinearVelocity, bool inLockBodies)
  565. {
  566. BodyInterface &bi = sRagdollGetBodyInterface(mSystem, inLockBodies);
  567. for (BodyID body_id : mBodyIDs)
  568. bi.SetLinearVelocity(body_id, inLinearVelocity);
  569. }
  570. void Ragdoll::AddLinearVelocity(Vec3Arg inLinearVelocity, bool inLockBodies)
  571. {
  572. BodyInterface &bi = sRagdollGetBodyInterface(mSystem, inLockBodies);
  573. for (BodyID body_id : mBodyIDs)
  574. bi.AddLinearVelocity(body_id, inLinearVelocity);
  575. }
  576. void Ragdoll::AddImpulse(Vec3Arg inImpulse, bool inLockBodies)
  577. {
  578. BodyInterface &bi = sRagdollGetBodyInterface(mSystem, inLockBodies);
  579. for (BodyID body_id : mBodyIDs)
  580. bi.AddImpulse(body_id, inImpulse);
  581. }
  582. void Ragdoll::GetRootTransform(RVec3 &outPosition, Quat &outRotation, bool inLockBodies) const
  583. {
  584. BodyLockRead lock(sRagdollGetBodyLockInterface(mSystem, inLockBodies), mBodyIDs[0]);
  585. if (lock.Succeeded())
  586. {
  587. const Body &body = lock.GetBody();
  588. outPosition = body.GetPosition();
  589. outRotation = body.GetRotation();
  590. }
  591. else
  592. {
  593. outPosition = RVec3::sZero();
  594. outRotation = Quat::sIdentity();
  595. }
  596. }
  597. AABox Ragdoll::GetWorldSpaceBounds(bool inLockBodies) const
  598. {
  599. // Lock the bodies
  600. int body_count = (int)mBodyIDs.size();
  601. BodyLockMultiRead lock(sRagdollGetBodyLockInterface(mSystem, inLockBodies), mBodyIDs.data(), body_count);
  602. // Encapsulate all bodies
  603. AABox bounds;
  604. for (int b = 0; b < body_count; ++b)
  605. {
  606. const Body *body = lock.GetBody(b);
  607. if (body != nullptr)
  608. bounds.Encapsulate(body->GetWorldSpaceBounds());
  609. }
  610. return bounds;
  611. }
  612. JPH_NAMESPACE_END