From 2046eca45a557a0a17858150afed71a177fd777f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 16 Jul 2023 14:40:11 +0200 Subject: [PATCH] Add NvCloth fabric reusing for multiple instances of the same cloth mesh --- Source/Engine/Physics/Actors/Cloth.cpp | 55 ++++++----- .../Physics/PhysX/PhysicsBackendPhysX.cpp | 91 ++++++++++++++----- 2 files changed, 101 insertions(+), 45 deletions(-) diff --git a/Source/Engine/Physics/Actors/Cloth.cpp b/Source/Engine/Physics/Actors/Cloth.cpp index df419eeb9..a7ab5fe0e 100644 --- a/Source/Engine/Physics/Actors/Cloth.cpp +++ b/Source/Engine/Physics/Actors/Cloth.cpp @@ -610,6 +610,7 @@ void Cloth::CalculateInvMasses(Array& 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& 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()[index]; - i1 = indicesData.Get()[index + 1]; - i2 = indicesData.Get()[index + 2]; - } - else - { - i0 = indicesData.Get()[index]; - i1 = indicesData.Get()[index + 1]; - i2 = indicesData.Get()[index + 2]; - } + const int32 index = triangleIndex * 3; + const int32 i0 = indicesData.Get()[index]; + const int32 i1 = indicesData.Get()[index + 1]; + const int32 i2 = indicesData.Get()[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()[index]; + const int32 i1 = indicesData.Get()[index + 1]; + const int32 i2 = indicesData.Get()[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 diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index 10d362e3a..801fd07bf 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -156,6 +156,29 @@ struct FabricSettings { int32 Refs; nv::cloth::Vector::Type PhraseTypes; + PhysicsClothDesc Desc; + Array 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::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::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);