SoftBodySharedSettings.cpp 54 KB

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