2
0

SoftBodySharedSettings.cpp 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485
  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/SoftBodySharedSettings.h>
  6. #include <Jolt/Physics/SoftBody/SoftBodyUpdateContext.h>
  7. #include <Jolt/ObjectStream/TypeDeclarations.h>
  8. #include <Jolt/Core/StreamUtils.h>
  9. #include <Jolt/Core/QuickSort.h>
  10. #include <Jolt/Core/UnorderedSet.h>
  11. #include <Jolt/Core/BinaryHeap.h>
  12. JPH_NAMESPACE_BEGIN
  13. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Vertex)
  14. {
  15. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Vertex, mPosition)
  16. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Vertex, mVelocity)
  17. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Vertex, mInvMass)
  18. }
  19. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Face)
  20. {
  21. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Face, mVertex)
  22. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Face, mMaterialIndex)
  23. }
  24. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Edge)
  25. {
  26. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Edge, mVertex)
  27. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Edge, mRestLength)
  28. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Edge, mCompliance)
  29. }
  30. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::RodStretchShear)
  31. {
  32. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::RodStretchShear, mVertex)
  33. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::RodStretchShear, mLength)
  34. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::RodStretchShear, mInvMass)
  35. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::RodStretchShear, mCompliance)
  36. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::RodStretchShear, mBishop)
  37. }
  38. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::RodBendTwist)
  39. {
  40. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::RodBendTwist, mRod)
  41. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::RodBendTwist, mCompliance)
  42. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::RodBendTwist, mOmega0)
  43. }
  44. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::DihedralBend)
  45. {
  46. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::DihedralBend, mVertex)
  47. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::DihedralBend, mCompliance)
  48. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::DihedralBend, mInitialAngle)
  49. }
  50. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Volume)
  51. {
  52. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Volume, mVertex)
  53. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Volume, mSixRestVolume)
  54. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Volume, mCompliance)
  55. }
  56. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::InvBind)
  57. {
  58. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::InvBind, mJointIndex)
  59. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::InvBind, mInvBind)
  60. }
  61. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::SkinWeight)
  62. {
  63. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::SkinWeight, mInvBindIndex)
  64. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::SkinWeight, mWeight)
  65. }
  66. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Skinned)
  67. {
  68. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Skinned, mVertex)
  69. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Skinned, mWeights)
  70. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Skinned, mMaxDistance)
  71. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Skinned, mBackStopDistance)
  72. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Skinned, mBackStopRadius)
  73. }
  74. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::LRA)
  75. {
  76. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::LRA, mVertex)
  77. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::LRA, mMaxDistance)
  78. }
  79. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings)
  80. {
  81. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mVertices)
  82. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mFaces)
  83. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mEdgeConstraints)
  84. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mDihedralBendConstraints)
  85. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mVolumeConstraints)
  86. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mSkinnedConstraints)
  87. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mInvBindMatrices)
  88. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mLRAConstraints)
  89. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mRodStretchShearConstraints)
  90. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mRodBendTwistConstraints)
  91. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mMaterials)
  92. }
  93. void SoftBodySharedSettings::CalculateClosestKinematic()
  94. {
  95. // Check if we already calculated this
  96. if (!mClosestKinematic.empty())
  97. return;
  98. // Reserve output size
  99. mClosestKinematic.resize(mVertices.size());
  100. // Create a list of connected vertices
  101. Array<Array<uint32>> connectivity;
  102. connectivity.resize(mVertices.size());
  103. for (const Edge &e : mEdgeConstraints)
  104. {
  105. connectivity[e.mVertex[0]].push_back(e.mVertex[1]);
  106. connectivity[e.mVertex[1]].push_back(e.mVertex[0]);
  107. }
  108. for (const RodStretchShear &r : mRodStretchShearConstraints)
  109. {
  110. connectivity[r.mVertex[0]].push_back(r.mVertex[1]);
  111. connectivity[r.mVertex[1]].push_back(r.mVertex[0]);
  112. }
  113. // Use Dijkstra's algorithm to find the closest kinematic vertex for each vertex
  114. // See: https://en.wikipedia.org/wiki/Dijkstra's_algorithm
  115. //
  116. // An element in the open list
  117. struct Open
  118. {
  119. // Order so that we get the shortest distance first
  120. bool operator < (const Open &inRHS) const
  121. {
  122. return mDistance > inRHS.mDistance;
  123. }
  124. uint32 mVertex;
  125. float mDistance;
  126. };
  127. // Start with all kinematic elements
  128. Array<Open> to_visit;
  129. for (uint32 v = 0; v < mVertices.size(); ++v)
  130. if (mVertices[v].mInvMass == 0.0f)
  131. {
  132. mClosestKinematic[v].mVertex = v;
  133. mClosestKinematic[v].mHops = 0;
  134. mClosestKinematic[v].mDistance = 0.0f;
  135. to_visit.push_back({ v, 0.0f });
  136. BinaryHeapPush(to_visit.begin(), to_visit.end(), std::less<Open> { });
  137. }
  138. // Visit all vertices remembering the closest kinematic vertex and its distance
  139. JPH_IF_ENABLE_ASSERTS(float last_closest = 0.0f;)
  140. while (!to_visit.empty())
  141. {
  142. // Pop element from the open list
  143. BinaryHeapPop(to_visit.begin(), to_visit.end(), std::less<Open> { });
  144. Open current = to_visit.back();
  145. to_visit.pop_back();
  146. JPH_ASSERT(current.mDistance >= last_closest);
  147. JPH_IF_ENABLE_ASSERTS(last_closest = current.mDistance;)
  148. // Loop through all of its connected vertices
  149. for (uint32 v : connectivity[current.mVertex])
  150. {
  151. // Calculate distance from the current vertex to this target vertex and check if it is smaller
  152. float new_distance = current.mDistance + (Vec3(mVertices[v].mPosition) - Vec3(mVertices[current.mVertex].mPosition)).Length();
  153. if (new_distance < mClosestKinematic[v].mDistance)
  154. {
  155. // Remember new closest vertex
  156. mClosestKinematic[v].mVertex = mClosestKinematic[current.mVertex].mVertex;
  157. mClosestKinematic[v].mHops = mClosestKinematic[current.mVertex].mHops + 1;
  158. mClosestKinematic[v].mDistance = new_distance;
  159. to_visit.push_back({ v, new_distance });
  160. BinaryHeapPush(to_visit.begin(), to_visit.end(), std::less<Open> { });
  161. }
  162. }
  163. }
  164. }
  165. void SoftBodySharedSettings::CreateConstraints(const VertexAttributes *inVertexAttributes, uint inVertexAttributesLength, EBendType inBendType, float inAngleTolerance)
  166. {
  167. struct EdgeHelper
  168. {
  169. uint32 mVertex[2];
  170. uint32 mEdgeIdx;
  171. };
  172. // Create list of all edges
  173. Array<EdgeHelper> edges;
  174. edges.reserve(mFaces.size() * 3);
  175. for (const Face &f : mFaces)
  176. for (int i = 0; i < 3; ++i)
  177. {
  178. uint32 v0 = f.mVertex[i];
  179. uint32 v1 = f.mVertex[(i + 1) % 3];
  180. EdgeHelper e;
  181. e.mVertex[0] = min(v0, v1);
  182. e.mVertex[1] = max(v0, v1);
  183. e.mEdgeIdx = uint32(&f - mFaces.data()) * 3 + i;
  184. edges.push_back(e);
  185. }
  186. // Sort the edges
  187. QuickSort(edges.begin(), edges.end(), [](const EdgeHelper &inLHS, const EdgeHelper &inRHS) { return inLHS.mVertex[0] < inRHS.mVertex[0] || (inLHS.mVertex[0] == inRHS.mVertex[0] && inLHS.mVertex[1] < inRHS.mVertex[1]); });
  188. // Only add edges if one of the vertices is movable
  189. auto add_edge = [this](uint32 inVtx1, uint32 inVtx2, float inCompliance1, float inCompliance2) {
  190. if ((mVertices[inVtx1].mInvMass > 0.0f || mVertices[inVtx2].mInvMass > 0.0f)
  191. && inCompliance1 < FLT_MAX && inCompliance2 < FLT_MAX)
  192. {
  193. Edge temp_edge;
  194. temp_edge.mVertex[0] = inVtx1;
  195. temp_edge.mVertex[1] = inVtx2;
  196. temp_edge.mCompliance = 0.5f * (inCompliance1 + inCompliance2);
  197. temp_edge.mRestLength = (Vec3(mVertices[inVtx2].mPosition) - Vec3(mVertices[inVtx1].mPosition)).Length();
  198. JPH_ASSERT(temp_edge.mRestLength > 0.0f);
  199. mEdgeConstraints.push_back(temp_edge);
  200. }
  201. };
  202. // Helper function to get the attributes of a vertex
  203. auto attr = [inVertexAttributes, inVertexAttributesLength](uint32 inVertex) {
  204. return inVertexAttributes[min(inVertex, inVertexAttributesLength - 1)];
  205. };
  206. // Create the constraints
  207. float sq_sin_tolerance = Square(Sin(inAngleTolerance));
  208. float sq_cos_tolerance = Square(Cos(inAngleTolerance));
  209. mEdgeConstraints.clear();
  210. mEdgeConstraints.reserve(edges.size());
  211. for (Array<EdgeHelper>::size_type i = 0; i < edges.size(); ++i)
  212. {
  213. const EdgeHelper &e0 = edges[i];
  214. // Get attributes for the vertices of the edge
  215. const VertexAttributes &a0 = attr(e0.mVertex[0]);
  216. const VertexAttributes &a1 = attr(e0.mVertex[1]);
  217. // Flag that indicates if this edge is a shear edge (if 2 triangles form a quad-like shape and this edge is on the diagonal)
  218. bool is_shear = false;
  219. // Test if there are any shared edges
  220. for (Array<EdgeHelper>::size_type j = i + 1; j < edges.size(); ++j)
  221. {
  222. const EdgeHelper &e1 = edges[j];
  223. if (e0.mVertex[0] == e1.mVertex[0] && e0.mVertex[1] == e1.mVertex[1])
  224. {
  225. // Get opposing vertices
  226. const Face &f0 = mFaces[e0.mEdgeIdx / 3];
  227. const Face &f1 = mFaces[e1.mEdgeIdx / 3];
  228. uint32 vopposite0 = f0.mVertex[(e0.mEdgeIdx + 2) % 3];
  229. uint32 vopposite1 = f1.mVertex[(e1.mEdgeIdx + 2) % 3];
  230. const VertexAttributes &a_opposite0 = attr(vopposite0);
  231. const VertexAttributes &a_opposite1 = attr(vopposite1);
  232. // If the opposite vertices happen to be the same vertex then we have 2 triangles back to back and we skip creating shear / bend constraints
  233. if (vopposite0 == vopposite1)
  234. continue;
  235. // Faces should be roughly in a plane
  236. Vec3 n0 = (Vec3(mVertices[f0.mVertex[2]].mPosition) - Vec3(mVertices[f0.mVertex[0]].mPosition)).Cross(Vec3(mVertices[f0.mVertex[1]].mPosition) - Vec3(mVertices[f0.mVertex[0]].mPosition));
  237. Vec3 n1 = (Vec3(mVertices[f1.mVertex[2]].mPosition) - Vec3(mVertices[f1.mVertex[0]].mPosition)).Cross(Vec3(mVertices[f1.mVertex[1]].mPosition) - Vec3(mVertices[f1.mVertex[0]].mPosition));
  238. float n0_dot_n1 = n0.Dot(n1);
  239. if (n0_dot_n1 > 0.0f
  240. && Square(n0_dot_n1) > sq_cos_tolerance * n0.LengthSq() * n1.LengthSq())
  241. {
  242. // Faces should approximately form a quad
  243. Vec3 e0_dir = Vec3(mVertices[vopposite0].mPosition) - Vec3(mVertices[e0.mVertex[0]].mPosition);
  244. Vec3 e1_dir = Vec3(mVertices[vopposite1].mPosition) - Vec3(mVertices[e0.mVertex[0]].mPosition);
  245. if (Square(e0_dir.Dot(e1_dir)) < sq_sin_tolerance * e0_dir.LengthSq() * e1_dir.LengthSq())
  246. {
  247. // Shear constraint
  248. add_edge(vopposite0, vopposite1, a_opposite0.mShearCompliance, a_opposite1.mShearCompliance);
  249. is_shear = true;
  250. }
  251. }
  252. // Bend constraint
  253. switch (inBendType)
  254. {
  255. case EBendType::None:
  256. // Do nothing
  257. break;
  258. case EBendType::Distance:
  259. // Create an edge constraint to represent the bend constraint
  260. // Use the bend compliance of the shared edge
  261. if (!is_shear)
  262. add_edge(vopposite0, vopposite1, a0.mBendCompliance, a1.mBendCompliance);
  263. break;
  264. case EBendType::Dihedral:
  265. // Test if both opposite vertices are free to move
  266. if ((mVertices[vopposite0].mInvMass > 0.0f || mVertices[vopposite1].mInvMass > 0.0f)
  267. && a0.mBendCompliance < FLT_MAX && a1.mBendCompliance < FLT_MAX)
  268. {
  269. // Create a bend constraint
  270. // Use the bend compliance of the shared edge
  271. mDihedralBendConstraints.emplace_back(e0.mVertex[0], e0.mVertex[1], vopposite0, vopposite1, 0.5f * (a0.mBendCompliance + a1.mBendCompliance));
  272. }
  273. break;
  274. }
  275. }
  276. else
  277. {
  278. // Start iterating from the first non-shared edge
  279. i = j - 1;
  280. break;
  281. }
  282. }
  283. // Create a edge constraint for the current edge
  284. add_edge(e0.mVertex[0], e0.mVertex[1], is_shear? a0.mShearCompliance : a0.mCompliance, is_shear? a1.mShearCompliance : a1.mCompliance);
  285. }
  286. mEdgeConstraints.shrink_to_fit();
  287. // Calculate the initial angle for all bend constraints
  288. CalculateBendConstraintConstants();
  289. // Check if any vertices have LRA constraints
  290. bool has_lra_constraints = false;
  291. for (const VertexAttributes *va = inVertexAttributes; va < inVertexAttributes + inVertexAttributesLength; ++va)
  292. if (va->mLRAType != ELRAType::None)
  293. {
  294. has_lra_constraints = true;
  295. break;
  296. }
  297. if (has_lra_constraints)
  298. {
  299. // Ensure we have calculated the closest kinematic vertex for each vertex
  300. CalculateClosestKinematic();
  301. // Find non-kinematic vertices
  302. for (uint32 v = 0; v < (uint32)mVertices.size(); ++v)
  303. if (mVertices[v].mInvMass > 0.0f)
  304. {
  305. // Check if a closest vertex was found
  306. uint32 closest = mClosestKinematic[v].mVertex;
  307. if (closest != 0xffffffff)
  308. {
  309. // Check which LRA constraint to create
  310. const VertexAttributes &va = attr(v);
  311. switch (va.mLRAType)
  312. {
  313. case ELRAType::None:
  314. break;
  315. case ELRAType::EuclideanDistance:
  316. mLRAConstraints.emplace_back(closest, v, va.mLRAMaxDistanceMultiplier * (Vec3(mVertices[closest].mPosition) - Vec3(mVertices[v].mPosition)).Length());
  317. break;
  318. case ELRAType::GeodesicDistance:
  319. mLRAConstraints.emplace_back(closest, v, va.mLRAMaxDistanceMultiplier * mClosestKinematic[v].mDistance);
  320. break;
  321. }
  322. }
  323. }
  324. }
  325. }
  326. void SoftBodySharedSettings::CalculateEdgeLengths()
  327. {
  328. for (Edge &e : mEdgeConstraints)
  329. {
  330. JPH_ASSERT(e.mVertex[0] != e.mVertex[1], "Edges need to connect 2 different vertices");
  331. e.mRestLength = (Vec3(mVertices[e.mVertex[1]].mPosition) - Vec3(mVertices[e.mVertex[0]].mPosition)).Length();
  332. JPH_ASSERT(e.mRestLength > 0.0f);
  333. }
  334. }
  335. void SoftBodySharedSettings::CalculateRodProperties()
  336. {
  337. // Mark connections through bend twist constraints
  338. Array<Array<uint32>> connections;
  339. connections.resize(mRodStretchShearConstraints.size());
  340. for (const RodBendTwist &c : mRodBendTwistConstraints)
  341. {
  342. JPH_ASSERT(c.mRod[0] != c.mRod[1], "A bend twist constraint needs to be attached to different rods");
  343. connections[c.mRod[1]].push_back(c.mRod[0]);
  344. connections[c.mRod[0]].push_back(c.mRod[1]);
  345. }
  346. // Now calculate the Bishop frames for all rods
  347. struct Entry
  348. {
  349. uint32 mFrom; // Rod we're coming from
  350. uint32 mTo; // Rod we're going to
  351. };
  352. Array<Entry> stack;
  353. stack.reserve(mRodStretchShearConstraints.size());
  354. for (uint32 r0_idx = 0; r0_idx < mRodStretchShearConstraints.size(); ++r0_idx)
  355. {
  356. RodStretchShear &r0 = mRodStretchShearConstraints[r0_idx];
  357. // Do not calculate a 2nd time
  358. if (r0.mBishop == Quat::sZero())
  359. {
  360. // Calculate the frame for this rod
  361. {
  362. Vec3 tangent = Vec3(mVertices[r0.mVertex[1]].mPosition) - Vec3(mVertices[r0.mVertex[0]].mPosition);
  363. r0.mLength = tangent.Length();
  364. JPH_ASSERT(r0.mLength > 0.0f, "Rods of zero length are not supported!");
  365. tangent /= r0.mLength;
  366. Vec3 normal = tangent.GetNormalizedPerpendicular();
  367. Vec3 binormal = tangent.Cross(normal);
  368. r0.mBishop = Mat44(Vec4(normal, 0), Vec4(binormal, 0), Vec4(tangent, 0), Vec4(0, 0, 0, 1)).GetQuaternion().Normalized();
  369. }
  370. // Add connected rods to the stack if they haven't been calculated yet
  371. for (uint32 r1_idx : connections[r0_idx])
  372. if (mRodStretchShearConstraints[r1_idx].mBishop == Quat::sZero())
  373. stack.push_back({ r0_idx, r1_idx });
  374. // Now connect the bishop frame for all connected rods on the stack
  375. // This follows the procedure outlined in "Discrete Elastic Rods" - M. Bergou et al.
  376. // See: https://www.cs.columbia.edu/cg/pdfs/143-rods.pdf
  377. while (!stack.empty())
  378. {
  379. uint32 r1_idx = stack.back().mFrom;
  380. uint32 r2_idx = stack.back().mTo;
  381. stack.pop_back();
  382. const RodStretchShear &r1 = mRodStretchShearConstraints[r1_idx];
  383. RodStretchShear &r2 = mRodStretchShearConstraints[r2_idx];
  384. // Get the normal and tangent of the first rod's Bishop frame (that was already calculated)
  385. Mat44 r1_frame = Mat44::sRotation(r1.mBishop);
  386. Vec3 tangent1 = r1_frame.GetAxisZ();
  387. Vec3 normal1 = r1_frame.GetAxisX();
  388. // Calculate the Bishop frame for the 2nd rod
  389. Vec3 tangent2 = Vec3(mVertices[r2.mVertex[1]].mPosition) - Vec3(mVertices[r2.mVertex[0]].mPosition);
  390. if (tangent1.Dot(tangent2) < 0.0f)
  391. {
  392. // Edge is oriented in the opposite direction of the previous edge, flip it
  393. std::swap(r2.mVertex[0], r2.mVertex[1]);
  394. tangent2 = -tangent2;
  395. }
  396. r2.mLength = tangent2.Length();
  397. JPH_ASSERT(r2.mLength > 0.0f, "Rods of zero length are not supported!");
  398. tangent2 /= r2.mLength;
  399. Vec3 t1_cross_t2 = tangent1.Cross(tangent2);
  400. float sin_angle = t1_cross_t2.Length();
  401. Vec3 normal2 = normal1;
  402. if (sin_angle > 1.0e-6f)
  403. {
  404. t1_cross_t2 /= sin_angle;
  405. normal2 = Quat::sRotation(t1_cross_t2, ASin(sin_angle)) * normal2;
  406. }
  407. Vec3 binormal2 = tangent2.Cross(normal2);
  408. r2.mBishop = Mat44(Vec4(normal2, 0), Vec4(binormal2, 0), Vec4(tangent2, 0), Vec4(0, 0, 0, 1)).GetQuaternion().Normalized();
  409. // Add connected rods to the stack if they haven't been calculated yet
  410. for (uint32 r3_idx : connections[r2_idx])
  411. if (mRodStretchShearConstraints[r3_idx].mBishop == Quat::sZero())
  412. stack.push_back({ r2_idx, r3_idx });
  413. }
  414. }
  415. }
  416. // Calculate inverse mass for all rods by taking the minimum inverse mass (aka the heaviest vertex) of both vertices
  417. for (RodStretchShear &r : mRodStretchShearConstraints)
  418. {
  419. JPH_ASSERT(r.mVertex[0] != r.mVertex[1], "A rod stretch shear constraint requires two different vertices");
  420. r.mInvMass = min(mVertices[r.mVertex[0]].mInvMass, mVertices[r.mVertex[1]].mInvMass);
  421. }
  422. // Calculate the initial rotation between the rods
  423. for (RodBendTwist &r : mRodBendTwistConstraints)
  424. r.mOmega0 = (mRodStretchShearConstraints[r.mRod[0]].mBishop.Conjugated() * mRodStretchShearConstraints[r.mRod[1]].mBishop).Normalized();
  425. }
  426. void SoftBodySharedSettings::CalculateLRALengths(float inMaxDistanceMultiplier)
  427. {
  428. for (LRA &l : mLRAConstraints)
  429. {
  430. JPH_ASSERT(l.mVertex[0] != l.mVertex[1], "LRA constraints need to connect 2 different vertices");
  431. l.mMaxDistance = inMaxDistanceMultiplier * (Vec3(mVertices[l.mVertex[1]].mPosition) - Vec3(mVertices[l.mVertex[0]].mPosition)).Length();
  432. JPH_ASSERT(l.mMaxDistance > 0.0f);
  433. }
  434. }
  435. void SoftBodySharedSettings::CalculateBendConstraintConstants()
  436. {
  437. for (DihedralBend &b : mDihedralBendConstraints)
  438. {
  439. JPH_ASSERT(b.mVertex[0] != b.mVertex[1] && b.mVertex[0] != b.mVertex[2] && b.mVertex[0] != b.mVertex[3]
  440. && b.mVertex[1] != b.mVertex[2] && b.mVertex[1] != b.mVertex[3]
  441. && b.mVertex[2] != b.mVertex[3], "Bend constraints need 4 different vertices");
  442. // Get positions
  443. Vec3 x0 = Vec3(mVertices[b.mVertex[0]].mPosition);
  444. Vec3 x1 = Vec3(mVertices[b.mVertex[1]].mPosition);
  445. Vec3 x2 = Vec3(mVertices[b.mVertex[2]].mPosition);
  446. Vec3 x3 = Vec3(mVertices[b.mVertex[3]].mPosition);
  447. /*
  448. x2
  449. e1/ \e3
  450. / \
  451. x0----x1
  452. \ e0 /
  453. e2\ /e4
  454. x3
  455. */
  456. // Calculate edges
  457. Vec3 e0 = x1 - x0;
  458. Vec3 e1 = x2 - x0;
  459. Vec3 e2 = x3 - x0;
  460. // Normals of both triangles
  461. Vec3 n1 = e0.Cross(e1);
  462. Vec3 n2 = e2.Cross(e0);
  463. float denom = sqrt(n1.LengthSq() * n2.LengthSq());
  464. if (denom < 1.0e-12f)
  465. b.mInitialAngle = 0.0f;
  466. else
  467. {
  468. float sign = Sign(n2.Cross(n1).Dot(e0));
  469. b.mInitialAngle = sign * ACosApproximate(n1.Dot(n2) / denom); // Runtime uses the approximation too
  470. }
  471. }
  472. }
  473. void SoftBodySharedSettings::CalculateVolumeConstraintVolumes()
  474. {
  475. for (Volume &v : mVolumeConstraints)
  476. {
  477. JPH_ASSERT(v.mVertex[0] != v.mVertex[1] && v.mVertex[0] != v.mVertex[2] && v.mVertex[0] != v.mVertex[3]
  478. && v.mVertex[1] != v.mVertex[2] && v.mVertex[1] != v.mVertex[3]
  479. && v.mVertex[2] != v.mVertex[3], "Volume constraints need 4 different vertices");
  480. Vec3 x1(mVertices[v.mVertex[0]].mPosition);
  481. Vec3 x2(mVertices[v.mVertex[1]].mPosition);
  482. Vec3 x3(mVertices[v.mVertex[2]].mPosition);
  483. Vec3 x4(mVertices[v.mVertex[3]].mPosition);
  484. Vec3 x1x2 = x2 - x1;
  485. Vec3 x1x3 = x3 - x1;
  486. Vec3 x1x4 = x4 - x1;
  487. v.mSixRestVolume = abs(x1x2.Cross(x1x3).Dot(x1x4));
  488. }
  489. }
  490. void SoftBodySharedSettings::CalculateSkinnedConstraintNormals()
  491. {
  492. // Clear any previous results
  493. mSkinnedConstraintNormals.clear();
  494. // If there are no skinned constraints, we're done
  495. if (mSkinnedConstraints.empty())
  496. return;
  497. // First collect all vertices that are skinned
  498. using VertexIndexSet = UnorderedSet<uint32>;
  499. VertexIndexSet skinned_vertices;
  500. skinned_vertices.reserve(VertexIndexSet::size_type(mSkinnedConstraints.size()));
  501. for (const Skinned &s : mSkinnedConstraints)
  502. skinned_vertices.insert(s.mVertex);
  503. // Now collect all faces that connect only to skinned vertices
  504. using ConnectedFacesMap = UnorderedMap<uint32, VertexIndexSet>;
  505. ConnectedFacesMap connected_faces;
  506. connected_faces.reserve(ConnectedFacesMap::size_type(mVertices.size()));
  507. for (const Face &f : mFaces)
  508. {
  509. // Must connect to only skinned vertices
  510. bool valid = true;
  511. for (uint32 v : f.mVertex)
  512. valid &= skinned_vertices.find(v) != skinned_vertices.end();
  513. if (!valid)
  514. continue;
  515. // Store faces that connect to vertices
  516. for (uint32 v : f.mVertex)
  517. connected_faces[v].insert(uint32(&f - mFaces.data()));
  518. }
  519. // Populate the list of connecting faces per skinned vertex
  520. mSkinnedConstraintNormals.reserve(mFaces.size());
  521. for (Skinned &s : mSkinnedConstraints)
  522. {
  523. uint32 start = uint32(mSkinnedConstraintNormals.size());
  524. JPH_ASSERT((start >> 24) == 0);
  525. ConnectedFacesMap::const_iterator connected_faces_it = connected_faces.find(s.mVertex);
  526. if (connected_faces_it != connected_faces.cend())
  527. {
  528. const VertexIndexSet &faces = connected_faces_it->second;
  529. uint32 num = uint32(faces.size());
  530. JPH_ASSERT(num < 256);
  531. mSkinnedConstraintNormals.insert(mSkinnedConstraintNormals.end(), faces.begin(), faces.end());
  532. QuickSort(mSkinnedConstraintNormals.begin() + start, mSkinnedConstraintNormals.begin() + start + num);
  533. s.mNormalInfo = start + (num << 24);
  534. }
  535. else
  536. s.mNormalInfo = 0;
  537. }
  538. mSkinnedConstraintNormals.shrink_to_fit();
  539. }
  540. void SoftBodySharedSettings::Optimize(OptimizationResults &outResults)
  541. {
  542. // Clear any previous results
  543. mUpdateGroups.clear();
  544. // Create a list of connected vertices
  545. struct Connection
  546. {
  547. uint32 mVertex;
  548. uint32 mCount;
  549. };
  550. Array<Array<Connection>> connectivity;
  551. connectivity.resize(mVertices.size());
  552. auto add_connection = [&connectivity](uint inV1, uint inV2) {
  553. for (int i = 0; i < 2; ++i)
  554. {
  555. bool found = false;
  556. for (Connection &c : connectivity[inV1])
  557. if (c.mVertex == inV2)
  558. {
  559. c.mCount++;
  560. found = true;
  561. break;
  562. }
  563. if (!found)
  564. connectivity[inV1].push_back({ inV2, 1 });
  565. std::swap(inV1, inV2);
  566. }
  567. };
  568. for (const Edge &c : mEdgeConstraints)
  569. add_connection(c.mVertex[0], c.mVertex[1]);
  570. for (const LRA &c : mLRAConstraints)
  571. add_connection(c.mVertex[0], c.mVertex[1]);
  572. for (const RodStretchShear &c : mRodStretchShearConstraints)
  573. add_connection(c.mVertex[0], c.mVertex[1]);
  574. for (const RodBendTwist &c : mRodBendTwistConstraints)
  575. {
  576. add_connection(mRodStretchShearConstraints[c.mRod[0]].mVertex[0], mRodStretchShearConstraints[c.mRod[1]].mVertex[0]);
  577. add_connection(mRodStretchShearConstraints[c.mRod[0]].mVertex[1], mRodStretchShearConstraints[c.mRod[1]].mVertex[0]);
  578. add_connection(mRodStretchShearConstraints[c.mRod[0]].mVertex[0], mRodStretchShearConstraints[c.mRod[1]].mVertex[1]);
  579. add_connection(mRodStretchShearConstraints[c.mRod[0]].mVertex[1], mRodStretchShearConstraints[c.mRod[1]].mVertex[1]);
  580. }
  581. for (const DihedralBend &c : mDihedralBendConstraints)
  582. {
  583. add_connection(c.mVertex[0], c.mVertex[1]);
  584. add_connection(c.mVertex[0], c.mVertex[2]);
  585. add_connection(c.mVertex[0], c.mVertex[3]);
  586. add_connection(c.mVertex[1], c.mVertex[2]);
  587. add_connection(c.mVertex[1], c.mVertex[3]);
  588. add_connection(c.mVertex[2], c.mVertex[3]);
  589. }
  590. for (const Volume &c : mVolumeConstraints)
  591. {
  592. add_connection(c.mVertex[0], c.mVertex[1]);
  593. add_connection(c.mVertex[0], c.mVertex[2]);
  594. add_connection(c.mVertex[0], c.mVertex[3]);
  595. add_connection(c.mVertex[1], c.mVertex[2]);
  596. add_connection(c.mVertex[1], c.mVertex[3]);
  597. add_connection(c.mVertex[2], c.mVertex[3]);
  598. }
  599. // Skinned constraints only update 1 vertex, so we don't need special logic here
  600. // Maps each of the vertices to a group index
  601. Array<int> group_idx;
  602. group_idx.resize(mVertices.size(), -1);
  603. // Which group we are currently filling and its vertices
  604. int current_group_idx = 0;
  605. Array<uint> current_group;
  606. // Start greedy algorithm to group vertices
  607. for (;;)
  608. {
  609. // Find the bounding box of the ungrouped vertices
  610. AABox bounds;
  611. for (uint i = 0; i < (uint)mVertices.size(); ++i)
  612. if (group_idx[i] == -1)
  613. bounds.Encapsulate(Vec3(mVertices[i].mPosition));
  614. // If the bounds are invalid, it means that there were no ungrouped vertices
  615. if (!bounds.IsValid())
  616. break;
  617. // Determine longest and shortest axis
  618. Vec3 bounds_size = bounds.GetSize();
  619. uint max_axis = bounds_size.GetHighestComponentIndex();
  620. uint min_axis = bounds_size.GetLowestComponentIndex();
  621. if (min_axis == max_axis)
  622. min_axis = (min_axis + 1) % 3;
  623. uint mid_axis = 3 - min_axis - max_axis;
  624. // Find the vertex that has the lowest value on the axis with the largest extent
  625. uint current_vertex = UINT_MAX;
  626. Float3 current_vertex_position { FLT_MAX, FLT_MAX, FLT_MAX };
  627. for (uint i = 0; i < (uint)mVertices.size(); ++i)
  628. if (group_idx[i] == -1)
  629. {
  630. const Float3 &vertex_position = mVertices[i].mPosition;
  631. float max_axis_value = vertex_position[max_axis];
  632. float mid_axis_value = vertex_position[mid_axis];
  633. float min_axis_value = vertex_position[min_axis];
  634. if (max_axis_value < current_vertex_position[max_axis]
  635. || (max_axis_value == current_vertex_position[max_axis]
  636. && (mid_axis_value < current_vertex_position[mid_axis]
  637. || (mid_axis_value == current_vertex_position[mid_axis]
  638. && min_axis_value < current_vertex_position[min_axis]))))
  639. {
  640. current_vertex_position = mVertices[i].mPosition;
  641. current_vertex = i;
  642. }
  643. }
  644. if (current_vertex == UINT_MAX)
  645. break;
  646. // Initialize the current group with 1 vertex
  647. current_group.push_back(current_vertex);
  648. group_idx[current_vertex] = current_group_idx;
  649. // Fill up the group
  650. for (;;)
  651. {
  652. // Find the vertex that is most connected to the current group
  653. uint best_vertex = UINT_MAX;
  654. uint best_num_connections = 0;
  655. float best_dist_sq = FLT_MAX;
  656. for (uint i = 0; i < (uint)current_group.size(); ++i) // For all vertices in the current group
  657. for (const Connection &c : connectivity[current_group[i]]) // For all connections to other vertices
  658. {
  659. uint v = c.mVertex;
  660. if (group_idx[v] == -1) // Ungrouped vertices only
  661. {
  662. // Count the number of connections to this group
  663. uint num_connections = 0;
  664. for (const Connection &v2 : connectivity[v])
  665. if (group_idx[v2.mVertex] == current_group_idx)
  666. num_connections += v2.mCount;
  667. // Calculate distance to group centroid
  668. float dist_sq = (Vec3(mVertices[v].mPosition) - Vec3(mVertices[current_group.front()].mPosition)).LengthSq();
  669. if (best_vertex == UINT_MAX
  670. || num_connections > best_num_connections
  671. || (num_connections == best_num_connections && dist_sq < best_dist_sq))
  672. {
  673. best_vertex = v;
  674. best_num_connections = num_connections;
  675. best_dist_sq = dist_sq;
  676. }
  677. }
  678. }
  679. // Add the best vertex to the current group
  680. if (best_vertex != UINT_MAX)
  681. {
  682. current_group.push_back(best_vertex);
  683. group_idx[best_vertex] = current_group_idx;
  684. }
  685. // Create a new group?
  686. if (current_group.size() >= SoftBodyUpdateContext::cVertexConstraintBatch // If full, yes
  687. || (current_group.size() > SoftBodyUpdateContext::cVertexConstraintBatch / 2 && best_vertex == UINT_MAX)) // If half full and we found no connected vertex, yes
  688. {
  689. current_group.clear();
  690. current_group_idx++;
  691. break;
  692. }
  693. // If we didn't find a connected vertex, we need to find a new starting vertex
  694. if (best_vertex == UINT_MAX)
  695. break;
  696. }
  697. }
  698. // If the last group is more than half full, we'll keep it as a separate group, otherwise we merge it with the 'non parallel' group
  699. if (current_group.size() > SoftBodyUpdateContext::cVertexConstraintBatch / 2)
  700. ++current_group_idx;
  701. // We no longer need the current group array, free the memory
  702. current_group.clear();
  703. current_group.shrink_to_fit();
  704. // We're done with the connectivity list, free the memory
  705. connectivity.clear();
  706. connectivity.shrink_to_fit();
  707. // Assign the constraints to their groups
  708. struct Group
  709. {
  710. uint GetSize() const
  711. {
  712. return (uint)mEdgeConstraints.size() + (uint)mLRAConstraints.size() + (uint)mRodStretchShearConstraints.size() + (uint)mRodBendTwistConstraints.size() + (uint)mDihedralBendConstraints.size() + (uint)mVolumeConstraints.size() + (uint)mSkinnedConstraints.size();
  713. }
  714. Array<uint> mEdgeConstraints;
  715. Array<uint> mLRAConstraints;
  716. Array<uint> mRodStretchShearConstraints;
  717. Array<uint> mRodBendTwistConstraints;
  718. Array<uint> mDihedralBendConstraints;
  719. Array<uint> mVolumeConstraints;
  720. Array<uint> mSkinnedConstraints;
  721. };
  722. Array<Group> groups;
  723. groups.resize(current_group_idx + 1); // + non parallel group
  724. for (const Edge &e : mEdgeConstraints)
  725. {
  726. int g1 = group_idx[e.mVertex[0]];
  727. int g2 = group_idx[e.mVertex[1]];
  728. JPH_ASSERT(g1 >= 0 && g2 >= 0);
  729. if (g1 == g2) // In the same group
  730. groups[g1].mEdgeConstraints.push_back(uint(&e - mEdgeConstraints.data()));
  731. else // In different groups -> parallel group
  732. groups.back().mEdgeConstraints.push_back(uint(&e - mEdgeConstraints.data()));
  733. }
  734. for (const LRA &l : mLRAConstraints)
  735. {
  736. int g1 = group_idx[l.mVertex[0]];
  737. int g2 = group_idx[l.mVertex[1]];
  738. JPH_ASSERT(g1 >= 0 && g2 >= 0);
  739. if (g1 == g2) // In the same group
  740. groups[g1].mLRAConstraints.push_back(uint(&l - mLRAConstraints.data()));
  741. else // In different groups -> parallel group
  742. groups.back().mLRAConstraints.push_back(uint(&l - mLRAConstraints.data()));
  743. }
  744. for (const RodStretchShear &r : mRodStretchShearConstraints)
  745. {
  746. int g1 = group_idx[r.mVertex[0]];
  747. int g2 = group_idx[r.mVertex[1]];
  748. JPH_ASSERT(g1 >= 0 && g2 >= 0);
  749. if (g1 == g2) // In the same group
  750. groups[g1].mRodStretchShearConstraints.push_back(uint(&r - mRodStretchShearConstraints.data()));
  751. else // In different groups -> parallel group
  752. groups.back().mRodStretchShearConstraints.push_back(uint(&r - mRodStretchShearConstraints.data()));
  753. }
  754. for (const RodBendTwist &r : mRodBendTwistConstraints)
  755. {
  756. int g1 = group_idx[mRodStretchShearConstraints[r.mRod[0]].mVertex[0]];
  757. int g2 = group_idx[mRodStretchShearConstraints[r.mRod[0]].mVertex[1]];
  758. int g3 = group_idx[mRodStretchShearConstraints[r.mRod[1]].mVertex[0]];
  759. int g4 = group_idx[mRodStretchShearConstraints[r.mRod[1]].mVertex[1]];
  760. JPH_ASSERT(g1 >= 0 && g2 >= 0 && g3 >= 0 && g4 >= 0);
  761. if (g1 == g2 && g1 == g3 && g1 == g4) // In the same group
  762. groups[g1].mRodBendTwistConstraints.push_back(uint(&r - mRodBendTwistConstraints.data()));
  763. else // In different groups -> parallel group
  764. groups.back().mRodBendTwistConstraints.push_back(uint(&r - mRodBendTwistConstraints.data()));
  765. }
  766. for (const DihedralBend &d : mDihedralBendConstraints)
  767. {
  768. int g1 = group_idx[d.mVertex[0]];
  769. int g2 = group_idx[d.mVertex[1]];
  770. int g3 = group_idx[d.mVertex[2]];
  771. int g4 = group_idx[d.mVertex[3]];
  772. JPH_ASSERT(g1 >= 0 && g2 >= 0 && g3 >= 0 && g4 >= 0);
  773. if (g1 == g2 && g1 == g3 && g1 == g4) // In the same group
  774. groups[g1].mDihedralBendConstraints.push_back(uint(&d - mDihedralBendConstraints.data()));
  775. else // In different groups -> parallel group
  776. groups.back().mDihedralBendConstraints.push_back(uint(&d - mDihedralBendConstraints.data()));
  777. }
  778. for (const Volume &v : mVolumeConstraints)
  779. {
  780. int g1 = group_idx[v.mVertex[0]];
  781. int g2 = group_idx[v.mVertex[1]];
  782. int g3 = group_idx[v.mVertex[2]];
  783. int g4 = group_idx[v.mVertex[3]];
  784. JPH_ASSERT(g1 >= 0 && g2 >= 0 && g3 >= 0 && g4 >= 0);
  785. if (g1 == g2 && g1 == g3 && g1 == g4) // In the same group
  786. groups[g1].mVolumeConstraints.push_back(uint(&v - mVolumeConstraints.data()));
  787. else // In different groups -> parallel group
  788. groups.back().mVolumeConstraints.push_back(uint(&v - mVolumeConstraints.data()));
  789. }
  790. for (const Skinned &s : mSkinnedConstraints)
  791. {
  792. int g1 = group_idx[s.mVertex];
  793. JPH_ASSERT(g1 >= 0);
  794. groups[g1].mSkinnedConstraints.push_back(uint(&s - mSkinnedConstraints.data()));
  795. }
  796. // Sort the parallel groups from big to small (this means the big groups will be scheduled first and have more time to complete)
  797. QuickSort(groups.begin(), groups.end() - 1, [](const Group &inLHS, const Group &inRHS) { return inLHS.GetSize() > inRHS.GetSize(); });
  798. // Make sure we know the closest kinematic vertex so we can sort
  799. CalculateClosestKinematic();
  800. // Sort within each group
  801. for (Group &group : groups)
  802. {
  803. // Sort the edge constraints
  804. QuickSort(group.mEdgeConstraints.begin(), group.mEdgeConstraints.end(), [this](uint inLHS, uint inRHS)
  805. {
  806. const Edge &e1 = mEdgeConstraints[inLHS];
  807. const Edge &e2 = mEdgeConstraints[inRHS];
  808. // First sort so that the edge with the smallest distance to a kinematic vertex comes first
  809. float d1 = min(mClosestKinematic[e1.mVertex[0]].mDistance, mClosestKinematic[e1.mVertex[1]].mDistance);
  810. float d2 = min(mClosestKinematic[e2.mVertex[0]].mDistance, mClosestKinematic[e2.mVertex[1]].mDistance);
  811. if (d1 != d2)
  812. return d1 < d2;
  813. // Order the edges so that the ones with the smallest index go first (hoping to get better cache locality when we process the edges).
  814. // Note we could also re-order the vertices but that would be much more of a burden to the end user
  815. uint32 m1 = e1.GetMinVertexIndex();
  816. uint32 m2 = e2.GetMinVertexIndex();
  817. if (m1 != m2)
  818. return m1 < m2;
  819. return inLHS < inRHS;
  820. });
  821. // Sort the LRA constraints
  822. QuickSort(group.mLRAConstraints.begin(), group.mLRAConstraints.end(), [this](uint inLHS, uint inRHS)
  823. {
  824. const LRA &l1 = mLRAConstraints[inLHS];
  825. const LRA &l2 = mLRAConstraints[inRHS];
  826. // First sort so that the longest constraint comes first (meaning the shortest constraint has the most influence on the end result)
  827. // Most of the time there will be a single LRA constraint per vertex and since the LRA constraint only modifies a single vertex,
  828. // updating one constraint will not violate another constraint.
  829. if (l1.mMaxDistance != l2.mMaxDistance)
  830. return l1.mMaxDistance > l2.mMaxDistance;
  831. // Order constraints so that the ones with the smallest index go first
  832. uint32 m1 = l1.GetMinVertexIndex();
  833. uint32 m2 = l2.GetMinVertexIndex();
  834. if (m1 != m2)
  835. return m1 < m2;
  836. return inLHS < inRHS;
  837. });
  838. // Sort the rod stretch shear constraints
  839. QuickSort(group.mRodStretchShearConstraints.begin(), group.mRodStretchShearConstraints.end(), [this](uint inLHS, uint inRHS)
  840. {
  841. const RodStretchShear &r1 = mRodStretchShearConstraints[inLHS];
  842. const RodStretchShear &r2 = mRodStretchShearConstraints[inRHS];
  843. // First sort so that the rod with the smallest distance to a kinematic vertex comes first
  844. float d1 = min(mClosestKinematic[r1.mVertex[0]].mDistance, mClosestKinematic[r1.mVertex[1]].mDistance);
  845. float d2 = min(mClosestKinematic[r2.mVertex[0]].mDistance, mClosestKinematic[r2.mVertex[1]].mDistance);
  846. if (d1 != d2)
  847. return d1 < d2;
  848. // Then sort on the rod that connects to the smallest kinematic vertex
  849. uint32 m1 = min(mClosestKinematic[r1.mVertex[0]].mVertex, mClosestKinematic[r1.mVertex[1]].mVertex);
  850. uint32 m2 = min(mClosestKinematic[r2.mVertex[0]].mVertex, mClosestKinematic[r2.mVertex[1]].mVertex);
  851. if (m1 != m2)
  852. return m1 < m2;
  853. // Order the rods so that the ones with the smallest index go first (hoping to get better cache locality when we process the rods).
  854. m1 = r1.GetMinVertexIndex();
  855. m2 = r2.GetMinVertexIndex();
  856. if (m1 != m2)
  857. return m1 < m2;
  858. return inLHS < inRHS;
  859. });
  860. // Sort the rod bend twist constraints
  861. QuickSort(group.mRodBendTwistConstraints.begin(), group.mRodBendTwistConstraints.end(), [this](uint inLHS, uint inRHS)
  862. {
  863. const RodBendTwist &b1 = mRodBendTwistConstraints[inLHS];
  864. const RodStretchShear &b1_r1 = mRodStretchShearConstraints[b1.mRod[0]];
  865. const RodStretchShear &b1_r2 = mRodStretchShearConstraints[b1.mRod[1]];
  866. const RodBendTwist &b2 = mRodBendTwistConstraints[inRHS];
  867. const RodStretchShear &b2_r1 = mRodStretchShearConstraints[b2.mRod[0]];
  868. const RodStretchShear &b2_r2 = mRodStretchShearConstraints[b2.mRod[1]];
  869. // First sort so that the rod with the smallest number of hops to a kinematic vertex comes first.
  870. // Note that we don't use distance because of the bilateral interleaving below.
  871. uint32 m1 = min(
  872. min(mClosestKinematic[b1_r1.mVertex[0]].mHops, mClosestKinematic[b1_r1.mVertex[1]].mHops),
  873. min(mClosestKinematic[b1_r2.mVertex[0]].mHops, mClosestKinematic[b1_r2.mVertex[1]].mHops));
  874. uint32 m2 = min(
  875. min(mClosestKinematic[b2_r1.mVertex[0]].mHops, mClosestKinematic[b2_r1.mVertex[1]].mHops),
  876. min(mClosestKinematic[b2_r2.mVertex[0]].mHops, mClosestKinematic[b2_r2.mVertex[1]].mHops));
  877. if (m1 != m2)
  878. return m1 < m2;
  879. // Then sort on the rod that connects to the kinematic vertex with lowest index.
  880. // This ensures that we consistently order the rods that are attached to other kinematic constraints.
  881. // Again, this helps bilateral interleaving below.
  882. m1 = min(
  883. min(mClosestKinematic[b1_r1.mVertex[0]].mVertex, mClosestKinematic[b1_r1.mVertex[1]].mVertex),
  884. min(mClosestKinematic[b1_r2.mVertex[0]].mVertex, mClosestKinematic[b1_r2.mVertex[1]].mVertex));
  885. m2 = min(
  886. min(mClosestKinematic[b2_r1.mVertex[0]].mVertex, mClosestKinematic[b2_r1.mVertex[1]].mVertex),
  887. min(mClosestKinematic[b2_r2.mVertex[0]].mVertex, mClosestKinematic[b2_r2.mVertex[1]].mVertex));
  888. if (m1 != m2)
  889. return m1 < m2;
  890. // Finally order so that the smallest vertex index goes first
  891. m1 = min(b1_r1.GetMinVertexIndex(), b1_r2.GetMinVertexIndex());
  892. m2 = min(b2_r1.GetMinVertexIndex(), b2_r2.GetMinVertexIndex());
  893. if (m1 != m2)
  894. return m1 < m2;
  895. return inLHS < inRHS;
  896. });
  897. // Bilateral interleaving, see figure 4 of "Position and Orientation Based Cosserat Rods" - Kugelstadt and Schoemer - SIGGRAPH 2016
  898. // Keeping the twist constraints sorted often results in an unstable simulation
  899. for (Array<uint>::size_type i = 1, s = group.mRodBendTwistConstraints.size(), s2 = s >> 1; i < s2; i += 2)
  900. std::swap(group.mRodBendTwistConstraints[i], group.mRodBendTwistConstraints[s - i]);
  901. // Sort the dihedral bend constraints
  902. QuickSort(group.mDihedralBendConstraints.begin(), group.mDihedralBendConstraints.end(), [this](uint inLHS, uint inRHS)
  903. {
  904. const DihedralBend &b1 = mDihedralBendConstraints[inLHS];
  905. const DihedralBend &b2 = mDihedralBendConstraints[inRHS];
  906. // First sort so that the constraint with the smallest distance to a kinematic vertex comes first
  907. float d1 = min(
  908. min(mClosestKinematic[b1.mVertex[0]].mDistance, mClosestKinematic[b1.mVertex[1]].mDistance),
  909. min(mClosestKinematic[b1.mVertex[2]].mDistance, mClosestKinematic[b1.mVertex[3]].mDistance));
  910. float d2 = min(
  911. min(mClosestKinematic[b2.mVertex[0]].mDistance, mClosestKinematic[b2.mVertex[1]].mDistance),
  912. min(mClosestKinematic[b2.mVertex[2]].mDistance, mClosestKinematic[b2.mVertex[3]].mDistance));
  913. if (d1 != d2)
  914. return d1 < d2;
  915. // Finally order so that the smallest vertex index goes first
  916. uint32 m1 = b1.GetMinVertexIndex();
  917. uint32 m2 = b2.GetMinVertexIndex();
  918. if (m1 != m2)
  919. return m1 < m2;
  920. return inLHS < inRHS;
  921. });
  922. // Sort the volume constraints
  923. QuickSort(group.mVolumeConstraints.begin(), group.mVolumeConstraints.end(), [this](uint inLHS, uint inRHS)
  924. {
  925. const Volume &v1 = mVolumeConstraints[inLHS];
  926. const Volume &v2 = mVolumeConstraints[inRHS];
  927. // First sort so that the constraint with the smallest distance to a kinematic vertex comes first
  928. float d1 = min(
  929. min(mClosestKinematic[v1.mVertex[0]].mDistance, mClosestKinematic[v1.mVertex[1]].mDistance),
  930. min(mClosestKinematic[v1.mVertex[2]].mDistance, mClosestKinematic[v1.mVertex[3]].mDistance));
  931. float d2 = min(
  932. min(mClosestKinematic[v2.mVertex[0]].mDistance, mClosestKinematic[v2.mVertex[1]].mDistance),
  933. min(mClosestKinematic[v2.mVertex[2]].mDistance, mClosestKinematic[v2.mVertex[3]].mDistance));
  934. if (d1 != d2)
  935. return d1 < d2;
  936. // Order constraints so that the ones with the smallest index go first
  937. uint32 m1 = v1.GetMinVertexIndex();
  938. uint32 m2 = v2.GetMinVertexIndex();
  939. if (m1 != m2)
  940. return m1 < m2;
  941. return inLHS < inRHS;
  942. });
  943. // Sort the skinned constraints
  944. QuickSort(group.mSkinnedConstraints.begin(), group.mSkinnedConstraints.end(), [this](uint inLHS, uint inRHS)
  945. {
  946. const Skinned &s1 = mSkinnedConstraints[inLHS];
  947. const Skinned &s2 = mSkinnedConstraints[inRHS];
  948. // Order the skinned constraints so that the ones with the smallest index go first (hoping to get better cache locality when we process the edges).
  949. if (s1.mVertex != s2.mVertex)
  950. return s1.mVertex < s2.mVertex;
  951. return inLHS < inRHS;
  952. });
  953. }
  954. // Temporary store constraints as we reorder them
  955. Array<Edge> temp_edges;
  956. temp_edges.swap(mEdgeConstraints);
  957. mEdgeConstraints.reserve(temp_edges.size());
  958. outResults.mEdgeRemap.resize(temp_edges.size(), ~uint(0));
  959. Array<LRA> temp_lra;
  960. temp_lra.swap(mLRAConstraints);
  961. mLRAConstraints.reserve(temp_lra.size());
  962. outResults.mLRARemap.resize(temp_lra.size(), ~uint(0));
  963. Array<RodStretchShear> temp_rod_stretch_shear;
  964. temp_rod_stretch_shear.swap(mRodStretchShearConstraints);
  965. mRodStretchShearConstraints.reserve(temp_rod_stretch_shear.size());
  966. outResults.mRodStretchShearConstraintRemap.resize(temp_rod_stretch_shear.size(), ~uint(0));
  967. Array<RodBendTwist> temp_rod_bend_twist;
  968. temp_rod_bend_twist.swap(mRodBendTwistConstraints);
  969. mRodBendTwistConstraints.reserve(temp_rod_bend_twist.size());
  970. outResults.mRodBendTwistConstraintRemap.resize(temp_rod_bend_twist.size(), ~uint(0));
  971. Array<DihedralBend> temp_dihedral_bend;
  972. temp_dihedral_bend.swap(mDihedralBendConstraints);
  973. mDihedralBendConstraints.reserve(temp_dihedral_bend.size());
  974. outResults.mDihedralBendRemap.resize(temp_dihedral_bend.size(), ~uint(0));
  975. Array<Volume> temp_volume;
  976. temp_volume.swap(mVolumeConstraints);
  977. mVolumeConstraints.reserve(temp_volume.size());
  978. outResults.mVolumeRemap.resize(temp_volume.size(), ~uint(0));
  979. Array<Skinned> temp_skinned;
  980. temp_skinned.swap(mSkinnedConstraints);
  981. mSkinnedConstraints.reserve(temp_skinned.size());
  982. outResults.mSkinnedRemap.resize(temp_skinned.size(), ~uint(0));
  983. // Finalize update groups
  984. for (const Group &group : groups)
  985. {
  986. // Reorder edge constraints for this group
  987. for (uint idx : group.mEdgeConstraints)
  988. {
  989. outResults.mEdgeRemap[idx] = (uint)mEdgeConstraints.size();
  990. mEdgeConstraints.push_back(temp_edges[idx]);
  991. }
  992. // Reorder LRA constraints for this group
  993. for (uint idx : group.mLRAConstraints)
  994. {
  995. outResults.mLRARemap[idx] = (uint)mLRAConstraints.size();
  996. mLRAConstraints.push_back(temp_lra[idx]);
  997. }
  998. // Reorder rod stretch shear constraints for this group
  999. for (uint idx : group.mRodStretchShearConstraints)
  1000. {
  1001. outResults.mRodStretchShearConstraintRemap[idx] = (uint)mRodStretchShearConstraints.size();
  1002. mRodStretchShearConstraints.push_back(temp_rod_stretch_shear[idx]);
  1003. }
  1004. // Reorder rod bend twist constraints for this group
  1005. for (uint idx : group.mRodBendTwistConstraints)
  1006. {
  1007. outResults.mRodBendTwistConstraintRemap[idx] = (uint)mRodBendTwistConstraints.size();
  1008. mRodBendTwistConstraints.push_back(temp_rod_bend_twist[idx]);
  1009. }
  1010. // Reorder dihedral bend constraints for this group
  1011. for (uint idx : group.mDihedralBendConstraints)
  1012. {
  1013. outResults.mDihedralBendRemap[idx] = (uint)mDihedralBendConstraints.size();
  1014. mDihedralBendConstraints.push_back(temp_dihedral_bend[idx]);
  1015. }
  1016. // Reorder volume constraints for this group
  1017. for (uint idx : group.mVolumeConstraints)
  1018. {
  1019. outResults.mVolumeRemap[idx] = (uint)mVolumeConstraints.size();
  1020. mVolumeConstraints.push_back(temp_volume[idx]);
  1021. }
  1022. // Reorder skinned constraints for this group
  1023. for (uint idx : group.mSkinnedConstraints)
  1024. {
  1025. outResults.mSkinnedRemap[idx] = (uint)mSkinnedConstraints.size();
  1026. mSkinnedConstraints.push_back(temp_skinned[idx]);
  1027. }
  1028. // Store end indices
  1029. mUpdateGroups.push_back({ (uint)mEdgeConstraints.size(), (uint)mLRAConstraints.size(), (uint)mRodStretchShearConstraints.size(), (uint)mRodBendTwistConstraints.size(), (uint)mDihedralBendConstraints.size(), (uint)mVolumeConstraints.size(), (uint)mSkinnedConstraints.size() });
  1030. }
  1031. // Remap bend twist indices because mRodStretchShearConstraints has been reordered
  1032. for (RodBendTwist &r : mRodBendTwistConstraints)
  1033. for (int i = 0; i < 2; ++i)
  1034. r.mRod[i] = outResults.mRodStretchShearConstraintRemap[r.mRod[i]];
  1035. // Free closest kinematic buffer
  1036. mClosestKinematic.clear();
  1037. mClosestKinematic.shrink_to_fit();
  1038. }
  1039. Ref<SoftBodySharedSettings> SoftBodySharedSettings::Clone() const
  1040. {
  1041. Ref<SoftBodySharedSettings> clone = new SoftBodySharedSettings;
  1042. clone->mVertices = mVertices;
  1043. clone->mFaces = mFaces;
  1044. clone->mEdgeConstraints = mEdgeConstraints;
  1045. clone->mDihedralBendConstraints = mDihedralBendConstraints;
  1046. clone->mVolumeConstraints = mVolumeConstraints;
  1047. clone->mSkinnedConstraints = mSkinnedConstraints;
  1048. clone->mSkinnedConstraintNormals = mSkinnedConstraintNormals;
  1049. clone->mInvBindMatrices = mInvBindMatrices;
  1050. clone->mLRAConstraints = mLRAConstraints;
  1051. clone->mRodStretchShearConstraints = mRodStretchShearConstraints;
  1052. clone->mRodBendTwistConstraints = mRodBendTwistConstraints;
  1053. clone->mMaterials = mMaterials;
  1054. clone->mUpdateGroups = mUpdateGroups;
  1055. return clone;
  1056. }
  1057. void SoftBodySharedSettings::SaveBinaryState(StreamOut &inStream) const
  1058. {
  1059. inStream.Write(mVertices);
  1060. inStream.Write(mFaces);
  1061. inStream.Write(mEdgeConstraints);
  1062. inStream.Write(mDihedralBendConstraints);
  1063. inStream.Write(mVolumeConstraints);
  1064. inStream.Write(mSkinnedConstraints);
  1065. inStream.Write(mSkinnedConstraintNormals);
  1066. inStream.Write(mLRAConstraints);
  1067. inStream.Write(mUpdateGroups);
  1068. // Can't write mRodStretchShearConstraints directly because the class contains padding
  1069. inStream.Write(mRodStretchShearConstraints, [](const RodStretchShear &inElement, StreamOut &inS) {
  1070. inS.Write(inElement.mVertex);
  1071. inS.Write(inElement.mLength);
  1072. inS.Write(inElement.mInvMass);
  1073. inS.Write(inElement.mCompliance);
  1074. inS.Write(inElement.mBishop);
  1075. });
  1076. // Can't write mRodBendTwistConstraints directly because the class contains padding
  1077. inStream.Write(mRodBendTwistConstraints, [](const RodBendTwist &inElement, StreamOut &inS) {
  1078. inS.Write(inElement.mRod);
  1079. inS.Write(inElement.mCompliance);
  1080. inS.Write(inElement.mOmega0);
  1081. });
  1082. // Can't write mInvBindMatrices directly because the class contains padding
  1083. inStream.Write(mInvBindMatrices, [](const InvBind &inElement, StreamOut &inS) {
  1084. inS.Write(inElement.mJointIndex);
  1085. inS.Write(inElement.mInvBind);
  1086. });
  1087. }
  1088. void SoftBodySharedSettings::RestoreBinaryState(StreamIn &inStream)
  1089. {
  1090. inStream.Read(mVertices);
  1091. inStream.Read(mFaces);
  1092. inStream.Read(mEdgeConstraints);
  1093. inStream.Read(mDihedralBendConstraints);
  1094. inStream.Read(mVolumeConstraints);
  1095. inStream.Read(mSkinnedConstraints);
  1096. inStream.Read(mSkinnedConstraintNormals);
  1097. inStream.Read(mLRAConstraints);
  1098. inStream.Read(mUpdateGroups);
  1099. inStream.Read(mRodStretchShearConstraints, [](StreamIn &inS, RodStretchShear &outElement) {
  1100. inS.Read(outElement.mVertex);
  1101. inS.Read(outElement.mLength);
  1102. inS.Read(outElement.mInvMass);
  1103. inS.Read(outElement.mCompliance);
  1104. inS.Read(outElement.mBishop);
  1105. });
  1106. inStream.Read(mRodBendTwistConstraints, [](StreamIn &inS, RodBendTwist &outElement) {
  1107. inS.Read(outElement.mRod);
  1108. inS.Read(outElement.mCompliance);
  1109. inS.Read(outElement.mOmega0);
  1110. });
  1111. inStream.Read(mInvBindMatrices, [](StreamIn &inS, InvBind &outElement) {
  1112. inS.Read(outElement.mJointIndex);
  1113. inS.Read(outElement.mInvBind);
  1114. });
  1115. }
  1116. void SoftBodySharedSettings::SaveWithMaterials(StreamOut &inStream, SharedSettingsToIDMap &ioSettingsMap, MaterialToIDMap &ioMaterialMap) const
  1117. {
  1118. SharedSettingsToIDMap::const_iterator settings_iter = ioSettingsMap.find(this);
  1119. if (settings_iter == ioSettingsMap.end())
  1120. {
  1121. // Write settings ID
  1122. uint32 settings_id = ioSettingsMap.size();
  1123. ioSettingsMap[this] = settings_id;
  1124. inStream.Write(settings_id);
  1125. // Write the settings
  1126. SaveBinaryState(inStream);
  1127. // Write materials
  1128. StreamUtils::SaveObjectArray(inStream, mMaterials, &ioMaterialMap);
  1129. }
  1130. else
  1131. {
  1132. // Known settings, just write the ID
  1133. inStream.Write(settings_iter->second);
  1134. }
  1135. }
  1136. SoftBodySharedSettings::SettingsResult SoftBodySharedSettings::sRestoreWithMaterials(StreamIn &inStream, IDToSharedSettingsMap &ioSettingsMap, IDToMaterialMap &ioMaterialMap)
  1137. {
  1138. SettingsResult result;
  1139. // Read settings id
  1140. uint32 settings_id;
  1141. inStream.Read(settings_id);
  1142. if (inStream.IsEOF() || inStream.IsFailed())
  1143. {
  1144. result.SetError("Failed to read settings id");
  1145. return result;
  1146. }
  1147. // Check nullptr settings
  1148. if (settings_id == ~uint32(0))
  1149. {
  1150. result.Set(nullptr);
  1151. return result;
  1152. }
  1153. // Check if we already read this settings
  1154. if (settings_id < ioSettingsMap.size())
  1155. {
  1156. result.Set(ioSettingsMap[settings_id]);
  1157. return result;
  1158. }
  1159. // Create new object
  1160. Ref<SoftBodySharedSettings> settings = new SoftBodySharedSettings;
  1161. // Read state
  1162. settings->RestoreBinaryState(inStream);
  1163. // Read materials
  1164. Result mlresult = StreamUtils::RestoreObjectArray<PhysicsMaterialList>(inStream, ioMaterialMap);
  1165. if (mlresult.HasError())
  1166. {
  1167. result.SetError(mlresult.GetError());
  1168. return result;
  1169. }
  1170. settings->mMaterials = mlresult.Get();
  1171. // Add the settings to the map
  1172. ioSettingsMap.push_back(settings);
  1173. result.Set(settings);
  1174. return result;
  1175. }
  1176. Ref<SoftBodySharedSettings> SoftBodySharedSettings::sCreateCube(uint inGridSize, float inGridSpacing)
  1177. {
  1178. const Vec3 cOffset = Vec3::sReplicate(-0.5f * inGridSpacing * (inGridSize - 1));
  1179. // Create settings
  1180. SoftBodySharedSettings *settings = new SoftBodySharedSettings;
  1181. for (uint z = 0; z < inGridSize; ++z)
  1182. for (uint y = 0; y < inGridSize; ++y)
  1183. for (uint x = 0; x < inGridSize; ++x)
  1184. {
  1185. SoftBodySharedSettings::Vertex v;
  1186. (cOffset + Vec3::sReplicate(inGridSpacing) * Vec3(float(x), float(y), float(z))).StoreFloat3(&v.mPosition);
  1187. settings->mVertices.push_back(v);
  1188. }
  1189. // Function to get the vertex index of a point on the cube
  1190. auto vertex_index = [inGridSize](uint inX, uint inY, uint inZ)
  1191. {
  1192. return inX + inY * inGridSize + inZ * inGridSize * inGridSize;
  1193. };
  1194. // Create edges
  1195. for (uint z = 0; z < inGridSize; ++z)
  1196. for (uint y = 0; y < inGridSize; ++y)
  1197. for (uint x = 0; x < inGridSize; ++x)
  1198. {
  1199. SoftBodySharedSettings::Edge e;
  1200. e.mVertex[0] = vertex_index(x, y, z);
  1201. if (x < inGridSize - 1)
  1202. {
  1203. e.mVertex[1] = vertex_index(x + 1, y, z);
  1204. settings->mEdgeConstraints.push_back(e);
  1205. }
  1206. if (y < inGridSize - 1)
  1207. {
  1208. e.mVertex[1] = vertex_index(x, y + 1, z);
  1209. settings->mEdgeConstraints.push_back(e);
  1210. }
  1211. if (z < inGridSize - 1)
  1212. {
  1213. e.mVertex[1] = vertex_index(x, y, z + 1);
  1214. settings->mEdgeConstraints.push_back(e);
  1215. }
  1216. }
  1217. settings->CalculateEdgeLengths();
  1218. // Tetrahedrons to fill a cube
  1219. const int tetra_indices[6][4][3] = {
  1220. { {0, 0, 0}, {0, 1, 1}, {0, 0, 1}, {1, 1, 1} },
  1221. { {0, 0, 0}, {0, 1, 0}, {0, 1, 1}, {1, 1, 1} },
  1222. { {0, 0, 0}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1} },
  1223. { {0, 0, 0}, {1, 0, 1}, {1, 0, 0}, {1, 1, 1} },
  1224. { {0, 0, 0}, {1, 1, 0}, {0, 1, 0}, {1, 1, 1} },
  1225. { {0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {1, 1, 1} }
  1226. };
  1227. // Create volume constraints
  1228. for (uint z = 0; z < inGridSize - 1; ++z)
  1229. for (uint y = 0; y < inGridSize - 1; ++y)
  1230. for (uint x = 0; x < inGridSize - 1; ++x)
  1231. for (uint t = 0; t < 6; ++t)
  1232. {
  1233. SoftBodySharedSettings::Volume v;
  1234. for (uint i = 0; i < 4; ++i)
  1235. v.mVertex[i] = vertex_index(x + tetra_indices[t][i][0], y + tetra_indices[t][i][1], z + tetra_indices[t][i][2]);
  1236. settings->mVolumeConstraints.push_back(v);
  1237. }
  1238. settings->CalculateVolumeConstraintVolumes();
  1239. // Create faces
  1240. for (uint y = 0; y < inGridSize - 1; ++y)
  1241. for (uint x = 0; x < inGridSize - 1; ++x)
  1242. {
  1243. SoftBodySharedSettings::Face f;
  1244. // Face 1
  1245. f.mVertex[0] = vertex_index(x, y, 0);
  1246. f.mVertex[1] = vertex_index(x, y + 1, 0);
  1247. f.mVertex[2] = vertex_index(x + 1, y + 1, 0);
  1248. settings->AddFace(f);
  1249. f.mVertex[1] = vertex_index(x + 1, y + 1, 0);
  1250. f.mVertex[2] = vertex_index(x + 1, y, 0);
  1251. settings->AddFace(f);
  1252. // Face 2
  1253. f.mVertex[0] = vertex_index(x, y, inGridSize - 1);
  1254. f.mVertex[1] = vertex_index(x + 1, y + 1, inGridSize - 1);
  1255. f.mVertex[2] = vertex_index(x, y + 1, inGridSize - 1);
  1256. settings->AddFace(f);
  1257. f.mVertex[1] = vertex_index(x + 1, y, inGridSize - 1);
  1258. f.mVertex[2] = vertex_index(x + 1, y + 1, inGridSize - 1);
  1259. settings->AddFace(f);
  1260. // Face 3
  1261. f.mVertex[0] = vertex_index(x, 0, y);
  1262. f.mVertex[1] = vertex_index(x + 1, 0, y + 1);
  1263. f.mVertex[2] = vertex_index(x, 0, y + 1);
  1264. settings->AddFace(f);
  1265. f.mVertex[1] = vertex_index(x + 1, 0, y);
  1266. f.mVertex[2] = vertex_index(x + 1, 0, y + 1);
  1267. settings->AddFace(f);
  1268. // Face 4
  1269. f.mVertex[0] = vertex_index(x, inGridSize - 1, y);
  1270. f.mVertex[1] = vertex_index(x, inGridSize - 1, y + 1);
  1271. f.mVertex[2] = vertex_index(x + 1, inGridSize - 1, y + 1);
  1272. settings->AddFace(f);
  1273. f.mVertex[1] = vertex_index(x + 1, inGridSize - 1, y + 1);
  1274. f.mVertex[2] = vertex_index(x + 1, inGridSize - 1, y);
  1275. settings->AddFace(f);
  1276. // Face 5
  1277. f.mVertex[0] = vertex_index(0, x, y);
  1278. f.mVertex[1] = vertex_index(0, x, y + 1);
  1279. f.mVertex[2] = vertex_index(0, x + 1, y + 1);
  1280. settings->AddFace(f);
  1281. f.mVertex[1] = vertex_index(0, x + 1, y + 1);
  1282. f.mVertex[2] = vertex_index(0, x + 1, y);
  1283. settings->AddFace(f);
  1284. // Face 6
  1285. f.mVertex[0] = vertex_index(inGridSize - 1, x, y);
  1286. f.mVertex[1] = vertex_index(inGridSize - 1, x + 1, y + 1);
  1287. f.mVertex[2] = vertex_index(inGridSize - 1, x, y + 1);
  1288. settings->AddFace(f);
  1289. f.mVertex[1] = vertex_index(inGridSize - 1, x + 1, y);
  1290. f.mVertex[2] = vertex_index(inGridSize - 1, x + 1, y + 1);
  1291. settings->AddFace(f);
  1292. }
  1293. // Optimize the settings
  1294. settings->Optimize();
  1295. return settings;
  1296. }
  1297. JPH_NAMESPACE_END