SoftBodySharedSettings.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. JPH_NAMESPACE_BEGIN
  12. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Vertex)
  13. {
  14. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Vertex, mPosition)
  15. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Vertex, mVelocity)
  16. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Vertex, mInvMass)
  17. }
  18. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Face)
  19. {
  20. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Face, mVertex)
  21. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Face, mMaterialIndex)
  22. }
  23. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Edge)
  24. {
  25. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Edge, mVertex)
  26. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Edge, mRestLength)
  27. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Edge, mCompliance)
  28. }
  29. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings::Volume)
  30. {
  31. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Volume, mVertex)
  32. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Volume, mSixRestVolume)
  33. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings::Volume, mCompliance)
  34. }
  35. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SoftBodySharedSettings)
  36. {
  37. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mVertices)
  38. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mFaces)
  39. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mEdgeConstraints)
  40. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mEdgeGroupEndIndices)
  41. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mVolumeConstraints)
  42. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mMaterials)
  43. JPH_ADD_ATTRIBUTE(SoftBodySharedSettings, mVertexRadius)
  44. }
  45. void SoftBodySharedSettings::CalculateEdgeLengths()
  46. {
  47. for (Edge &e : mEdgeConstraints)
  48. {
  49. e.mRestLength = (Vec3(mVertices[e.mVertex[1]].mPosition) - Vec3(mVertices[e.mVertex[0]].mPosition)).Length();
  50. JPH_ASSERT(e.mRestLength > 0.0f);
  51. }
  52. }
  53. void SoftBodySharedSettings::CalculateVolumeConstraintVolumes()
  54. {
  55. for (Volume &v : mVolumeConstraints)
  56. {
  57. Vec3 x1(mVertices[v.mVertex[0]].mPosition);
  58. Vec3 x2(mVertices[v.mVertex[1]].mPosition);
  59. Vec3 x3(mVertices[v.mVertex[2]].mPosition);
  60. Vec3 x4(mVertices[v.mVertex[3]].mPosition);
  61. Vec3 x1x2 = x2 - x1;
  62. Vec3 x1x3 = x3 - x1;
  63. Vec3 x1x4 = x4 - x1;
  64. v.mSixRestVolume = abs(x1x2.Cross(x1x3).Dot(x1x4));
  65. }
  66. }
  67. void SoftBodySharedSettings::Optimize(OptimizationResults &outResults)
  68. {
  69. const uint cMaxNumGroups = 32;
  70. const uint cNonParallelGroupIdx = cMaxNumGroups - 1;
  71. const uint cMinimumSize = 2 * SoftBodyUpdateContext::cEdgeConstraintBatch; // There should be at least 2 batches, otherwise there's no point in parallelizing
  72. // Assign edges to non-overlapping groups
  73. Array<uint32> masks;
  74. masks.resize(mVertices.size(), 0);
  75. Array<uint> edge_groups[cMaxNumGroups];
  76. for (const Edge &e : mEdgeConstraints)
  77. {
  78. uint32 &mask1 = masks[e.mVertex[0]];
  79. uint32 &mask2 = masks[e.mVertex[1]];
  80. uint group = min(CountTrailingZeros((~mask1) & (~mask2)), cNonParallelGroupIdx);
  81. uint32 mask = uint32(1U << group);
  82. mask1 |= mask;
  83. mask2 |= mask;
  84. edge_groups[group].push_back(uint(&e - mEdgeConstraints.data()));
  85. }
  86. // Merge groups that are too small into the non-parallel group
  87. for (uint i = 0; i < cNonParallelGroupIdx; ++i)
  88. if (edge_groups[i].size() < cMinimumSize)
  89. {
  90. edge_groups[cNonParallelGroupIdx].insert(edge_groups[cNonParallelGroupIdx].end(), edge_groups[i].begin(), edge_groups[i].end());
  91. edge_groups[i].clear();
  92. }
  93. // Order the edges so that the ones with the smallest index go first (hoping to get better cache locality when we process the edges).
  94. // Note we could also re-order the vertices but that would be much more of a burden to the end user
  95. for (Array<uint> &group : edge_groups)
  96. QuickSort(group.begin(), group.end(), [this](uint inLHS, uint inRHS)
  97. {
  98. const Edge &e1 = mEdgeConstraints[inLHS];
  99. const Edge &e2 = mEdgeConstraints[inRHS];
  100. return min(e1.mVertex[0], e1.mVertex[1]) < min(e2.mVertex[0], e2.mVertex[1]);
  101. });
  102. // Assign the edges to groups and reorder them
  103. Array<Edge> temp_edges;
  104. temp_edges.swap(mEdgeConstraints);
  105. mEdgeConstraints.reserve(temp_edges.size());
  106. for (const Array<uint> &group : edge_groups)
  107. if (!group.empty())
  108. {
  109. for (uint idx : group)
  110. {
  111. mEdgeConstraints.push_back(temp_edges[idx]);
  112. outResults.mEdgeRemap.push_back(idx);
  113. }
  114. mEdgeGroupEndIndices.push_back((uint)mEdgeConstraints.size());
  115. }
  116. // If there is no non-parallel group then add an empty group at the end
  117. if (edge_groups[cNonParallelGroupIdx].empty())
  118. mEdgeGroupEndIndices.push_back((uint)mEdgeConstraints.size());
  119. }
  120. void SoftBodySharedSettings::SaveBinaryState(StreamOut &inStream) const
  121. {
  122. inStream.Write(mVertices);
  123. inStream.Write(mFaces);
  124. inStream.Write(mEdgeConstraints);
  125. inStream.Write(mEdgeGroupEndIndices);
  126. inStream.Write(mVolumeConstraints);
  127. inStream.Write(mVertexRadius);
  128. }
  129. void SoftBodySharedSettings::RestoreBinaryState(StreamIn &inStream)
  130. {
  131. inStream.Read(mVertices);
  132. inStream.Read(mFaces);
  133. inStream.Read(mEdgeConstraints);
  134. inStream.Read(mEdgeGroupEndIndices);
  135. inStream.Read(mVolumeConstraints);
  136. inStream.Read(mVertexRadius);
  137. }
  138. void SoftBodySharedSettings::SaveWithMaterials(StreamOut &inStream, SharedSettingsToIDMap &ioSettingsMap, MaterialToIDMap &ioMaterialMap) const
  139. {
  140. SharedSettingsToIDMap::const_iterator settings_iter = ioSettingsMap.find(this);
  141. if (settings_iter == ioSettingsMap.end())
  142. {
  143. // Write settings ID
  144. uint32 settings_id = (uint32)ioSettingsMap.size();
  145. ioSettingsMap[this] = settings_id;
  146. inStream.Write(settings_id);
  147. // Write the settings
  148. SaveBinaryState(inStream);
  149. // Write materials
  150. StreamUtils::SaveObjectArray(inStream, mMaterials, &ioMaterialMap);
  151. }
  152. else
  153. {
  154. // Known settings, just write the ID
  155. inStream.Write(settings_iter->second);
  156. }
  157. }
  158. SoftBodySharedSettings::SettingsResult SoftBodySharedSettings::sRestoreWithMaterials(StreamIn &inStream, IDToSharedSettingsMap &ioSettingsMap, IDToMaterialMap &ioMaterialMap)
  159. {
  160. SettingsResult result;
  161. // Read settings id
  162. uint32 settings_id;
  163. inStream.Read(settings_id);
  164. if (inStream.IsEOF() || inStream.IsFailed())
  165. {
  166. result.SetError("Failed to read settings id");
  167. return result;
  168. }
  169. // Check nullptr settings
  170. if (settings_id == ~uint32(0))
  171. {
  172. result.Set(nullptr);
  173. return result;
  174. }
  175. // Check if we already read this settings
  176. if (settings_id < ioSettingsMap.size())
  177. {
  178. result.Set(ioSettingsMap[settings_id]);
  179. return result;
  180. }
  181. // Create new object
  182. Ref<SoftBodySharedSettings> settings = new SoftBodySharedSettings;
  183. // Read state
  184. settings->RestoreBinaryState(inStream);
  185. // Read materials
  186. Result mlresult = StreamUtils::RestoreObjectArray<PhysicsMaterialList>(inStream, ioMaterialMap);
  187. if (mlresult.HasError())
  188. {
  189. result.SetError(mlresult.GetError());
  190. return result;
  191. }
  192. settings->mMaterials = mlresult.Get();
  193. // Add the settings to the map
  194. ioSettingsMap.push_back(settings);
  195. result.Set(settings);
  196. return result;
  197. }
  198. JPH_NAMESPACE_END