SoftBodyCreator.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2023 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Utils/SoftBodyCreator.h>
  6. namespace SoftBodyCreator {
  7. Ref<SoftBodySharedSettings> CreateCloth(uint inGridSizeX, uint inGridSizeZ, float inGridSpacing, const function<float(uint, uint)> &inVertexGetInvMass)
  8. {
  9. const float cOffsetX = -0.5f * inGridSpacing * (inGridSizeX - 1);
  10. const float cOffsetZ = -0.5f * inGridSpacing * (inGridSizeZ - 1);
  11. // Create settings
  12. SoftBodySharedSettings *settings = new SoftBodySharedSettings;
  13. for (uint z = 0; z < inGridSizeZ; ++z)
  14. for (uint x = 0; x < inGridSizeX; ++x)
  15. {
  16. SoftBodySharedSettings::Vertex v;
  17. v.mPosition = Float3(cOffsetX + x * inGridSpacing, 0.0f, cOffsetZ + z * inGridSpacing);
  18. v.mInvMass = inVertexGetInvMass(x, z);
  19. settings->mVertices.push_back(v);
  20. }
  21. // Function to get the vertex index of a point on the cloth
  22. auto vertex_index = [inGridSizeX](uint inX, uint inY) -> uint
  23. {
  24. return inX + inY * inGridSizeX;
  25. };
  26. // Only add edges if one of the vertices is moveable
  27. auto add_edge = [settings](const SoftBodySharedSettings::Edge &inEdge) {
  28. if (settings->mVertices[inEdge.mVertex[0]].mInvMass > 0.0f || settings->mVertices[inEdge.mVertex[1]].mInvMass > 0.0f)
  29. settings->mEdgeConstraints.push_back(inEdge);
  30. };
  31. // Create edges
  32. for (uint z = 0; z < inGridSizeZ; ++z)
  33. for (uint x = 0; x < inGridSizeX; ++x)
  34. {
  35. SoftBodySharedSettings::Edge e;
  36. e.mCompliance = 0.00001f;
  37. e.mVertex[0] = vertex_index(x, z);
  38. if (x < inGridSizeX - 1)
  39. {
  40. e.mVertex[1] = vertex_index(x + 1, z);
  41. add_edge(e);
  42. }
  43. if (z < inGridSizeZ - 1)
  44. {
  45. e.mVertex[1] = vertex_index(x, z + 1);
  46. add_edge(e);
  47. }
  48. if (x < inGridSizeX - 1 && z < inGridSizeZ - 1)
  49. {
  50. e.mVertex[1] = vertex_index(x + 1, z + 1);
  51. add_edge(e);
  52. e.mVertex[0] = vertex_index(x + 1, z);
  53. e.mVertex[1] = vertex_index(x, z + 1);
  54. add_edge(e);
  55. }
  56. }
  57. settings->CalculateEdgeLengths();
  58. // Create faces
  59. for (uint z = 0; z < inGridSizeZ - 1; ++z)
  60. for (uint x = 0; x < inGridSizeX - 1; ++x)
  61. {
  62. SoftBodySharedSettings::Face f;
  63. f.mVertex[0] = vertex_index(x, z);
  64. f.mVertex[1] = vertex_index(x, z + 1);
  65. f.mVertex[2] = vertex_index(x + 1, z + 1);
  66. settings->AddFace(f);
  67. f.mVertex[1] = vertex_index(x + 1, z + 1);
  68. f.mVertex[2] = vertex_index(x + 1, z);
  69. settings->AddFace(f);
  70. }
  71. // Optimize the settings
  72. settings->Optimize();
  73. return settings;
  74. }
  75. Ref<SoftBodySharedSettings> CreateClothWithFixatedCorners(uint inGridSizeX, uint inGridSizeZ, float inGridSpacing)
  76. {
  77. auto inv_mass = [inGridSizeX, inGridSizeZ](uint inX, uint inZ) {
  78. return (inX == 0 && inZ == 0)
  79. || (inX == inGridSizeX - 1 && inZ == 0)
  80. || (inX == 0 && inZ == inGridSizeZ - 1)
  81. || (inX == inGridSizeX - 1 && inZ == inGridSizeZ - 1)? 0.0f : 1.0f;
  82. };
  83. return CreateCloth(inGridSizeX, inGridSizeZ, inGridSpacing, inv_mass);
  84. }
  85. Ref<SoftBodySharedSettings> CreateCube(uint inGridSize, float inGridSpacing)
  86. {
  87. const Vec3 cOffset = Vec3::sReplicate(-0.5f * inGridSpacing * (inGridSize - 1));
  88. // Create settings
  89. SoftBodySharedSettings *settings = new SoftBodySharedSettings;
  90. for (uint z = 0; z < inGridSize; ++z)
  91. for (uint y = 0; y < inGridSize; ++y)
  92. for (uint x = 0; x < inGridSize; ++x)
  93. {
  94. SoftBodySharedSettings::Vertex v;
  95. (cOffset + Vec3::sReplicate(inGridSpacing) * Vec3(float(x), float(y), float(z))).StoreFloat3(&v.mPosition);
  96. settings->mVertices.push_back(v);
  97. }
  98. // Function to get the vertex index of a point on the cloth
  99. auto vertex_index = [inGridSize](uint inX, uint inY, uint inZ) -> uint
  100. {
  101. return inX + inY * inGridSize + inZ * inGridSize * inGridSize;
  102. };
  103. // Create edges
  104. for (uint z = 0; z < inGridSize; ++z)
  105. for (uint y = 0; y < inGridSize; ++y)
  106. for (uint x = 0; x < inGridSize; ++x)
  107. {
  108. SoftBodySharedSettings::Edge e;
  109. e.mVertex[0] = vertex_index(x, y, z);
  110. if (x < inGridSize - 1)
  111. {
  112. e.mVertex[1] = vertex_index(x + 1, y, z);
  113. settings->mEdgeConstraints.push_back(e);
  114. }
  115. if (y < inGridSize - 1)
  116. {
  117. e.mVertex[1] = vertex_index(x, y + 1, z);
  118. settings->mEdgeConstraints.push_back(e);
  119. }
  120. if (z < inGridSize - 1)
  121. {
  122. e.mVertex[1] = vertex_index(x, y, z + 1);
  123. settings->mEdgeConstraints.push_back(e);
  124. }
  125. }
  126. settings->CalculateEdgeLengths();
  127. // Tetrahedrons to fill a cube
  128. const int tetra_indices[6][4][3] = {
  129. { {0, 0, 0}, {0, 1, 1}, {0, 0, 1}, {1, 1, 1} },
  130. { {0, 0, 0}, {0, 1, 0}, {0, 1, 1}, {1, 1, 1} },
  131. { {0, 0, 0}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1} },
  132. { {0, 0, 0}, {1, 0, 1}, {1, 0, 0}, {1, 1, 1} },
  133. { {0, 0, 0}, {1, 1, 0}, {0, 1, 0}, {1, 1, 1} },
  134. { {0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {1, 1, 1} }
  135. };
  136. // Create volume constraints
  137. for (uint z = 0; z < inGridSize - 1; ++z)
  138. for (uint y = 0; y < inGridSize - 1; ++y)
  139. for (uint x = 0; x < inGridSize - 1; ++x)
  140. for (uint t = 0; t < 6; ++t)
  141. {
  142. SoftBodySharedSettings::Volume v;
  143. for (uint i = 0; i < 4; ++i)
  144. v.mVertex[i] = vertex_index(x + tetra_indices[t][i][0], y + tetra_indices[t][i][1], z + tetra_indices[t][i][2]);
  145. settings->mVolumeConstraints.push_back(v);
  146. }
  147. settings->CalculateVolumeConstraintVolumes();
  148. // Create faces
  149. for (uint y = 0; y < inGridSize - 1; ++y)
  150. for (uint x = 0; x < inGridSize - 1; ++x)
  151. {
  152. SoftBodySharedSettings::Face f;
  153. // Face 1
  154. f.mVertex[0] = vertex_index(x, y, 0);
  155. f.mVertex[1] = vertex_index(x, y + 1, 0);
  156. f.mVertex[2] = vertex_index(x + 1, y + 1, 0);
  157. settings->AddFace(f);
  158. f.mVertex[1] = vertex_index(x + 1, y + 1, 0);
  159. f.mVertex[2] = vertex_index(x + 1, y, 0);
  160. settings->AddFace(f);
  161. // Face 2
  162. f.mVertex[0] = vertex_index(x, y, inGridSize - 1);
  163. f.mVertex[1] = vertex_index(x + 1, y + 1, inGridSize - 1);
  164. f.mVertex[2] = vertex_index(x, y + 1, inGridSize - 1);
  165. settings->AddFace(f);
  166. f.mVertex[1] = vertex_index(x + 1, y, inGridSize - 1);
  167. f.mVertex[2] = vertex_index(x + 1, y + 1, inGridSize - 1);
  168. settings->AddFace(f);
  169. // Face 3
  170. f.mVertex[0] = vertex_index(x, 0, y);
  171. f.mVertex[1] = vertex_index(x + 1, 0, y + 1);
  172. f.mVertex[2] = vertex_index(x, 0, y + 1);
  173. settings->AddFace(f);
  174. f.mVertex[1] = vertex_index(x + 1, 0, y);
  175. f.mVertex[2] = vertex_index(x + 1, 0, y + 1);
  176. settings->AddFace(f);
  177. // Face 4
  178. f.mVertex[0] = vertex_index(x, inGridSize - 1, y);
  179. f.mVertex[1] = vertex_index(x, inGridSize - 1, y + 1);
  180. f.mVertex[2] = vertex_index(x + 1, inGridSize - 1, y + 1);
  181. settings->AddFace(f);
  182. f.mVertex[1] = vertex_index(x + 1, inGridSize - 1, y + 1);
  183. f.mVertex[2] = vertex_index(x + 1, inGridSize - 1, y);
  184. settings->AddFace(f);
  185. // Face 5
  186. f.mVertex[0] = vertex_index(0, x, y);
  187. f.mVertex[1] = vertex_index(0, x, y + 1);
  188. f.mVertex[2] = vertex_index(0, x + 1, y + 1);
  189. settings->AddFace(f);
  190. f.mVertex[1] = vertex_index(0, x + 1, y + 1);
  191. f.mVertex[2] = vertex_index(0, x + 1, y);
  192. settings->AddFace(f);
  193. // Face 6
  194. f.mVertex[0] = vertex_index(inGridSize - 1, x, y);
  195. f.mVertex[1] = vertex_index(inGridSize - 1, x + 1, y + 1);
  196. f.mVertex[2] = vertex_index(inGridSize - 1, x, y + 1);
  197. settings->AddFace(f);
  198. f.mVertex[1] = vertex_index(inGridSize - 1, x + 1, y);
  199. f.mVertex[2] = vertex_index(inGridSize - 1, x + 1, y + 1);
  200. settings->AddFace(f);
  201. }
  202. // Optimize the settings
  203. settings->Optimize();
  204. return settings;
  205. }
  206. Ref<SoftBodySharedSettings> CreateSphere(float inRadius, uint inNumTheta, uint inNumPhi)
  207. {
  208. // Create settings
  209. SoftBodySharedSettings *settings = new SoftBodySharedSettings;
  210. // Create vertices
  211. // NOTE: This is not how you should create a soft body sphere, we explicitly use polar coordinates to make the vertices unevenly distributed.
  212. // Doing it this way tests the pressure algorithm as it receives non-uniform triangles. Better is to use uniform triangles,
  213. // see the use of DebugRenderer::Create8thSphere for an example.
  214. SoftBodySharedSettings::Vertex v;
  215. (inRadius * Vec3::sUnitSpherical(0, 0)).StoreFloat3(&v.mPosition);
  216. settings->mVertices.push_back(v);
  217. (inRadius * Vec3::sUnitSpherical(JPH_PI, 0)).StoreFloat3(&v.mPosition);
  218. settings->mVertices.push_back(v);
  219. for (uint theta = 1; theta < inNumTheta - 1; ++theta)
  220. for (uint phi = 0; phi < inNumPhi; ++phi)
  221. {
  222. (inRadius * Vec3::sUnitSpherical(JPH_PI * theta / (inNumTheta - 1), 2.0f * JPH_PI * phi / inNumPhi)).StoreFloat3(&v.mPosition);
  223. settings->mVertices.push_back(v);
  224. }
  225. // Function to get the vertex index of a point on the sphere
  226. auto vertex_index = [inNumTheta, inNumPhi](uint inTheta, uint inPhi) -> uint
  227. {
  228. if (inTheta == 0)
  229. return 0;
  230. else if (inTheta == inNumTheta - 1)
  231. return 1;
  232. else
  233. return 2 + (inTheta - 1) * inNumPhi + inPhi % inNumPhi;
  234. };
  235. // Create edge constraints
  236. for (uint phi = 0; phi < inNumPhi; ++phi)
  237. {
  238. for (uint theta = 0; theta < inNumTheta - 1; ++theta)
  239. {
  240. SoftBodySharedSettings::Edge e;
  241. e.mCompliance = 0.0001f;
  242. e.mVertex[0] = vertex_index(theta, phi);
  243. e.mVertex[1] = vertex_index(theta + 1, phi);
  244. settings->mEdgeConstraints.push_back(e);
  245. e.mVertex[1] = vertex_index(theta + 1, phi + 1);
  246. settings->mEdgeConstraints.push_back(e);
  247. if (theta > 0)
  248. {
  249. e.mVertex[1] = vertex_index(theta, phi + 1);
  250. settings->mEdgeConstraints.push_back(e);
  251. }
  252. }
  253. }
  254. settings->CalculateEdgeLengths();
  255. // Create faces
  256. SoftBodySharedSettings::Face f;
  257. for (uint phi = 0; phi < inNumPhi; ++phi)
  258. {
  259. for (uint theta = 0; theta < inNumTheta - 2; ++theta)
  260. {
  261. f.mVertex[0] = vertex_index(theta, phi);
  262. f.mVertex[1] = vertex_index(theta + 1, phi);
  263. f.mVertex[2] = vertex_index(theta + 1, phi + 1);
  264. settings->AddFace(f);
  265. if (theta > 0)
  266. {
  267. f.mVertex[1] = vertex_index(theta + 1, phi + 1);
  268. f.mVertex[2] = vertex_index(theta, phi + 1);
  269. settings->AddFace(f);
  270. }
  271. }
  272. f.mVertex[0] = vertex_index(inNumTheta - 2, phi + 1);
  273. f.mVertex[1] = vertex_index(inNumTheta - 2, phi);
  274. f.mVertex[2] = vertex_index(inNumTheta - 1, 0);
  275. settings->AddFace(f);
  276. }
  277. // Optimize the settings
  278. settings->Optimize();
  279. return settings;
  280. }
  281. };