SoftBodySharedSettings.cpp 6.9 KB

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