SoftBodyMotionProperties.cpp 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2023 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #include <Jolt/Physics/SoftBody/SoftBodyMotionProperties.h>
  6. #include <Jolt/Physics/SoftBody/SoftBodyCreationSettings.h>
  7. #include <Jolt/Physics/SoftBody/SoftBodyContactListener.h>
  8. #include <Jolt/Physics/SoftBody/SoftBodyManifold.h>
  9. #include <Jolt/Physics/Collision/CollideSoftBodyVertexIterator.h>
  10. #include <Jolt/Physics/PhysicsSystem.h>
  11. #include <Jolt/Physics/Body/BodyManager.h>
  12. #include <Jolt/Core/ScopeExit.h>
  13. #ifdef JPH_DEBUG_RENDERER
  14. #include <Jolt/Renderer/DebugRenderer.h>
  15. #endif // JPH_DEBUG_RENDERER
  16. JPH_NAMESPACE_BEGIN
  17. using namespace JPH::literals;
  18. void SoftBodyMotionProperties::CalculateMassAndInertia()
  19. {
  20. MassProperties mp;
  21. for (const Vertex &v : mVertices)
  22. if (v.mInvMass > 0.0f)
  23. {
  24. Vec3 pos = v.mPosition;
  25. // Accumulate mass
  26. float mass = 1.0f / v.mInvMass;
  27. mp.mMass += mass;
  28. // Inertia tensor, diagonal
  29. // See equations https://en.wikipedia.org/wiki/Moment_of_inertia section 'Inertia Tensor'
  30. for (int i = 0; i < 3; ++i)
  31. mp.mInertia(i, i) += mass * (Square(pos[(i + 1) % 3]) + Square(pos[(i + 2) % 3]));
  32. // Inertia tensor off diagonal
  33. for (int i = 0; i < 3; ++i)
  34. for (int j = 0; j < 3; ++j)
  35. if (i != j)
  36. mp.mInertia(i, j) -= mass * pos[i] * pos[j];
  37. }
  38. else
  39. {
  40. // If one vertex is kinematic, the entire body will have infinite mass and inertia
  41. SetInverseMass(0.0f);
  42. SetInverseInertia(Vec3::sZero(), Quat::sIdentity());
  43. return;
  44. }
  45. SetMassProperties(EAllowedDOFs::All, mp);
  46. }
  47. void SoftBodyMotionProperties::Initialize(const SoftBodyCreationSettings &inSettings)
  48. {
  49. // Store settings
  50. mSettings = inSettings.mSettings;
  51. mNumIterations = inSettings.mNumIterations;
  52. mPressure = inSettings.mPressure;
  53. mUpdatePosition = inSettings.mUpdatePosition;
  54. // Initialize vertices
  55. mVertices.resize(inSettings.mSettings->mVertices.size());
  56. Mat44 rotation = inSettings.mMakeRotationIdentity? Mat44::sRotation(inSettings.mRotation) : Mat44::sIdentity();
  57. for (Array<Vertex>::size_type v = 0, s = mVertices.size(); v < s; ++v)
  58. {
  59. const SoftBodySharedSettings::Vertex &in_vertex = inSettings.mSettings->mVertices[v];
  60. Vertex &out_vertex = mVertices[v];
  61. out_vertex.mPreviousPosition = out_vertex.mPosition = rotation * Vec3(in_vertex.mPosition);
  62. out_vertex.mVelocity = rotation.Multiply3x3(Vec3(in_vertex.mVelocity));
  63. out_vertex.ResetCollision();
  64. out_vertex.mInvMass = in_vertex.mInvMass;
  65. mLocalBounds.Encapsulate(out_vertex.mPosition);
  66. }
  67. // Allocate space for skinned vertices
  68. if (!inSettings.mSettings->mSkinnedConstraints.empty())
  69. mSkinState.resize(mVertices.size());
  70. // We don't know delta time yet, so we can't predict the bounds and use the local bounds as the predicted bounds
  71. mLocalPredictedBounds = mLocalBounds;
  72. CalculateMassAndInertia();
  73. }
  74. float SoftBodyMotionProperties::GetVolumeTimesSix() const
  75. {
  76. float six_volume = 0.0f;
  77. for (const Face &f : mSettings->mFaces)
  78. {
  79. Vec3 x1 = mVertices[f.mVertex[0]].mPosition;
  80. Vec3 x2 = mVertices[f.mVertex[1]].mPosition;
  81. Vec3 x3 = mVertices[f.mVertex[2]].mPosition;
  82. six_volume += x1.Cross(x2).Dot(x3); // We pick zero as the origin as this is the center of the bounding box so should give good accuracy
  83. }
  84. return six_volume;
  85. }
  86. void SoftBodyMotionProperties::DetermineCollidingShapes(const SoftBodyUpdateContext &inContext, const PhysicsSystem &inSystem, const BodyLockInterface &inBodyLockInterface)
  87. {
  88. JPH_PROFILE_FUNCTION();
  89. // Reset flag prior to collision detection
  90. mNeedContactCallback = false;
  91. struct Collector : public CollideShapeBodyCollector
  92. {
  93. Collector(const SoftBodyUpdateContext &inContext, const PhysicsSystem &inSystem, const BodyLockInterface &inBodyLockInterface, Array<CollidingShape> &ioHits, Array<CollidingSensor> &ioSensors) :
  94. mContext(inContext),
  95. mInverseTransform(inContext.mCenterOfMassTransform.InversedRotationTranslation()),
  96. mBodyLockInterface(inBodyLockInterface),
  97. mCombineFriction(inSystem.GetCombineFriction()),
  98. mCombineRestitution(inSystem.GetCombineRestitution()),
  99. mHits(ioHits),
  100. mSensors(ioSensors)
  101. {
  102. }
  103. virtual void AddHit(const BodyID &inResult) override
  104. {
  105. BodyLockRead lock(mBodyLockInterface, inResult);
  106. if (lock.Succeeded())
  107. {
  108. const Body &soft_body = *mContext.mBody;
  109. const Body &body = lock.GetBody();
  110. if (body.IsRigidBody() // TODO: We should support soft body vs soft body
  111. && soft_body.GetCollisionGroup().CanCollide(body.GetCollisionGroup()))
  112. {
  113. SoftBodyContactSettings settings;
  114. settings.mIsSensor = body.IsSensor();
  115. if (mContext.mContactListener == nullptr)
  116. {
  117. // If we have no contact listener, we can ignore sensors
  118. if (settings.mIsSensor)
  119. return;
  120. }
  121. else
  122. {
  123. // Call the contact listener to see if we should accept this contact
  124. if (mContext.mContactListener->OnSoftBodyContactValidate(soft_body, body, settings) != SoftBodyValidateResult::AcceptContact)
  125. return;
  126. // Check if there will be any interaction
  127. if (!settings.mIsSensor
  128. && settings.mInvMassScale1 == 0.0f
  129. && (body.GetMotionType() != EMotionType::Dynamic || settings.mInvMassScale2 == 0.0f))
  130. return;
  131. }
  132. Mat44 com = (mInverseTransform * body.GetCenterOfMassTransform()).ToMat44();
  133. if (settings.mIsSensor)
  134. {
  135. CollidingSensor cs;
  136. cs.mCenterOfMassTransform = com;
  137. cs.mShape = body.GetShape();
  138. cs.mBodyID = inResult;
  139. mSensors.push_back(cs);
  140. }
  141. else
  142. {
  143. CollidingShape cs;
  144. cs.mCenterOfMassTransform = com;
  145. cs.mShape = body.GetShape();
  146. cs.mBodyID = inResult;
  147. cs.mMotionType = body.GetMotionType();
  148. cs.mUpdateVelocities = false;
  149. cs.mFriction = mCombineFriction(soft_body, SubShapeID(), body, SubShapeID());
  150. cs.mRestitution = mCombineRestitution(soft_body, SubShapeID(), body, SubShapeID());
  151. cs.mSoftBodyInvMassScale = settings.mInvMassScale1;
  152. if (cs.mMotionType == EMotionType::Dynamic)
  153. {
  154. const MotionProperties *mp = body.GetMotionProperties();
  155. cs.mInvMass = settings.mInvMassScale2 * mp->GetInverseMass();
  156. cs.mInvInertia = settings.mInvInertiaScale2 * mp->GetInverseInertiaForRotation(cs.mCenterOfMassTransform.GetRotation());
  157. cs.mOriginalLinearVelocity = cs.mLinearVelocity = mInverseTransform.Multiply3x3(mp->GetLinearVelocity());
  158. cs.mOriginalAngularVelocity = cs.mAngularVelocity = mInverseTransform.Multiply3x3(mp->GetAngularVelocity());
  159. }
  160. mHits.push_back(cs);
  161. }
  162. }
  163. }
  164. }
  165. private:
  166. const SoftBodyUpdateContext &mContext;
  167. RMat44 mInverseTransform;
  168. const BodyLockInterface & mBodyLockInterface;
  169. ContactConstraintManager::CombineFunction mCombineFriction;
  170. ContactConstraintManager::CombineFunction mCombineRestitution;
  171. Array<CollidingShape> & mHits;
  172. Array<CollidingSensor> & mSensors;
  173. };
  174. Collector collector(inContext, inSystem, inBodyLockInterface, mCollidingShapes, mCollidingSensors);
  175. AABox bounds = mLocalBounds;
  176. bounds.Encapsulate(mLocalPredictedBounds);
  177. bounds = bounds.Transformed(inContext.mCenterOfMassTransform);
  178. bounds.ExpandBy(Vec3::sReplicate(mSettings->mVertexRadius));
  179. ObjectLayer layer = inContext.mBody->GetObjectLayer();
  180. DefaultBroadPhaseLayerFilter broadphase_layer_filter = inSystem.GetDefaultBroadPhaseLayerFilter(layer);
  181. DefaultObjectLayerFilter object_layer_filter = inSystem.GetDefaultLayerFilter(layer);
  182. inSystem.GetBroadPhaseQuery().CollideAABox(bounds, collector, broadphase_layer_filter, object_layer_filter);
  183. }
  184. void SoftBodyMotionProperties::DetermineCollisionPlanes(uint inVertexStart, uint inNumVertices)
  185. {
  186. JPH_PROFILE_FUNCTION();
  187. // Generate collision planes
  188. for (const CollidingShape &cs : mCollidingShapes)
  189. cs.mShape->CollideSoftBodyVertices(cs.mCenterOfMassTransform, Vec3::sReplicate(1.0f), CollideSoftBodyVertexIterator(mVertices.data() + inVertexStart), inNumVertices, int(&cs - mCollidingShapes.data()));
  190. }
  191. void SoftBodyMotionProperties::DetermineSensorCollisions(CollidingSensor &ioSensor)
  192. {
  193. JPH_PROFILE_FUNCTION();
  194. Plane collision_plane;
  195. float largest_penetration = -FLT_MAX;
  196. int colliding_shape_idx = -1;
  197. // Collide sensor against all vertices
  198. CollideSoftBodyVertexIterator vertex_iterator(
  199. StridedPtr<const Vec3>(&mVertices[0].mPosition, sizeof(SoftBodyVertex)), // The position and mass come from the soft body vertex
  200. StridedPtr<const float>(&mVertices[0].mInvMass, sizeof(SoftBodyVertex)),
  201. StridedPtr<Plane>(&collision_plane, 0), // We want all vertices to result in a single collision so we pass stride 0
  202. StridedPtr<float>(&largest_penetration, 0),
  203. StridedPtr<int>(&colliding_shape_idx, 0));
  204. ioSensor.mShape->CollideSoftBodyVertices(ioSensor.mCenterOfMassTransform, Vec3::sReplicate(1.0f), vertex_iterator, uint(mVertices.size()), 0);
  205. ioSensor.mHasContact = largest_penetration > 0.0f;
  206. // We need a contact callback if one of the sensors collided
  207. if (ioSensor.mHasContact)
  208. mNeedContactCallback = true;
  209. }
  210. void SoftBodyMotionProperties::ApplyPressure(const SoftBodyUpdateContext &inContext)
  211. {
  212. JPH_PROFILE_FUNCTION();
  213. float dt = inContext.mSubStepDeltaTime;
  214. float pressure_coefficient = mPressure;
  215. if (pressure_coefficient > 0.0f)
  216. {
  217. // Calculate total volume
  218. float six_volume = GetVolumeTimesSix();
  219. if (six_volume > 0.0f)
  220. {
  221. // Apply pressure
  222. // p = F / A = n R T / V (see https://en.wikipedia.org/wiki/Pressure)
  223. // Our pressure coefficient is n R T so the impulse is:
  224. // P = F dt = pressure_coefficient / V * A * dt
  225. float coefficient = pressure_coefficient * dt / six_volume; // Need to still multiply by 6 for the volume
  226. for (const Face &f : mSettings->mFaces)
  227. {
  228. Vec3 x1 = mVertices[f.mVertex[0]].mPosition;
  229. Vec3 x2 = mVertices[f.mVertex[1]].mPosition;
  230. Vec3 x3 = mVertices[f.mVertex[2]].mPosition;
  231. Vec3 impulse = coefficient * (x2 - x1).Cross(x3 - x1); // Area is half the cross product so need to still divide by 2
  232. for (uint32 i : f.mVertex)
  233. {
  234. Vertex &v = mVertices[i];
  235. v.mVelocity += v.mInvMass * impulse; // Want to divide by 3 because we spread over 3 vertices
  236. }
  237. }
  238. }
  239. }
  240. }
  241. void SoftBodyMotionProperties::IntegratePositions(const SoftBodyUpdateContext &inContext)
  242. {
  243. JPH_PROFILE_FUNCTION();
  244. float dt = inContext.mSubStepDeltaTime;
  245. float linear_damping = max(0.0f, 1.0f - GetLinearDamping() * dt); // See: MotionProperties::ApplyForceTorqueAndDragInternal
  246. // Integrate
  247. Vec3 sub_step_gravity = inContext.mGravity * dt;
  248. Vec3 sub_step_impulse = GetAccumulatedForce() * dt;
  249. for (Vertex &v : mVertices)
  250. if (v.mInvMass > 0.0f)
  251. {
  252. // Gravity
  253. v.mVelocity += sub_step_gravity + sub_step_impulse * v.mInvMass;
  254. // Damping
  255. v.mVelocity *= linear_damping;
  256. // Integrate
  257. v.mPreviousPosition = v.mPosition;
  258. v.mPosition += v.mVelocity * dt;
  259. }
  260. else
  261. {
  262. // Integrate
  263. v.mPreviousPosition = v.mPosition;
  264. v.mPosition += v.mVelocity * dt;
  265. }
  266. }
  267. void SoftBodyMotionProperties::ApplyDihedralBendConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex)
  268. {
  269. JPH_PROFILE_FUNCTION();
  270. float inv_dt_sq = 1.0f / Square(inContext.mSubStepDeltaTime);
  271. for (const DihedralBend *b = mSettings->mDihedralBendConstraints.data() + inStartIndex, *b_end = mSettings->mDihedralBendConstraints.data() + inEndIndex; b < b_end; ++b)
  272. {
  273. Vertex &v0 = mVertices[b->mVertex[0]];
  274. Vertex &v1 = mVertices[b->mVertex[1]];
  275. Vertex &v2 = mVertices[b->mVertex[2]];
  276. Vertex &v3 = mVertices[b->mVertex[3]];
  277. // Get positions
  278. Vec3 x0 = v0.mPosition;
  279. Vec3 x1 = v1.mPosition;
  280. Vec3 x2 = v2.mPosition;
  281. Vec3 x3 = v3.mPosition;
  282. /*
  283. x2
  284. e1/ \e3
  285. / \
  286. x0----x1
  287. \ e0 /
  288. e2\ /e4
  289. x3
  290. */
  291. // Calculate the shared edge of the triangles
  292. Vec3 e = x1 - x0;
  293. float e_len = e.Length();
  294. if (e_len < 1.0e-6f)
  295. continue;
  296. // Calculate the normals of the triangles
  297. Vec3 x1x2 = x2 - x1;
  298. Vec3 x1x3 = x3 - x1;
  299. Vec3 n1 = (x2 - x0).Cross(x1x2);
  300. Vec3 n2 = x1x3.Cross(x3 - x0);
  301. float n1_len_sq = n1.LengthSq();
  302. float n2_len_sq = n2.LengthSq();
  303. float n1_len_sq_n2_len_sq = n1_len_sq * n2_len_sq;
  304. if (n1_len_sq_n2_len_sq < 1.0e-24f)
  305. continue;
  306. // Calculate constraint equation
  307. // As per "Strain Based Dynamics" Appendix A we need to negate the gradients when (n1 x n2) . e > 0, instead we make sure that the sign of the constraint equation is correct
  308. float sign = Sign(n2.Cross(n1).Dot(e));
  309. float d = n1.Dot(n2) / sqrt(n1_len_sq_n2_len_sq);
  310. float c = sign * ACosApproximate(d) - b->mInitialAngle;
  311. // Ensure the range is -PI to PI
  312. if (c > JPH_PI)
  313. c -= 2.0f * JPH_PI;
  314. else if (c < -JPH_PI)
  315. c += 2.0f * JPH_PI;
  316. // Calculate gradient of constraint equation
  317. // Taken from "Strain Based Dynamics" - Matthias Muller et al. (Appendix A)
  318. // with p1 = x2, p2 = x3, p3 = x0 and p4 = x1
  319. // which in turn is based on "Simulation of Clothing with Folds and Wrinkles" - R. Bridson et al. (Section 4)
  320. n1 /= n1_len_sq;
  321. n2 /= n2_len_sq;
  322. Vec3 d0c = (x1x2.Dot(e) * n1 + x1x3.Dot(e) * n2) / e_len;
  323. Vec3 d2c = e_len * n1;
  324. Vec3 d3c = e_len * n2;
  325. // The sum of the gradients must be zero (see "Strain Based Dynamics" section 4)
  326. Vec3 d1c = -d0c - d2c - d3c;
  327. // Get masses
  328. float w0 = v0.mInvMass;
  329. float w1 = v1.mInvMass;
  330. float w2 = v2.mInvMass;
  331. float w3 = v3.mInvMass;
  332. // Calculate -lambda
  333. float denom = w0 * d0c.LengthSq() + w1 * d1c.LengthSq() + w2 * d2c.LengthSq() + w3 * d3c.LengthSq() + b->mCompliance * inv_dt_sq;
  334. if (denom < 1.0e-12f)
  335. continue;
  336. float minus_lambda = c / denom;
  337. // Apply correction
  338. v0.mPosition = x0 - minus_lambda * w0 * d0c;
  339. v1.mPosition = x1 - minus_lambda * w1 * d1c;
  340. v2.mPosition = x2 - minus_lambda * w2 * d2c;
  341. v3.mPosition = x3 - minus_lambda * w3 * d3c;
  342. }
  343. }
  344. void SoftBodyMotionProperties::ApplyVolumeConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex)
  345. {
  346. JPH_PROFILE_FUNCTION();
  347. float inv_dt_sq = 1.0f / Square(inContext.mSubStepDeltaTime);
  348. // Satisfy volume constraints
  349. for (const Volume *v = mSettings->mVolumeConstraints.data() + inStartIndex, *v_end = mSettings->mVolumeConstraints.data() + inEndIndex; v < v_end; ++v)
  350. {
  351. Vertex &v1 = mVertices[v->mVertex[0]];
  352. Vertex &v2 = mVertices[v->mVertex[1]];
  353. Vertex &v3 = mVertices[v->mVertex[2]];
  354. Vertex &v4 = mVertices[v->mVertex[3]];
  355. Vec3 x1 = v1.mPosition;
  356. Vec3 x2 = v2.mPosition;
  357. Vec3 x3 = v3.mPosition;
  358. Vec3 x4 = v4.mPosition;
  359. // Calculate constraint equation
  360. Vec3 x1x2 = x2 - x1;
  361. Vec3 x1x3 = x3 - x1;
  362. Vec3 x1x4 = x4 - x1;
  363. float c = abs(x1x2.Cross(x1x3).Dot(x1x4)) - v->mSixRestVolume;
  364. // Calculate gradient of constraint equation
  365. Vec3 d1c = (x4 - x2).Cross(x3 - x2);
  366. Vec3 d2c = x1x3.Cross(x1x4);
  367. Vec3 d3c = x1x4.Cross(x1x2);
  368. Vec3 d4c = x1x2.Cross(x1x3);
  369. // Get masses
  370. float w1 = v1.mInvMass;
  371. float w2 = v2.mInvMass;
  372. float w3 = v3.mInvMass;
  373. float w4 = v4.mInvMass;
  374. // Calculate -lambda
  375. float denom = w1 * d1c.LengthSq() + w2 * d2c.LengthSq() + w3 * d3c.LengthSq() + w4 * d4c.LengthSq() + v->mCompliance * inv_dt_sq;
  376. if (denom < 1.0e-12f)
  377. continue;
  378. float minus_lambda = c / denom;
  379. // Apply correction
  380. v1.mPosition = x1 - minus_lambda * w1 * d1c;
  381. v2.mPosition = x2 - minus_lambda * w2 * d2c;
  382. v3.mPosition = x3 - minus_lambda * w3 * d3c;
  383. v4.mPosition = x4 - minus_lambda * w4 * d4c;
  384. }
  385. }
  386. void SoftBodyMotionProperties::ApplySkinConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex)
  387. {
  388. // Early out if nothing to do
  389. if (mSettings->mSkinnedConstraints.empty() || !mEnableSkinConstraints)
  390. return;
  391. JPH_PROFILE_FUNCTION();
  392. // We're going to iterate multiple times over the skin constraints, update the skinned position accordingly.
  393. // If we don't do this, the simulation will see a big jump and the first iteration will cause a big velocity change in the system.
  394. float factor = mSkinStatePreviousPositionValid? inContext.mNextIteration.load(std::memory_order_relaxed) / float(mNumIterations) : 1.0f;
  395. float prev_factor = 1.0f - factor;
  396. // Apply the constraints
  397. Vertex *vertices = mVertices.data();
  398. const SkinState *skin_states = mSkinState.data();
  399. for (const Skinned *s = mSettings->mSkinnedConstraints.data() + inStartIndex, *s_end = mSettings->mSkinnedConstraints.data() + inEndIndex; s < s_end; ++s)
  400. {
  401. Vertex &vertex = vertices[s->mVertex];
  402. const SkinState &skin_state = skin_states[s->mVertex];
  403. float max_distance = s->mMaxDistance * mSkinnedMaxDistanceMultiplier;
  404. // Calculate the skinned position by interpolating from previous to current position
  405. Vec3 skin_pos = prev_factor * skin_state.mPreviousPosition + factor * skin_state.mPosition;
  406. if (max_distance > 0.0f)
  407. {
  408. // Move vertex if it violated the back stop
  409. if (s->mBackStopDistance < max_distance)
  410. {
  411. // Center of the back stop sphere
  412. Vec3 center = skin_pos - skin_state.mNormal * (s->mBackStopDistance + s->mBackStopRadius);
  413. // Check if we're inside the back stop sphere
  414. Vec3 delta = vertex.mPosition - center;
  415. float delta_len_sq = delta.LengthSq();
  416. if (delta_len_sq < Square(s->mBackStopRadius))
  417. {
  418. // Push the vertex to the surface of the back stop sphere
  419. float delta_len = sqrt(delta_len_sq);
  420. vertex.mPosition = delta_len > 0.0f?
  421. center + delta * (s->mBackStopRadius / delta_len)
  422. : center + skin_state.mNormal * s->mBackStopRadius;
  423. }
  424. }
  425. // Clamp vertex distance to max distance from skinned position
  426. if (max_distance < FLT_MAX)
  427. {
  428. Vec3 delta = vertex.mPosition - skin_pos;
  429. float delta_len_sq = delta.LengthSq();
  430. float max_distance_sq = Square(max_distance);
  431. if (delta_len_sq > max_distance_sq)
  432. vertex.mPosition = skin_pos + delta * sqrt(max_distance_sq / delta_len_sq);
  433. }
  434. }
  435. else
  436. {
  437. // Kinematic: Just update the vertex position
  438. vertex.mPosition = skin_pos;
  439. }
  440. }
  441. }
  442. void SoftBodyMotionProperties::ApplyEdgeConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex)
  443. {
  444. JPH_PROFILE_FUNCTION();
  445. float inv_dt_sq = 1.0f / Square(inContext.mSubStepDeltaTime);
  446. // Satisfy edge constraints
  447. for (const Edge *e = mSettings->mEdgeConstraints.data() + inStartIndex, *e_end = mSettings->mEdgeConstraints.data() + inEndIndex; e < e_end; ++e)
  448. {
  449. Vertex &v0 = mVertices[e->mVertex[0]];
  450. Vertex &v1 = mVertices[e->mVertex[1]];
  451. // Get positions
  452. Vec3 x0 = v0.mPosition;
  453. Vec3 x1 = v1.mPosition;
  454. // Calculate current length
  455. Vec3 delta = x1 - x0;
  456. float length = delta.Length();
  457. // Apply correction
  458. float denom = length * (v0.mInvMass + v1.mInvMass + e->mCompliance * inv_dt_sq);
  459. if (denom < 1.0e-12f)
  460. continue;
  461. Vec3 correction = delta * (length - e->mRestLength) / denom;
  462. v0.mPosition = x0 + v0.mInvMass * correction;
  463. v1.mPosition = x1 - v1.mInvMass * correction;
  464. }
  465. }
  466. void SoftBodyMotionProperties::ApplyLRAConstraints(uint inStartIndex, uint inEndIndex)
  467. {
  468. JPH_PROFILE_FUNCTION();
  469. // Satisfy LRA constraints
  470. Vertex *vertices = mVertices.data();
  471. for (const LRA *lra = mSettings->mLRAConstraints.data() + inStartIndex, *lra_end = mSettings->mLRAConstraints.data() + inEndIndex; lra < lra_end; ++lra)
  472. {
  473. JPH_ASSERT(lra->mVertex[0] < mVertices.size());
  474. JPH_ASSERT(lra->mVertex[1] < mVertices.size());
  475. const Vertex &vertex0 = vertices[lra->mVertex[0]];
  476. Vertex &vertex1 = vertices[lra->mVertex[1]];
  477. Vec3 x0 = vertex0.mPosition;
  478. Vec3 delta = vertex1.mPosition - x0;
  479. float delta_len_sq = delta.LengthSq();
  480. if (delta_len_sq > Square(lra->mMaxDistance))
  481. vertex1.mPosition = x0 + delta * lra->mMaxDistance / sqrt(delta_len_sq);
  482. }
  483. }
  484. void SoftBodyMotionProperties::ApplyCollisionConstraintsAndUpdateVelocities(const SoftBodyUpdateContext &inContext)
  485. {
  486. JPH_PROFILE_FUNCTION();
  487. float dt = inContext.mSubStepDeltaTime;
  488. float restitution_treshold = -2.0f * inContext.mGravity.Length() * dt;
  489. float vertex_radius = mSettings->mVertexRadius;
  490. for (Vertex &v : mVertices)
  491. if (v.mInvMass > 0.0f)
  492. {
  493. // Remember previous velocity for restitution calculations
  494. Vec3 prev_v = v.mVelocity;
  495. // XPBD velocity update
  496. v.mVelocity = (v.mPosition - v.mPreviousPosition) / dt;
  497. // Satisfy collision constraint
  498. if (v.mCollidingShapeIndex >= 0)
  499. {
  500. // Check if there is a collision
  501. float projected_distance = -v.mCollisionPlane.SignedDistance(v.mPosition) + vertex_radius;
  502. if (projected_distance > 0.0f)
  503. {
  504. // Remember that there was a collision
  505. v.mHasContact = true;
  506. // We need a contact callback if one of the vertices collided
  507. mNeedContactCallback = true;
  508. // Note that we already calculated the velocity, so this does not affect the velocity (next iteration starts by setting previous position to current position)
  509. CollidingShape &cs = mCollidingShapes[v.mCollidingShapeIndex];
  510. Vec3 contact_normal = v.mCollisionPlane.GetNormal();
  511. v.mPosition += contact_normal * projected_distance;
  512. // Apply friction as described in Detailed Rigid Body Simulation with Extended Position Based Dynamics - Matthias Muller et al.
  513. // See section 3.6:
  514. // Inverse mass: w1 = 1 / m1, w2 = 1 / m2 + (r2 x n)^T I^-1 (r2 x n) = 0 for a static object
  515. // r2 are the contact point relative to the center of mass of body 2
  516. // Lagrange multiplier for contact: lambda = -c / (w1 + w2)
  517. // Where c is the constraint equation (the distance to the plane, negative because penetrating)
  518. // Contact normal force: fn = lambda / dt^2
  519. // Delta velocity due to friction dv = -vt / |vt| * min(dt * friction * fn * (w1 + w2), |vt|) = -vt * min(-friction * c / (|vt| * dt), 1)
  520. // Note that I think there is an error in the paper, I added a mass term, see: https://github.com/matthias-research/pages/issues/29
  521. // Relative velocity: vr = v1 - v2 - omega2 x r2
  522. // Normal velocity: vn = vr . contact_normal
  523. // Tangential velocity: vt = vr - contact_normal * vn
  524. // Impulse: p = dv / (w1 + w2)
  525. // Changes in particle velocities:
  526. // v1 = v1 + p / m1
  527. // v2 = v2 - p / m2 (no change when colliding with a static body)
  528. // w2 = w2 - I^-1 (r2 x p) (no change when colliding with a static body)
  529. if (cs.mMotionType == EMotionType::Dynamic)
  530. {
  531. // Calculate normal and tangential velocity (equation 30)
  532. Vec3 r2 = v.mPosition - cs.mCenterOfMassTransform.GetTranslation();
  533. Vec3 v2 = cs.GetPointVelocity(r2);
  534. Vec3 relative_velocity = v.mVelocity - v2;
  535. Vec3 v_normal = contact_normal * contact_normal.Dot(relative_velocity);
  536. Vec3 v_tangential = relative_velocity - v_normal;
  537. float v_tangential_length = v_tangential.Length();
  538. // Calculate resulting inverse mass of vertex
  539. float vertex_inv_mass = cs.mSoftBodyInvMassScale * v.mInvMass;
  540. // Calculate inverse effective mass
  541. Vec3 r2_cross_n = r2.Cross(contact_normal);
  542. float w2 = cs.mInvMass + r2_cross_n.Dot(cs.mInvInertia * r2_cross_n);
  543. float w1_plus_w2 = vertex_inv_mass + w2;
  544. if (w1_plus_w2 > 0.0f)
  545. {
  546. // Calculate delta relative velocity due to friction (modified equation 31)
  547. Vec3 dv;
  548. if (v_tangential_length > 0.0f)
  549. dv = v_tangential * min(cs.mFriction * projected_distance / (v_tangential_length * dt), 1.0f);
  550. else
  551. dv = Vec3::sZero();
  552. // Calculate delta relative velocity due to restitution (equation 35)
  553. dv += v_normal;
  554. float prev_v_normal = (prev_v - v2).Dot(contact_normal);
  555. if (prev_v_normal < restitution_treshold)
  556. dv += cs.mRestitution * prev_v_normal * contact_normal;
  557. // Calculate impulse
  558. Vec3 p = dv / w1_plus_w2;
  559. // Apply impulse to particle
  560. v.mVelocity -= p * vertex_inv_mass;
  561. // Apply impulse to rigid body
  562. cs.mLinearVelocity += p * cs.mInvMass;
  563. cs.mAngularVelocity += cs.mInvInertia * r2.Cross(p);
  564. // Mark that the velocities of the body we hit need to be updated
  565. cs.mUpdateVelocities = true;
  566. }
  567. }
  568. else if (cs.mSoftBodyInvMassScale > 0.0f)
  569. {
  570. // Body is not movable, equations are simpler
  571. // Calculate normal and tangential velocity (equation 30)
  572. Vec3 v_normal = contact_normal * contact_normal.Dot(v.mVelocity);
  573. Vec3 v_tangential = v.mVelocity - v_normal;
  574. float v_tangential_length = v_tangential.Length();
  575. // Apply friction (modified equation 31)
  576. if (v_tangential_length > 0.0f)
  577. v.mVelocity -= v_tangential * min(cs.mFriction * projected_distance / (v_tangential_length * dt), 1.0f);
  578. // Apply restitution (equation 35)
  579. v.mVelocity -= v_normal;
  580. float prev_v_normal = prev_v.Dot(contact_normal);
  581. if (prev_v_normal < restitution_treshold)
  582. v.mVelocity -= cs.mRestitution * prev_v_normal * contact_normal;
  583. }
  584. }
  585. }
  586. }
  587. }
  588. void SoftBodyMotionProperties::UpdateSoftBodyState(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings)
  589. {
  590. JPH_PROFILE_FUNCTION();
  591. // Contact callback
  592. if (mNeedContactCallback && ioContext.mContactListener != nullptr)
  593. {
  594. // Remove non-colliding sensors from the list
  595. for (int i = int(mCollidingSensors.size()) - 1; i >= 0; --i)
  596. if (!mCollidingSensors[i].mHasContact)
  597. {
  598. mCollidingSensors[i] = std::move(mCollidingSensors.back());
  599. mCollidingSensors.pop_back();
  600. }
  601. ioContext.mContactListener->OnSoftBodyContactAdded(*ioContext.mBody, SoftBodyManifold(this));
  602. }
  603. // Loop through vertices once more to update the global state
  604. float dt = ioContext.mDeltaTime;
  605. float max_linear_velocity_sq = Square(GetMaxLinearVelocity());
  606. float max_v_sq = 0.0f;
  607. Vec3 linear_velocity = Vec3::sZero(), angular_velocity = Vec3::sZero();
  608. mLocalPredictedBounds = mLocalBounds = { };
  609. for (Vertex &v : mVertices)
  610. {
  611. // Calculate max square velocity
  612. float v_sq = v.mVelocity.LengthSq();
  613. max_v_sq = max(max_v_sq, v_sq);
  614. // Clamp if velocity is too high
  615. if (v_sq > max_linear_velocity_sq)
  616. v.mVelocity *= sqrt(max_linear_velocity_sq / v_sq);
  617. // Calculate local linear/angular velocity
  618. linear_velocity += v.mVelocity;
  619. angular_velocity += v.mPosition.Cross(v.mVelocity);
  620. // Update local bounding box
  621. mLocalBounds.Encapsulate(v.mPosition);
  622. // Create predicted position for the next frame in order to detect collisions before they happen
  623. mLocalPredictedBounds.Encapsulate(v.mPosition + v.mVelocity * dt + ioContext.mDisplacementDueToGravity);
  624. // Reset collision data for the next iteration
  625. v.ResetCollision();
  626. }
  627. // Calculate linear/angular velocity of the body by averaging all vertices and bringing the value to world space
  628. float num_vertices_divider = float(max(int(mVertices.size()), 1));
  629. SetLinearVelocity(ioContext.mCenterOfMassTransform.Multiply3x3(linear_velocity / num_vertices_divider));
  630. SetAngularVelocity(ioContext.mCenterOfMassTransform.Multiply3x3(angular_velocity / num_vertices_divider));
  631. if (mUpdatePosition)
  632. {
  633. // Shift the body so that the position is the center of the local bounds
  634. Vec3 delta = mLocalBounds.GetCenter();
  635. ioContext.mDeltaPosition = ioContext.mCenterOfMassTransform.Multiply3x3(delta);
  636. for (Vertex &v : mVertices)
  637. v.mPosition -= delta;
  638. // Update the skin state too since we will use this position as the previous position in the next update
  639. for (SkinState &s : mSkinState)
  640. s.mPosition -= delta;
  641. JPH_IF_DEBUG_RENDERER(mSkinStateTransform.SetTranslation(mSkinStateTransform.GetTranslation() + ioContext.mDeltaPosition);)
  642. // Offset bounds to match new position
  643. mLocalBounds.Translate(-delta);
  644. mLocalPredictedBounds.Translate(-delta);
  645. }
  646. else
  647. ioContext.mDeltaPosition = Vec3::sZero();
  648. // Test if we should go to sleep
  649. if (GetAllowSleeping())
  650. {
  651. if (max_v_sq > inPhysicsSettings.mPointVelocitySleepThreshold)
  652. {
  653. ResetSleepTestTimer();
  654. ioContext.mCanSleep = ECanSleep::CannotSleep;
  655. }
  656. else
  657. ioContext.mCanSleep = AccumulateSleepTime(dt, inPhysicsSettings.mTimeBeforeSleep);
  658. }
  659. else
  660. ioContext.mCanSleep = ECanSleep::CannotSleep;
  661. // If SkinVertices is not called after this then don't use the previous position as the skin is static
  662. mSkinStatePreviousPositionValid = false;
  663. // Reset force accumulator
  664. ResetForce();
  665. }
  666. void SoftBodyMotionProperties::UpdateRigidBodyVelocities(const SoftBodyUpdateContext &inContext, BodyInterface &inBodyInterface)
  667. {
  668. JPH_PROFILE_FUNCTION();
  669. // Write back velocity deltas
  670. for (const CollidingShape &cs : mCollidingShapes)
  671. if (cs.mUpdateVelocities)
  672. inBodyInterface.AddLinearAndAngularVelocity(cs.mBodyID, inContext.mCenterOfMassTransform.Multiply3x3(cs.mLinearVelocity - cs.mOriginalLinearVelocity), inContext.mCenterOfMassTransform.Multiply3x3(cs.mAngularVelocity - cs.mOriginalAngularVelocity));
  673. // Clear colliding shapes/sensors to avoid hanging on to references to shapes
  674. mCollidingShapes.clear();
  675. mCollidingSensors.clear();
  676. }
  677. void SoftBodyMotionProperties::InitializeUpdateContext(float inDeltaTime, Body &inSoftBody, const PhysicsSystem &inSystem, SoftBodyUpdateContext &ioContext)
  678. {
  679. JPH_PROFILE_FUNCTION();
  680. // Store body
  681. ioContext.mBody = &inSoftBody;
  682. ioContext.mMotionProperties = this;
  683. ioContext.mContactListener = inSystem.GetSoftBodyContactListener();
  684. // Convert gravity to local space
  685. ioContext.mCenterOfMassTransform = inSoftBody.GetCenterOfMassTransform();
  686. ioContext.mGravity = ioContext.mCenterOfMassTransform.Multiply3x3Transposed(GetGravityFactor() * inSystem.GetGravity());
  687. // Calculate delta time for sub step
  688. ioContext.mDeltaTime = inDeltaTime;
  689. ioContext.mSubStepDeltaTime = inDeltaTime / mNumIterations;
  690. // Calculate total displacement we'll have due to gravity over all sub steps
  691. // The total displacement as produced by our integrator can be written as: Sum(i * g * dt^2, i = 0..mNumIterations).
  692. // This is bigger than 0.5 * g * dt^2 because we first increment the velocity and then update the position
  693. // Using Sum(i, i = 0..n) = n * (n + 1) / 2 we can write this as:
  694. ioContext.mDisplacementDueToGravity = (0.5f * mNumIterations * (mNumIterations + 1) * Square(ioContext.mSubStepDeltaTime)) * ioContext.mGravity;
  695. }
  696. void SoftBodyMotionProperties::StartNextIteration(const SoftBodyUpdateContext &ioContext)
  697. {
  698. ApplyPressure(ioContext);
  699. IntegratePositions(ioContext);
  700. }
  701. void SoftBodyMotionProperties::StartFirstIteration(SoftBodyUpdateContext &ioContext)
  702. {
  703. // Start the first iteration
  704. JPH_IF_ENABLE_ASSERTS(uint iteration =) ioContext.mNextIteration.fetch_add(1, memory_order_relaxed);
  705. JPH_ASSERT(iteration == 0);
  706. StartNextIteration(ioContext);
  707. ioContext.mState.store(SoftBodyUpdateContext::EState::ApplyConstraints, memory_order_release);
  708. }
  709. SoftBodyMotionProperties::EStatus SoftBodyMotionProperties::ParallelDetermineCollisionPlanes(SoftBodyUpdateContext &ioContext)
  710. {
  711. // Do a relaxed read first to see if there is any work to do (this prevents us from doing expensive atomic operations and also prevents us from continuously incrementing the counter and overflowing it)
  712. uint num_vertices = (uint)mVertices.size();
  713. if (ioContext.mNextCollisionVertex.load(memory_order_relaxed) < num_vertices)
  714. {
  715. // Fetch next batch of vertices to process
  716. uint next_vertex = ioContext.mNextCollisionVertex.fetch_add(SoftBodyUpdateContext::cVertexCollisionBatch, memory_order_acquire);
  717. if (next_vertex < num_vertices)
  718. {
  719. // Process collision planes
  720. uint num_vertices_to_process = min(SoftBodyUpdateContext::cVertexCollisionBatch, num_vertices - next_vertex);
  721. DetermineCollisionPlanes(next_vertex, num_vertices_to_process);
  722. uint vertices_processed = ioContext.mNumCollisionVerticesProcessed.fetch_add(SoftBodyUpdateContext::cVertexCollisionBatch, memory_order_release) + num_vertices_to_process;
  723. if (vertices_processed >= num_vertices)
  724. {
  725. // Determine next state
  726. if (mCollidingSensors.empty())
  727. StartFirstIteration(ioContext);
  728. else
  729. ioContext.mState.store(SoftBodyUpdateContext::EState::DetermineSensorCollisions, memory_order_release);
  730. }
  731. return EStatus::DidWork;
  732. }
  733. }
  734. return EStatus::NoWork;
  735. }
  736. SoftBodyMotionProperties::EStatus SoftBodyMotionProperties::ParallelDetermineSensorCollisions(SoftBodyUpdateContext &ioContext)
  737. {
  738. // Do a relaxed read to see if there are more sensors to process
  739. uint num_sensors = (uint)mCollidingSensors.size();
  740. if (ioContext.mNextSensorIndex.load(memory_order_relaxed) < num_sensors)
  741. {
  742. // Fetch next sensor to process
  743. uint sensor_index = ioContext.mNextSensorIndex.fetch_add(1, memory_order_acquire);
  744. if (sensor_index < num_sensors)
  745. {
  746. // Process this sensor
  747. DetermineSensorCollisions(mCollidingSensors[sensor_index]);
  748. // Determine next state
  749. uint sensors_processed = ioContext.mNumSensorsProcessed.fetch_add(1, memory_order_release) + 1;
  750. if (sensors_processed >= num_sensors)
  751. StartFirstIteration(ioContext);
  752. return EStatus::DidWork;
  753. }
  754. }
  755. return EStatus::NoWork;
  756. }
  757. void SoftBodyMotionProperties::ProcessGroup(const SoftBodyUpdateContext &ioContext, uint inGroupIndex)
  758. {
  759. // Determine start and end
  760. SoftBodySharedSettings::UpdateGroup start { 0, 0, 0, 0, 0 };
  761. const SoftBodySharedSettings::UpdateGroup &prev = inGroupIndex > 0? mSettings->mUpdateGroups[inGroupIndex - 1] : start;
  762. const SoftBodySharedSettings::UpdateGroup &current = mSettings->mUpdateGroups[inGroupIndex];
  763. // Process volume constraints
  764. ApplyVolumeConstraints(ioContext, prev.mVolumeEndIndex, current.mVolumeEndIndex);
  765. // Process bend constraints
  766. ApplyDihedralBendConstraints(ioContext, prev.mDihedralBendEndIndex, current.mDihedralBendEndIndex);
  767. // Process skinned constraints
  768. ApplySkinConstraints(ioContext, prev.mSkinnedEndIndex, current.mSkinnedEndIndex);
  769. // Process edges
  770. ApplyEdgeConstraints(ioContext, prev.mEdgeEndIndex, current.mEdgeEndIndex);
  771. // Process LRA constraints
  772. ApplyLRAConstraints(prev.mLRAEndIndex, current.mLRAEndIndex);
  773. }
  774. SoftBodyMotionProperties::EStatus SoftBodyMotionProperties::ParallelApplyConstraints(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings)
  775. {
  776. uint num_groups = (uint)mSettings->mUpdateGroups.size();
  777. JPH_ASSERT(num_groups > 0, "SoftBodySharedSettings::Optimize should have been called!");
  778. --num_groups; // Last group is the non-parallel group, we don't want to execute it in parallel
  779. // Do a relaxed read first to see if there is any work to do (this prevents us from doing expensive atomic operations and also prevents us from continuously incrementing the counter and overflowing it)
  780. uint next_group = ioContext.mNextConstraintGroup.load(memory_order_relaxed);
  781. if (next_group < num_groups || (num_groups == 0 && next_group == 0))
  782. {
  783. // Fetch the next group process
  784. next_group = ioContext.mNextConstraintGroup.fetch_add(1, memory_order_acquire);
  785. if (next_group < num_groups || (num_groups == 0 && next_group == 0))
  786. {
  787. uint num_groups_processed = 0;
  788. if (num_groups > 0)
  789. {
  790. // Process this group
  791. ProcessGroup(ioContext, next_group);
  792. // Increment total number of groups processed
  793. num_groups_processed = ioContext.mNumConstraintGroupsProcessed.fetch_add(1, memory_order_relaxed) + 1;
  794. }
  795. if (num_groups_processed >= num_groups)
  796. {
  797. // Finish the iteration
  798. JPH_PROFILE("FinishIteration");
  799. // Process non-parallel group
  800. ProcessGroup(ioContext, num_groups);
  801. ApplyCollisionConstraintsAndUpdateVelocities(ioContext);
  802. uint iteration = ioContext.mNextIteration.fetch_add(1, memory_order_relaxed);
  803. if (iteration < mNumIterations)
  804. {
  805. // Start a new iteration
  806. StartNextIteration(ioContext);
  807. // Reset group logic
  808. ioContext.mNumConstraintGroupsProcessed.store(0, memory_order_relaxed);
  809. ioContext.mNextConstraintGroup.store(0, memory_order_release);
  810. }
  811. else
  812. {
  813. // On final iteration we update the state
  814. UpdateSoftBodyState(ioContext, inPhysicsSettings);
  815. ioContext.mState.store(SoftBodyUpdateContext::EState::Done, memory_order_release);
  816. return EStatus::Done;
  817. }
  818. }
  819. return EStatus::DidWork;
  820. }
  821. }
  822. return EStatus::NoWork;
  823. }
  824. SoftBodyMotionProperties::EStatus SoftBodyMotionProperties::ParallelUpdate(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings)
  825. {
  826. switch (ioContext.mState.load(memory_order_relaxed))
  827. {
  828. case SoftBodyUpdateContext::EState::DetermineCollisionPlanes:
  829. return ParallelDetermineCollisionPlanes(ioContext);
  830. case SoftBodyUpdateContext::EState::DetermineSensorCollisions:
  831. return ParallelDetermineSensorCollisions(ioContext);
  832. case SoftBodyUpdateContext::EState::ApplyConstraints:
  833. return ParallelApplyConstraints(ioContext, inPhysicsSettings);
  834. case SoftBodyUpdateContext::EState::Done:
  835. return EStatus::Done;
  836. default:
  837. JPH_ASSERT(false);
  838. return EStatus::NoWork;
  839. }
  840. }
  841. void SoftBodyMotionProperties::SkinVertices([[maybe_unused]] RMat44Arg inCenterOfMassTransform, const Mat44 *inJointMatrices, [[maybe_unused]] uint inNumJoints, bool inHardSkinAll, TempAllocator &ioTempAllocator)
  842. {
  843. // Calculate the skin matrices
  844. uint num_skin_matrices = uint(mSettings->mInvBindMatrices.size());
  845. uint skin_matrices_size = num_skin_matrices * sizeof(Mat44);
  846. Mat44 *skin_matrices = (Mat44 *)ioTempAllocator.Allocate(skin_matrices_size);
  847. JPH_SCOPE_EXIT([&ioTempAllocator, skin_matrices, skin_matrices_size]{ ioTempAllocator.Free(skin_matrices, skin_matrices_size); });
  848. const Mat44 *skin_matrices_end = skin_matrices + num_skin_matrices;
  849. const InvBind *inv_bind_matrix = mSettings->mInvBindMatrices.data();
  850. for (Mat44 *s = skin_matrices; s < skin_matrices_end; ++s, ++inv_bind_matrix)
  851. *s = inJointMatrices[inv_bind_matrix->mJointIndex] * inv_bind_matrix->mInvBind;
  852. // Skin the vertices
  853. JPH_IF_DEBUG_RENDERER(mSkinStateTransform = inCenterOfMassTransform;)
  854. JPH_IF_ENABLE_ASSERTS(uint num_vertices = uint(mSettings->mVertices.size());)
  855. JPH_ASSERT(mSkinState.size() == num_vertices);
  856. const SoftBodySharedSettings::Vertex *in_vertices = mSettings->mVertices.data();
  857. for (const Skinned &s : mSettings->mSkinnedConstraints)
  858. {
  859. // Get bind pose
  860. JPH_ASSERT(s.mVertex < num_vertices);
  861. Vec3 bind_pos = Vec3::sLoadFloat3Unsafe(in_vertices[s.mVertex].mPosition);
  862. // Skin vertex
  863. Vec3 pos = Vec3::sZero();
  864. for (const SkinWeight &w : s.mWeights)
  865. {
  866. // We assume that the first zero weight is the end of the list
  867. if (w.mWeight == 0.0f)
  868. break;
  869. JPH_ASSERT(w.mInvBindIndex < num_skin_matrices);
  870. pos += w.mWeight * (skin_matrices[w.mInvBindIndex] * bind_pos);
  871. }
  872. SkinState &skin_state = mSkinState[s.mVertex];
  873. skin_state.mPreviousPosition = skin_state.mPosition;
  874. skin_state.mPosition = pos;
  875. }
  876. // Calculate the normals
  877. for (const Skinned &s : mSettings->mSkinnedConstraints)
  878. {
  879. Vec3 normal = Vec3::sZero();
  880. uint32 num_faces = s.mNormalInfo >> 24;
  881. if (num_faces > 0)
  882. {
  883. // Calculate normal
  884. const uint32 *f = &mSettings->mSkinnedConstraintNormals[s.mNormalInfo & 0xffffff];
  885. const uint32 *f_end = f + num_faces;
  886. while (f < f_end)
  887. {
  888. const Face &face = mSettings->mFaces[*f];
  889. Vec3 v0 = mSkinState[face.mVertex[0]].mPosition;
  890. Vec3 v1 = mSkinState[face.mVertex[1]].mPosition;
  891. Vec3 v2 = mSkinState[face.mVertex[2]].mPosition;
  892. normal += (v1 - v0).Cross(v2 - v0).NormalizedOr(Vec3::sZero());
  893. ++f;
  894. }
  895. normal = normal.NormalizedOr(Vec3::sZero());
  896. }
  897. mSkinState[s.mVertex].mNormal = normal;
  898. }
  899. if (inHardSkinAll)
  900. {
  901. // Hard skin all vertices and reset their velocities
  902. for (const Skinned &s : mSettings->mSkinnedConstraints)
  903. {
  904. Vertex &vertex = mVertices[s.mVertex];
  905. SkinState &skin_state = mSkinState[s.mVertex];
  906. skin_state.mPreviousPosition = skin_state.mPosition;
  907. vertex.mPosition = skin_state.mPosition;
  908. vertex.mVelocity = Vec3::sZero();
  909. }
  910. }
  911. else if (!mEnableSkinConstraints)
  912. {
  913. // Hard skin only the kinematic vertices as we will not solve the skin constraints later
  914. for (const Skinned &s : mSettings->mSkinnedConstraints)
  915. if (s.mMaxDistance == 0.0f)
  916. {
  917. Vertex &vertex = mVertices[s.mVertex];
  918. vertex.mPosition = mSkinState[s.mVertex].mPosition;
  919. }
  920. }
  921. // Indicate that the previous positions are valid for the coming update
  922. mSkinStatePreviousPositionValid = true;
  923. }
  924. void SoftBodyMotionProperties::CustomUpdate(float inDeltaTime, Body &ioSoftBody, PhysicsSystem &inSystem)
  925. {
  926. JPH_PROFILE_FUNCTION();
  927. // Create update context
  928. SoftBodyUpdateContext context;
  929. InitializeUpdateContext(inDeltaTime, ioSoftBody, inSystem, context);
  930. // Determine bodies we're colliding with
  931. DetermineCollidingShapes(context, inSystem, inSystem.GetBodyLockInterface());
  932. // Call the internal update until it finishes
  933. EStatus status;
  934. const PhysicsSettings &settings = inSystem.GetPhysicsSettings();
  935. while ((status = ParallelUpdate(context, settings)) == EStatus::DidWork)
  936. continue;
  937. JPH_ASSERT(status == EStatus::Done);
  938. // Update the state of the bodies we've collided with
  939. UpdateRigidBodyVelocities(context, inSystem.GetBodyInterface());
  940. // Update position of the soft body
  941. if (mUpdatePosition)
  942. inSystem.GetBodyInterface().SetPosition(ioSoftBody.GetID(), ioSoftBody.GetPosition() + context.mDeltaPosition, EActivation::DontActivate);
  943. }
  944. #ifdef JPH_DEBUG_RENDERER
  945. void SoftBodyMotionProperties::DrawVertices(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const
  946. {
  947. for (const Vertex &v : mVertices)
  948. inRenderer->DrawMarker(inCenterOfMassTransform * v.mPosition, v.mInvMass > 0.0f? Color::sGreen : Color::sRed, 0.05f);
  949. }
  950. void SoftBodyMotionProperties::DrawVertexVelocities(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const
  951. {
  952. for (const Vertex &v : mVertices)
  953. inRenderer->DrawArrow(inCenterOfMassTransform * v.mPosition, inCenterOfMassTransform * (v.mPosition + v.mVelocity), Color::sYellow, 0.01f);
  954. }
  955. template <typename GetEndIndex, typename DrawConstraint>
  956. inline void SoftBodyMotionProperties::DrawConstraints(ESoftBodyConstraintColor inConstraintColor, const GetEndIndex &inGetEndIndex, const DrawConstraint &inDrawConstraint, ColorArg inBaseColor) const
  957. {
  958. uint start = 0;
  959. for (uint i = 0; i < (uint)mSettings->mUpdateGroups.size(); ++i)
  960. {
  961. uint end = inGetEndIndex(mSettings->mUpdateGroups[i]);
  962. Color base_color;
  963. if (inConstraintColor != ESoftBodyConstraintColor::ConstraintType)
  964. base_color = Color::sGetDistinctColor((uint)mSettings->mUpdateGroups.size() - i - 1); // Ensure that color 0 is always the last group
  965. else
  966. base_color = inBaseColor;
  967. for (uint idx = start; idx < end; ++idx)
  968. {
  969. Color color = inConstraintColor == ESoftBodyConstraintColor::ConstraintOrder? base_color * (float(idx - start) / (end - start)) : base_color;
  970. inDrawConstraint(idx, color);
  971. }
  972. start = end;
  973. }
  974. }
  975. void SoftBodyMotionProperties::DrawEdgeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
  976. {
  977. DrawConstraints(inConstraintColor,
  978. [](const SoftBodySharedSettings::UpdateGroup &inGroup) {
  979. return inGroup.mEdgeEndIndex;
  980. },
  981. [this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
  982. const Edge &e = mSettings->mEdgeConstraints[inIndex];
  983. inRenderer->DrawLine(inCenterOfMassTransform * mVertices[e.mVertex[0]].mPosition, inCenterOfMassTransform * mVertices[e.mVertex[1]].mPosition, inColor);
  984. },
  985. Color::sWhite);
  986. }
  987. void SoftBodyMotionProperties::DrawBendConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
  988. {
  989. DrawConstraints(inConstraintColor,
  990. [](const SoftBodySharedSettings::UpdateGroup &inGroup) {
  991. return inGroup.mDihedralBendEndIndex;
  992. },
  993. [this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
  994. const DihedralBend &b = mSettings->mDihedralBendConstraints[inIndex];
  995. RVec3 x0 = inCenterOfMassTransform * mVertices[b.mVertex[0]].mPosition;
  996. RVec3 x1 = inCenterOfMassTransform * mVertices[b.mVertex[1]].mPosition;
  997. RVec3 x2 = inCenterOfMassTransform * mVertices[b.mVertex[2]].mPosition;
  998. RVec3 x3 = inCenterOfMassTransform * mVertices[b.mVertex[3]].mPosition;
  999. RVec3 c_edge = 0.5_r * (x0 + x1);
  1000. RVec3 c0 = (x0 + x1 + x2) / 3.0_r;
  1001. RVec3 c1 = (x0 + x1 + x3) / 3.0_r;
  1002. inRenderer->DrawArrow(0.9_r * x0 + 0.1_r * x1, 0.1_r * x0 + 0.9_r * x1, inColor, 0.01f);
  1003. inRenderer->DrawLine(c_edge, 0.1_r * c_edge + 0.9_r * c0, inColor);
  1004. inRenderer->DrawLine(c_edge, 0.1_r * c_edge + 0.9_r * c1, inColor);
  1005. },
  1006. Color::sGreen);
  1007. }
  1008. void SoftBodyMotionProperties::DrawVolumeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
  1009. {
  1010. DrawConstraints(inConstraintColor,
  1011. [](const SoftBodySharedSettings::UpdateGroup &inGroup) {
  1012. return inGroup.mVolumeEndIndex;
  1013. },
  1014. [this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
  1015. const Volume &v = mSettings->mVolumeConstraints[inIndex];
  1016. RVec3 x1 = inCenterOfMassTransform * mVertices[v.mVertex[0]].mPosition;
  1017. RVec3 x2 = inCenterOfMassTransform * mVertices[v.mVertex[1]].mPosition;
  1018. RVec3 x3 = inCenterOfMassTransform * mVertices[v.mVertex[2]].mPosition;
  1019. RVec3 x4 = inCenterOfMassTransform * mVertices[v.mVertex[3]].mPosition;
  1020. inRenderer->DrawTriangle(x1, x3, x2, inColor, DebugRenderer::ECastShadow::On);
  1021. inRenderer->DrawTriangle(x2, x3, x4, inColor, DebugRenderer::ECastShadow::On);
  1022. inRenderer->DrawTriangle(x1, x4, x3, inColor, DebugRenderer::ECastShadow::On);
  1023. inRenderer->DrawTriangle(x1, x2, x4, inColor, DebugRenderer::ECastShadow::On);
  1024. },
  1025. Color::sYellow);
  1026. }
  1027. void SoftBodyMotionProperties::DrawSkinConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
  1028. {
  1029. DrawConstraints(inConstraintColor,
  1030. [](const SoftBodySharedSettings::UpdateGroup &inGroup) {
  1031. return inGroup.mSkinnedEndIndex;
  1032. },
  1033. [this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
  1034. const Skinned &s = mSettings->mSkinnedConstraints[inIndex];
  1035. const SkinState &skin_state = mSkinState[s.mVertex];
  1036. inRenderer->DrawArrow(mSkinStateTransform * skin_state.mPosition, mSkinStateTransform * (skin_state.mPosition + 0.1f * skin_state.mNormal), inColor, 0.01f);
  1037. inRenderer->DrawLine(mSkinStateTransform * skin_state.mPosition, inCenterOfMassTransform * mVertices[s.mVertex].mPosition, Color::sBlue);
  1038. },
  1039. Color::sOrange);
  1040. }
  1041. void SoftBodyMotionProperties::DrawLRAConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
  1042. {
  1043. DrawConstraints(inConstraintColor,
  1044. [](const SoftBodySharedSettings::UpdateGroup &inGroup) {
  1045. return inGroup.mLRAEndIndex;
  1046. },
  1047. [this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
  1048. const LRA &l = mSettings->mLRAConstraints[inIndex];
  1049. inRenderer->DrawLine(inCenterOfMassTransform * mVertices[l.mVertex[0]].mPosition, inCenterOfMassTransform * mVertices[l.mVertex[1]].mPosition, inColor);
  1050. },
  1051. Color::sGrey);
  1052. }
  1053. void SoftBodyMotionProperties::DrawPredictedBounds(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const
  1054. {
  1055. inRenderer->DrawWireBox(inCenterOfMassTransform, mLocalPredictedBounds, Color::sRed);
  1056. }
  1057. #endif // JPH_DEBUG_RENDERER
  1058. void SoftBodyMotionProperties::SaveState(StateRecorder &inStream) const
  1059. {
  1060. MotionProperties::SaveState(inStream);
  1061. for (const Vertex &v : mVertices)
  1062. {
  1063. inStream.Write(v.mPreviousPosition);
  1064. inStream.Write(v.mPosition);
  1065. inStream.Write(v.mVelocity);
  1066. }
  1067. for (const SkinState &s : mSkinState)
  1068. {
  1069. inStream.Write(s.mPreviousPosition);
  1070. inStream.Write(s.mPosition);
  1071. inStream.Write(s.mNormal);
  1072. }
  1073. inStream.Write(mLocalBounds.mMin);
  1074. inStream.Write(mLocalBounds.mMax);
  1075. inStream.Write(mLocalPredictedBounds.mMin);
  1076. inStream.Write(mLocalPredictedBounds.mMax);
  1077. }
  1078. void SoftBodyMotionProperties::RestoreState(StateRecorder &inStream)
  1079. {
  1080. MotionProperties::RestoreState(inStream);
  1081. for (Vertex &v : mVertices)
  1082. {
  1083. inStream.Read(v.mPreviousPosition);
  1084. inStream.Read(v.mPosition);
  1085. inStream.Read(v.mVelocity);
  1086. }
  1087. for (SkinState &s : mSkinState)
  1088. {
  1089. inStream.Read(s.mPreviousPosition);
  1090. inStream.Read(s.mPosition);
  1091. inStream.Read(s.mNormal);
  1092. }
  1093. inStream.Read(mLocalBounds.mMin);
  1094. inStream.Read(mLocalBounds.mMax);
  1095. inStream.Read(mLocalPredictedBounds.mMin);
  1096. inStream.Read(mLocalPredictedBounds.mMax);
  1097. }
  1098. JPH_NAMESPACE_END