Ragdoll.cpp 25 KB

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