Add NvCloth fabric reusing for multiple instances of the same cloth mesh

This commit is contained in:
2023-07-16 14:40:11 +02:00
parent e075a1c6aa
commit 2046eca45a
2 changed files with 101 additions and 45 deletions
+34 -21
View File
@@ -610,6 +610,7 @@ void Cloth::CalculateInvMasses(Array<float>& invMasses)
#if WITH_CLOTH
if (_paint.IsEmpty())
return;
PROFILE_CPU();
// Get mesh data
const ModelInstanceActor::MeshReference mesh = GetMesh();
@@ -630,31 +631,43 @@ void Cloth::CalculateInvMasses(Array<float>& invMasses)
// Sum triangle area for each influenced particle
invMasses.Resize(verticesCount);
Platform::MemoryClear(invMasses.Get(), verticesCount * sizeof(float));
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
if (indices16bit)
{
const int32 index = triangleIndex * 3;
int32 i0, i1, i2;
if (indices16bit)
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
{
i0 = indicesData.Get<uint16>()[index];
i1 = indicesData.Get<uint16>()[index + 1];
i2 = indicesData.Get<uint16>()[index + 2];
}
else
{
i0 = indicesData.Get<uint32>()[index];
i1 = indicesData.Get<uint32>()[index + 1];
i2 = indicesData.Get<uint32>()[index + 2];
}
const int32 index = triangleIndex * 3;
const int32 i0 = indicesData.Get<uint16>()[index];
const int32 i1 = indicesData.Get<uint16>()[index + 1];
const int32 i2 = indicesData.Get<uint16>()[index + 2];
#define GET_POS(i) *(Float3*)((byte*)verticesData.Get() + i * verticesStride)
const Float3 v0(GET_POS(i0));
const Float3 v1(GET_POS(i1));
const Float3 v2(GET_POS(i2));
const Float3 v0(GET_POS(i0));
const Float3 v1(GET_POS(i1));
const Float3 v2(GET_POS(i2));
#undef GET_POS
const float area = Float3::TriangleArea(v0, v1, v2);
invMasses.Get()[i0] += area;
invMasses.Get()[i1] += area;
invMasses.Get()[i2] += area;
const float area = Float3::TriangleArea(v0, v1, v2);
invMasses.Get()[i0] += area;
invMasses.Get()[i1] += area;
invMasses.Get()[i2] += area;
}
}
else
{
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
{
const int32 index = triangleIndex * 3;
const int32 i0 = indicesData.Get<uint32>()[index];
const int32 i1 = indicesData.Get<uint32>()[index + 1];
const int32 i2 = indicesData.Get<uint32>()[index + 2];
#define GET_POS(i) *(Float3*)((byte*)verticesData.Get() + i * verticesStride)
const Float3 v0(GET_POS(i0));
const Float3 v1(GET_POS(i1));
const Float3 v2(GET_POS(i2));
#undef GET_POS
const float area = Float3::TriangleArea(v0, v1, v2);
invMasses.Get()[i0] += area;
invMasses.Get()[i1] += area;
invMasses.Get()[i2] += area;
}
}
// Count fixed vertices which max movement distance is zero
@@ -156,6 +156,29 @@ struct FabricSettings
{
int32 Refs;
nv::cloth::Vector<int32_t>::Type PhraseTypes;
PhysicsClothDesc Desc;
Array<byte> InvMasses;
bool MatchesDesc(const PhysicsClothDesc& r) const
{
if (Desc.VerticesData == r.VerticesData &&
Desc.VerticesStride == r.VerticesStride &&
Desc.VerticesCount == r.VerticesCount &&
Desc.IndicesData == r.IndicesData &&
Desc.IndicesStride == r.IndicesStride &&
Desc.IndicesCount == r.IndicesCount &&
Desc.InvMassesStride == r.InvMassesStride)
{
if (Desc.InvMassesData && r.InvMassesData)
{
bool matches = Platform::MemoryCompare(InvMasses.Get(), r.InvMassesData, r.VerticesCount * r.InvMassesStride) == 0;
return matches;
}
bool matches = !Desc.InvMassesData && !r.InvMassesData;
return matches;
}
return false;
}
};
struct ClothSettings
@@ -1434,7 +1457,6 @@ void PhysicsBackend::EndSimulateScene(void* scene)
PROFILE_CPU_NAMED("Physics.Cloth");
const int32 clothsCount = scenePhysX->ClothSolver->getNumCloths();
nv::cloth::Cloth* const* cloths = scenePhysX->ClothSolver->getClothList();
// TODO: jobify to run in async (eg. with vehicles update and events setup)
{
PROFILE_CPU_NAMED("Pre");
@@ -3384,26 +3406,51 @@ void* PhysicsBackend::CreateCloth(const PhysicsClothDesc& desc)
}
// Cook fabric from the mesh data
nv::cloth::ClothMeshDesc meshDesc;
meshDesc.points.data = desc.VerticesData;
meshDesc.points.stride = desc.VerticesStride;
meshDesc.points.count = desc.VerticesCount;
meshDesc.invMasses.data = desc.InvMassesData;
meshDesc.invMasses.stride = desc.InvMassesStride;
meshDesc.invMasses.count = desc.InvMassesData ? desc.VerticesCount : 0;
meshDesc.triangles.data = desc.IndicesData;
meshDesc.triangles.stride = desc.IndicesStride * 3;
meshDesc.triangles.count = desc.IndicesCount / 3;
if (desc.IndicesStride == sizeof(uint16))
meshDesc.flags |= nv::cloth::MeshFlag::e16_BIT_INDICES;
const Float3 gravity(PhysicsSettings::Get()->DefaultGravity);
nv::cloth::Vector<int32_t>::Type phaseTypeInfo;
// TODO: automatically reuse fabric from existing cloths (simply check for input data used for computations to improve perf when duplicating cloths or with prefab)
nv::cloth::Fabric* fabric = NvClothCookFabricFromMesh(ClothFactory, meshDesc, gravity.Raw, &phaseTypeInfo);
if (!fabric)
nv::cloth::Fabric* fabric = nullptr;
{
LOG(Error, "NvClothCookFabricFromMesh failed");
return nullptr;
for (auto& e : Fabrics)
{
if (e.Value.MatchesDesc(desc))
{
fabric = e.Key;
break;
}
}
if (fabric)
{
Fabrics[fabric].Refs++;
}
else
{
PROFILE_CPU_NAMED("CookFabric");
nv::cloth::ClothMeshDesc meshDesc;
meshDesc.points.data = desc.VerticesData;
meshDesc.points.stride = desc.VerticesStride;
meshDesc.points.count = desc.VerticesCount;
meshDesc.invMasses.data = desc.InvMassesData;
meshDesc.invMasses.stride = desc.InvMassesStride;
meshDesc.invMasses.count = desc.InvMassesData ? desc.VerticesCount : 0;
meshDesc.triangles.data = desc.IndicesData;
meshDesc.triangles.stride = desc.IndicesStride * 3;
meshDesc.triangles.count = desc.IndicesCount / 3;
if (desc.IndicesStride == sizeof(uint16))
meshDesc.flags |= nv::cloth::MeshFlag::e16_BIT_INDICES;
const Float3 gravity(PhysicsSettings::Get()->DefaultGravity);
nv::cloth::Vector<int32_t>::Type phaseTypeInfo;
fabric = NvClothCookFabricFromMesh(ClothFactory, meshDesc, gravity.Raw, &phaseTypeInfo);
if (!fabric)
{
LOG(Error, "NvClothCookFabricFromMesh failed");
return nullptr;
}
FabricSettings fabricSettings;
fabricSettings.Refs = 1;
fabricSettings.PhraseTypes.swap(phaseTypeInfo);
fabricSettings.Desc = desc;
if (desc.InvMassesData)
fabricSettings.InvMasses.Set((byte*)desc.InvMassesData, desc.VerticesCount * desc.InvMassesStride);
Fabrics.Add(fabric, MoveTemp(fabricSettings));
}
}
// Create cloth object
@@ -3438,10 +3485,6 @@ void* PhysicsBackend::CreateCloth(const PhysicsClothDesc& desc)
clothPhysX->setUserData(desc.Actor);
// Setup settings
FabricSettings fabricSettings;
fabricSettings.Refs = 1;
fabricSettings.PhraseTypes.swap(phaseTypeInfo);
Fabrics.Add(fabric, fabricSettings);
ClothSettings clothSettings;
clothSettings.Actor = desc.Actor;
clothSettings.UpdateBounds(clothPhysX);