123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AZTestShared/Math/MathTestHelpers.h>
- #include <UnitTestHelper.h>
- #include <TriangleInputHelper.h>
- #include <System/Factory.h>
- #include <System/Fabric.h>
- #include <System/FabricCooker.h>
- #include <System/Cloth.h>
- #include <System/NvTypes.h>
- // NvCloth library includes
- #include <NvCloth/Cloth.h>
- namespace NvCloth
- {
- namespace Internal
- {
- physx::PxVec3& AsPxVec3(AZ::Vector3& azVec);
- const physx::PxVec3& AsPxVec3(const AZ::Vector3& azVec);
- physx::PxQuat& AsPxQuat(AZ::Quaternion& azQuat);
- const physx::PxQuat& AsPxQuat(const AZ::Quaternion& azQuat);
- void FastCopy(const AZStd::vector<AZ::Vector4>& azVector, nv::cloth::Range<physx::PxVec4>& nvRange);
- void FastCopy(const nv::cloth::Range<physx::PxVec4>& nvRange, AZStd::vector<AZ::Vector4>& azVector);
- void FastMove(AZStd::vector<AZ::Vector4>&& azVector, nv::cloth::Range<physx::PxVec4>& nvRange);
- void FastMove(nv::cloth::Range<physx::PxVec4>&& nvRange, AZStd::vector<AZ::Vector4>& azVector);
- } // namespace Internal
- } // namespace NvCloth
- namespace UnitTest
- {
- TEST(NvClothSystem, Cloth_AzVector3AsPxVec3_PxVec3ElementsAreTheSameAsAzVector3)
- {
- AZ::Vector3 zero = AZ::Vector3::CreateZero();
- AZ::Vector3 one = AZ::Vector3::CreateOne();
- AZ::Vector3 axisX = AZ::Vector3::CreateAxisX();
- AZ::Vector3 axisY = AZ::Vector3::CreateAxisY();
- AZ::Vector3 axisZ = AZ::Vector3::CreateAxisZ();
- AZ::Vector3 vec3 = AZ::Vector3(26.0f, -462.366f, 15.384f);
- physx::PxVec3& pxZero = NvCloth::Internal::AsPxVec3(zero);
- physx::PxVec3& pxOne = NvCloth::Internal::AsPxVec3(one);
- physx::PxVec3& pxAxisX = NvCloth::Internal::AsPxVec3(axisX);
- physx::PxVec3& pxAxisY = NvCloth::Internal::AsPxVec3(axisY);
- physx::PxVec3& pxAxisZ = NvCloth::Internal::AsPxVec3(axisZ);
- physx::PxVec3& pxVec3 = NvCloth::Internal::AsPxVec3(vec3);
- ExpectEq(zero, pxZero);
- ExpectEq(one, pxOne);
- ExpectEq(axisX, pxAxisX);
- ExpectEq(axisY, pxAxisY);
- ExpectEq(axisZ, pxAxisZ);
- ExpectEq(vec3, pxVec3);
- }
- TEST(NvClothSystem, Cloth_AzVector3AsPxVec3Const_PxVec3ElementsAreTheSameAsAzVector3)
- {
- const AZ::Vector3 zero = AZ::Vector3::CreateZero();
- const AZ::Vector3 one = AZ::Vector3::CreateOne();
- const AZ::Vector3 axisX = AZ::Vector3::CreateAxisX();
- const AZ::Vector3 axisY = AZ::Vector3::CreateAxisY();
- const AZ::Vector3 axisZ = AZ::Vector3::CreateAxisZ();
- const AZ::Vector3 vec3 = AZ::Vector3(26.0f, -462.366f, 15.384f);
- const physx::PxVec3& pxZero = NvCloth::Internal::AsPxVec3(zero);
- const physx::PxVec3& pxOne = NvCloth::Internal::AsPxVec3(one);
- const physx::PxVec3& pxAxisX = NvCloth::Internal::AsPxVec3(axisX);
- const physx::PxVec3& pxAxisY = NvCloth::Internal::AsPxVec3(axisY);
- const physx::PxVec3& pxAxisZ = NvCloth::Internal::AsPxVec3(axisZ);
- const physx::PxVec3& pxVec3 = NvCloth::Internal::AsPxVec3(vec3);
- ExpectEq(zero, pxZero);
- ExpectEq(one, pxOne);
- ExpectEq(axisX, pxAxisX);
- ExpectEq(axisY, pxAxisY);
- ExpectEq(axisZ, pxAxisZ);
- ExpectEq(vec3, pxVec3);
- }
- TEST(NvClothSystem, Cloth_AzQuaternionAsPxQuat_QuatElementsAreTheSameAsAzQuaternion)
- {
- AZ::Quaternion zero = AZ::Quaternion::CreateZero();
- AZ::Quaternion one = AZ::Quaternion::CreateIdentity();
- AZ::Quaternion rotX = AZ::Quaternion::CreateRotationX(AZ::DegToRad(26.5f));
- AZ::Quaternion rotY = AZ::Quaternion::CreateRotationY(AZ::DegToRad(-196.5f));
- AZ::Quaternion rotZ = AZ::Quaternion::CreateRotationZ(AZ::DegToRad(263.2f));
- AZ::Quaternion quat = AZ::Quaternion(26.0f, -62.366f, 15.384f, 5.0f);
- physx::PxQuat& pxZero = NvCloth::Internal::AsPxQuat(zero);
- physx::PxQuat& pxOne = NvCloth::Internal::AsPxQuat(one);
- physx::PxQuat& pxRotX = NvCloth::Internal::AsPxQuat(rotX);
- physx::PxQuat& pxRotY = NvCloth::Internal::AsPxQuat(rotY);
- physx::PxQuat& pxRotZ = NvCloth::Internal::AsPxQuat(rotZ);
- physx::PxQuat& pxQuat = NvCloth::Internal::AsPxQuat(quat);
- ExpectEq(zero, pxZero);
- ExpectEq(one, pxOne);
- ExpectEq(rotX, pxRotX);
- ExpectEq(rotY, pxRotY);
- ExpectEq(rotZ, pxRotZ);
- ExpectEq(quat, pxQuat);
- }
- TEST(NvClothSystem, Cloth_AzQuaternionAsPxQuatConst_QuatElementsAreTheSameAsAzQuaternion)
- {
- const AZ::Quaternion zero = AZ::Quaternion::CreateZero();
- const AZ::Quaternion one = AZ::Quaternion::CreateIdentity();
- const AZ::Quaternion rotX = AZ::Quaternion::CreateRotationX(AZ::DegToRad(26.5f));
- const AZ::Quaternion rotY = AZ::Quaternion::CreateRotationY(AZ::DegToRad(-196.5f));
- const AZ::Quaternion rotZ = AZ::Quaternion::CreateRotationZ(AZ::DegToRad(263.2f));
- const AZ::Quaternion quat = AZ::Quaternion(26.0f, -62.366f, 15.384f, 5.0f);
- const physx::PxQuat& pxZero = NvCloth::Internal::AsPxQuat(zero);
- const physx::PxQuat& pxOne = NvCloth::Internal::AsPxQuat(one);
- const physx::PxQuat& pxRotX = NvCloth::Internal::AsPxQuat(rotX);
- const physx::PxQuat& pxRotY = NvCloth::Internal::AsPxQuat(rotY);
- const physx::PxQuat& pxRotZ = NvCloth::Internal::AsPxQuat(rotZ);
- const physx::PxQuat& pxQuat = NvCloth::Internal::AsPxQuat(quat);
- ExpectEq(zero, pxZero);
- ExpectEq(one, pxOne);
- ExpectEq(rotX, pxRotX);
- ExpectEq(rotY, pxRotY);
- ExpectEq(rotZ, pxRotZ);
- ExpectEq(quat, pxQuat);
- }
- TEST(NvClothSystem, Cloth_FastCopy_nvRangeElmenentsAreTheSameAsAZStdVector)
- {
- const AZStd::vector<AZ::Vector4> azEmpty;
- const AZStd::vector<AZ::Vector4> azValues = {{
- AZ::Vector4(15.0f, -692.0f, 65.0f, -15.0f),
- AZ::Vector4(1851.594f, 1.0f, -125.0f, 168.0f),
- AZ::Vector4(2384.05f, -692.0f, 41865.153f, 1567.0f),
- AZ::Vector4(35.02f, 2572.453f, 2465.0f, 987.0f),
- AZ::Vector4(-14.161f, 47.0f, 65.0f, -6358.52f)
- }};
- nv::cloth::Vector<physx::PxVec4>::Type nvEmpty;
- nv::cloth::Vector<physx::PxVec4>::Type nvValues(static_cast<uint32_t>(azValues.size()));
- nv::cloth::Range<physx::PxVec4> nvEmptyRange(nvEmpty.begin(), nvEmpty.end());
- nv::cloth::Range<physx::PxVec4> nvValuesRange(nvValues.begin(), nvValues.end());
- NvCloth::Internal::FastCopy(azEmpty, nvEmptyRange);
- NvCloth::Internal::FastCopy(azValues, nvValuesRange);
- ExpectEq(azEmpty, nvEmptyRange);
- ExpectEq(azValues, nvValuesRange);
- }
- TEST(NvClothSystem, Cloth_FastCopy_AZStdVectorElmenentsAreTheSameAsNvRange)
- {
- nv::cloth::Vector<physx::PxVec4>::Type nvEmpty;
- nv::cloth::Vector<physx::PxVec4>::Type nvValues;
- nvValues.pushBack(physx::PxVec4(15.0f, -692.0f, 65.0f, -15.0f));
- nvValues.pushBack(physx::PxVec4(1851.594f, 1.0f, -125.0f, 168.0f));
- nvValues.pushBack(physx::PxVec4(2384.05f, -692.0f, 41865.153f, 1567.0f));
- nvValues.pushBack(physx::PxVec4(35.02f, 2572.453f, 2465.0f, 987.0f));
- nvValues.pushBack(physx::PxVec4(-14.161f, 47.0f, 65.0f, -6358.52f));
- const nv::cloth::Range<physx::PxVec4> nvEmptyRange(nvEmpty.begin(), nvEmpty.end());
- const nv::cloth::Range<physx::PxVec4> nvValuesRange(nvValues.begin(), nvValues.end());
- AZStd::vector<AZ::Vector4> azEmpty;
- AZStd::vector<AZ::Vector4> azValues(nvValuesRange.size());
- NvCloth::Internal::FastCopy(nvEmptyRange, azEmpty);
- NvCloth::Internal::FastCopy(nvValuesRange, azValues);
- ExpectEq(azEmpty, nvEmptyRange);
- ExpectEq(azValues, nvValuesRange);
- }
- TEST(NvClothSystem, Cloth_FastMove_nvRangeElmenentsAreTheSameAsAZStdVector)
- {
- const AZStd::vector<AZ::Vector4> azEmpty;
- const AZStd::vector<AZ::Vector4> azValues = {{
- AZ::Vector4(15.0f, -692.0f, 65.0f, -15.0f),
- AZ::Vector4(1851.594f, 1.0f, -125.0f, 168.0f),
- AZ::Vector4(2384.05f, -692.0f, 41865.153f, 1567.0f),
- AZ::Vector4(35.02f, 2572.453f, 2465.0f, 987.0f),
- AZ::Vector4(-14.161f, 47.0f, 65.0f, -6358.52f)
- }};
- nv::cloth::Vector<physx::PxVec4>::Type nvEmpty;
- nv::cloth::Vector<physx::PxVec4>::Type nvValues(static_cast<uint32_t>(azValues.size()));
- nv::cloth::Range<physx::PxVec4> nvEmptyRange(nvEmpty.begin(), nvEmpty.end());
- nv::cloth::Range<physx::PxVec4> nvValuesRange(nvValues.begin(), nvValues.end());
- {
- AZStd::vector<AZ::Vector4> azEmptyCopy = azEmpty;
- AZStd::vector<AZ::Vector4> azValuesCopy = azValues;
- NvCloth::Internal::FastMove(AZStd::move(azEmptyCopy), nvEmptyRange);
- NvCloth::Internal::FastMove(AZStd::move(azValuesCopy), nvValuesRange);
- }
- ExpectEq(azEmpty, nvEmptyRange);
- ExpectEq(azValues, nvValuesRange);
- }
- TEST(NvClothSystem, Cloth_FastMove_AZStdVectorElmenentsAreTheSameAsNvRange)
- {
- nv::cloth::Vector<physx::PxVec4>::Type nvEmpty;
- nv::cloth::Vector<physx::PxVec4>::Type nvValues;
- nvValues.pushBack(physx::PxVec4(15.0f, -692.0f, 65.0f, -15.0f));
- nvValues.pushBack(physx::PxVec4(1851.594f, 1.0f, -125.0f, 168.0f));
- nvValues.pushBack(physx::PxVec4(2384.05f, -692.0f, 41865.153f, 1567.0f));
- nvValues.pushBack(physx::PxVec4(35.02f, 2572.453f, 2465.0f, 987.0f));
- nvValues.pushBack(physx::PxVec4(-14.161f, 47.0f, 65.0f, -6358.52f));
- const nv::cloth::Range<physx::PxVec4> nvEmptyRange(nvEmpty.begin(), nvEmpty.end());
- const nv::cloth::Range<physx::PxVec4> nvValuesRange(nvValues.begin(), nvValues.end());
- AZStd::vector<AZ::Vector4> azEmpty;
- AZStd::vector<AZ::Vector4> azValues(nvValuesRange.size());
- {
- nv::cloth::Vector<physx::PxVec4>::Type nvEmptyCopy = nvEmpty;
- nv::cloth::Vector<physx::PxVec4>::Type nvValuesCopy = nvValues;
- nv::cloth::Range<physx::PxVec4> nvEmptyRangeCopy(nvEmptyCopy.begin(), nvEmptyCopy.end());
- nv::cloth::Range<physx::PxVec4> nvValuesRangeCopy(nvValuesCopy.begin(), nvValuesCopy.end());
- NvCloth::Internal::FastMove(AZStd::move(nvEmptyRangeCopy), azEmpty);
- NvCloth::Internal::FastMove(AZStd::move(nvValuesRangeCopy), azValues);
- }
- ExpectEq(azEmpty, nvEmptyRange);
- ExpectEq(azValues, nvValuesRange);
- }
- //! Sets up a cloth for each test case with access to its native cloth instance.
- //! Creating cloth using direct calls to the library, instead of using Factory, to
- //! be able to keep a pointer the native cloth instance.
- class NvClothSystemCloth
- : public ::testing::Test
- {
- protected:
- // ::testing::Test overrides ...
- void SetUp() override;
- void TearDown() override;
- AZStd::unique_ptr<NvCloth::Cloth> m_cloth;
- nv::cloth::Cloth* m_nvCloth = nullptr; // Pointer to native cloth instance of m_cloth
- private:
- void CreateFabric();
- void CreateCloth();
- NvCloth::NvFactoryUniquePtr m_nvFactory;
- AZStd::unique_ptr<NvCloth::Fabric> m_fabric;
- };
- void NvClothSystemCloth::SetUp()
- {
- m_nvFactory = NvCloth::NvFactoryUniquePtr(NvClothCreateFactoryCPU());
- CreateFabric();
- CreateCloth();
- }
- void NvClothSystemCloth::TearDown()
- {
- m_nvCloth = nullptr;
- m_cloth.reset();
- m_fabric.reset();
- m_nvFactory.reset();
- }
- void NvClothSystemCloth::CreateFabric()
- {
- const NvCloth::FabricCookedData fabricCookedData = CreateTestFabricCookedData();
- NvCloth::NvFabricUniquePtr nvFabric(
- m_nvFactory->createFabric(
- fabricCookedData.m_internalData.m_numParticles,
- NvCloth::ToNvRange(fabricCookedData.m_internalData.m_phaseIndices),
- NvCloth::ToNvRange(fabricCookedData.m_internalData.m_sets),
- NvCloth::ToNvRange(fabricCookedData.m_internalData.m_restValues),
- NvCloth::ToNvRange(fabricCookedData.m_internalData.m_stiffnessValues),
- NvCloth::ToNvRange(fabricCookedData.m_internalData.m_indices),
- NvCloth::ToNvRange(fabricCookedData.m_internalData.m_anchors),
- NvCloth::ToNvRange(fabricCookedData.m_internalData.m_tetherLengths),
- NvCloth::ToNvRange(fabricCookedData.m_internalData.m_triangles)));
- EXPECT_TRUE(nvFabric.get() != nullptr);
- m_fabric = AZStd::make_unique<NvCloth::Fabric>(
- fabricCookedData,
- AZStd::move(nvFabric));
- }
- void NvClothSystemCloth::CreateCloth()
- {
- NvCloth::NvClothUniquePtr nvCloth(
- m_nvFactory->createCloth(
- NvCloth::ToPxVec4NvRange(m_fabric->m_cookedData.m_particles),
- *m_fabric->m_nvFabric.get()));
- EXPECT_TRUE(nvCloth.get() != nullptr);
- m_nvCloth = nvCloth.get();
- m_cloth = AZStd::make_unique<NvCloth::Cloth>(
- NvCloth::ClothId(1),
- m_fabric->m_cookedData.m_particles,
- m_fabric.get(),
- AZStd::move(nvCloth));
- }
- TEST_F(NvClothSystemCloth, Cloth_SetParticles_ParticlesAreSetToClothAndNativeCloth)
- {
- auto newParticles = m_cloth->GetParticles();
- for (auto& particle : newParticles)
- {
- particle *= 2.0f;
- }
- m_cloth->SetParticles(newParticles);
- EXPECT_THAT(newParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), m_cloth->GetParticles()));
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothCurrentParticles = nv::cloth::readCurrentParticles(*m_nvCloth);
- ExpectEq(newParticles, nvClothCurrentParticles);
- // The inverse masses (W element) should have been copied into the previous particles inside NvCloth
- // to take effect for the next simulation update.
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothPreviousParticles = nv::cloth::readPreviousParticles(*m_nvCloth);
- for (size_t i = 0; i < newParticles.size(); ++i)
- {
- EXPECT_NEAR(newParticles[i].GetW(), nvClothPreviousParticles[static_cast<uint32_t>(i)].w, Tolerance);
- }
- }
- TEST_F(NvClothSystemCloth, Cloth_SetParticlesMove_ParticlesAreSetToClothAndNativeCloth)
- {
- auto newParticles = m_cloth->GetParticles();
- for (auto& particle : newParticles)
- {
- particle *= 2.0f;
- }
- {
- auto newParticlesCopy = newParticles;
- m_cloth->SetParticles(AZStd::move(newParticlesCopy));
- }
- EXPECT_THAT(newParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), m_cloth->GetParticles()));
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothCurrentParticles = nv::cloth::readCurrentParticles(*m_nvCloth);
- ExpectEq(newParticles, nvClothCurrentParticles);
- // The inverse masses (W element) should have been copied into the previous particles inside NvCloth
- // to take effect for the next simulation update.
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothPreviousParticles = nv::cloth::readPreviousParticles(*m_nvCloth);
- for (size_t i = 0; i < newParticles.size(); ++i)
- {
- EXPECT_NEAR(newParticles[i].GetW(), nvClothPreviousParticles[static_cast<uint32_t>(i)].w, Tolerance);
- }
- }
- TEST_F(NvClothSystemCloth, Cloth_DiscardParticleDelta_NativeClothPreviousAndCurrentParticlesAreTheSame)
- {
- m_cloth->DiscardParticleDelta();
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothCurrentParticles = nv::cloth::readCurrentParticles(*m_nvCloth);
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothPreviousParticles = nv::cloth::readPreviousParticles(*m_nvCloth);
- EXPECT_EQ(nvClothCurrentParticles.size(), nvClothPreviousParticles.size());
- for (size_t i = 0; i < nvClothCurrentParticles.size(); ++i)
- {
- ExpectEq(nvClothCurrentParticles[static_cast<uint32_t>(i)], nvClothPreviousParticles[static_cast<uint32_t>(i)]);
- }
- }
- TEST_F(NvClothSystemCloth, Cloth_Update_SimParticlesAreUpdated)
- {
- const AZ::Vector3 movement(6.0f, 1.0f, 3.0f);
- const auto previousParticles = m_cloth->GetParticles();
- // Fake all particles have been moved during simulation.
- {
- nv::cloth::MappedRange<physx::PxVec4> nvParticles = m_nvCloth->getCurrentParticles();
- for (auto& particle : nvParticles)
- {
- if (particle.w != 0.0f)
- {
- particle.x += movement.GetX();
- particle.y += movement.GetY();
- particle.z += movement.GetZ();
- }
- }
- // nvcloth particles are set once nvParticles gets out of scope
- }
- m_cloth->Update();
- const auto& particles = m_cloth->GetParticles();
- for (size_t i = 0; i < particles.size(); ++i)
- {
- if (particles[i].GetW() == 0.0f)
- {
- EXPECT_THAT(particles[i].GetAsVector3(), IsCloseTolerance(previousParticles[i].GetAsVector3(), Tolerance));
- }
- else
- {
- EXPECT_THAT(particles[i].GetAsVector3(), IsCloseTolerance(previousParticles[i].GetAsVector3() + movement, Tolerance));
- }
- }
- }
- TEST_F(NvClothSystemCloth, Cloth_UpdateInvalidParticles_SimParticlesAreNotUpdated)
- {
- const auto previousParticles = m_cloth->GetParticles();
- // Fake a particle has been set to non-finite values during simulation
- {
- nv::cloth::MappedRange<physx::PxVec4> nvParticles = m_nvCloth->getCurrentParticles();
- for (auto& particle : nvParticles)
- {
- if (particle.w != 0.0f)
- {
- particle.x = std::numeric_limits<float>::quiet_NaN();
- particle.y = std::numeric_limits<float>::infinity();
- break;
- }
- }
- // nvcloth particles are set once nvParticles gets out of scope
- }
- m_cloth->Update();
- const auto& particles = m_cloth->GetParticles();
- EXPECT_THAT(particles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), previousParticles));
- }
- TEST_F(NvClothSystemCloth, Cloth_UpdateInvalidParticles_NativeClothParticlesAreRestored)
- {
- // Fake a particle has been set to non-finite values during simulation
- {
- nv::cloth::MappedRange<physx::PxVec4> nvParticles = m_nvCloth->getCurrentParticles();
- for (auto& particle : nvParticles)
- {
- if (particle.w != 0.0f)
- {
- particle.x = std::numeric_limits<float>::quiet_NaN();
- particle.y = std::numeric_limits<float>::infinity();
- break;
- }
- }
- // nvcloth particles are set once nvParticles gets out of scope
- }
- m_cloth->Update();
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothCurrentParticles = nv::cloth::readCurrentParticles(*m_nvCloth);
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothPreviousParticles = nv::cloth::readPreviousParticles(*m_nvCloth);
- EXPECT_EQ(nvClothCurrentParticles.size(), nvClothPreviousParticles.size());
- for (size_t i = 0; i < nvClothCurrentParticles.size(); ++i)
- {
- ExpectEq(nvClothCurrentParticles[static_cast<uint32_t>(i)], nvClothPreviousParticles[static_cast<uint32_t>(i)]);
- }
- }
- TEST_F(NvClothSystemCloth, Cloth_UpdateInvalidParticlesManyAttempts_NativeClothParticlesAreRestoredToInitialPositions)
- {
- const auto& initialParticles = m_cloth->GetInitialParticles();
- const size_t numInvalidSimulations = 30;
- for (size_t i = 0; i < numInvalidSimulations; ++i)
- {
- // Fake a particle has been set to non-finite values during simulation
- {
- nv::cloth::MappedRange<physx::PxVec4> nvParticles = m_nvCloth->getCurrentParticles();
- for (auto& particle : nvParticles)
- {
- if (particle.w != 0.0f)
- {
- particle.x = std::numeric_limits<float>::quiet_NaN();
- particle.y = std::numeric_limits<float>::infinity();
- break;
- }
- }
- // nvcloth particles are set once nvParticles gets out of scope
- }
- m_cloth->Update();
- }
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothCurrentParticles = nv::cloth::readCurrentParticles(*m_nvCloth);
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothPreviousParticles = nv::cloth::readPreviousParticles(*m_nvCloth);
- EXPECT_EQ(initialParticles.size(), nvClothCurrentParticles.size());
- EXPECT_EQ(initialParticles.size(), nvClothPreviousParticles.size());
- for (size_t i = 0; i < initialParticles.size(); ++i)
- {
- ExpectEq(initialParticles[i], nvClothCurrentParticles[static_cast<uint32_t>(i)]);
- ExpectEq(initialParticles[i], nvClothPreviousParticles[static_cast<uint32_t>(i)]);
- }
- }
- TEST_F(NvClothSystemCloth, Cloth_CollisionAffectsStaticParticles_StaticParticlesAreModifiedDuringUpdate)
- {
- const AZ::Vector3 movement(6.0f, 1.0f, 3.0f);
- const auto previousParticles = m_cloth->GetParticles();
- m_cloth->GetClothConfigurator()->SetCollisionAffectsStaticParticles(true);
- // Fake all particles have been moved during simulation, cloth contains static particles.
- {
- nv::cloth::MappedRange<physx::PxVec4> nvParticles = m_nvCloth->getCurrentParticles();
- for (auto& particle : nvParticles)
- {
- particle.x += movement.GetX();
- particle.y += movement.GetY();
- particle.z += movement.GetZ();
- }
- // nvcloth particles are set once nvParticles gets out of scope
- }
- m_cloth->Update();
- const auto& particles = m_cloth->GetParticles();
- for (size_t i = 0; i < particles.size(); ++i)
- {
- EXPECT_THAT(particles[i].GetAsVector3(), IsCloseTolerance(previousParticles[i].GetAsVector3() + movement, Tolerance));
- }
- }
- TEST_F(NvClothSystemCloth, Cloth_CollisionDoesNotAffectStaticParticles_StaticParticlesAreNotModifiedDuringUpdate)
- {
- const AZ::Vector3 movement(6.0f, 1.0f, 3.0f);
- const auto previousParticles = m_cloth->GetParticles();
- m_cloth->GetClothConfigurator()->SetCollisionAffectsStaticParticles(false);
- // Fake all particles have been moved during simulation, cloth contains static particles.
- {
- nv::cloth::MappedRange<physx::PxVec4> nvParticles = m_nvCloth->getCurrentParticles();
- for (auto& particle : nvParticles)
- {
- particle.x += movement.GetX();
- particle.y += movement.GetY();
- particle.z += movement.GetZ();
- }
- // nvcloth particles are set once nvParticles gets out of scope
- }
- m_cloth->Update();
- const auto& particles = m_cloth->GetParticles();
- for (size_t i = 0; i < particles.size(); ++i)
- {
- if (particles[i].GetW() == 0.0f)
- {
- EXPECT_THAT(particles[i].GetAsVector3(), IsCloseTolerance(previousParticles[i].GetAsVector3(), Tolerance));
- }
- else
- {
- EXPECT_THAT(particles[i].GetAsVector3(), IsCloseTolerance(previousParticles[i].GetAsVector3() + movement, Tolerance));
- }
- }
- }
- TEST_F(NvClothSystemCloth, Cloth_ClothConfigurationSetTransform_TranslationAndRotationAreAppliedToNativeCloth)
- {
- const AZ::Transform identity = AZ::Transform::CreateIdentity();
- const AZ::Transform rotationX = AZ::Transform::CreateRotationX(AZ::DegToRad(35.0f));
- const AZ::Transform rotationYAndTranslation = AZ::Transform::CreateFromQuaternionAndTranslation(
- AZ::Quaternion::CreateRotationY(AZ::DegToRad(-135.0f)),
- AZ::Vector3(36.0f, 50.0f, -69.35f));
- m_cloth->GetClothConfigurator()->SetTransform(identity);
- ExpectEq(identity.GetTranslation(), m_nvCloth->getTranslation());
- ExpectEq(identity.GetRotation(), m_nvCloth->getRotation());
- m_cloth->GetClothConfigurator()->SetTransform(rotationX);
- ExpectEq(rotationX.GetTranslation(), m_nvCloth->getTranslation());
- ExpectEq(rotationX.GetRotation(), m_nvCloth->getRotation());
- m_cloth->GetClothConfigurator()->SetTransform(rotationYAndTranslation);
- ExpectEq(rotationYAndTranslation.GetTranslation(), m_nvCloth->getTranslation());
- ExpectEq(rotationYAndTranslation.GetRotation(), m_nvCloth->getRotation());
- }
- TEST_F(NvClothSystemCloth, Cloth_ClothConfigurationSetMass_MassIsAppliedToClothSimParticlesAndNativeClothPreviousParticles)
- {
- const float globalMass = 2.0f;
- const auto& initialParticles = m_cloth->GetInitialParticles();
- m_cloth->GetClothConfigurator()->SetMass(globalMass);
- const auto& particles = m_cloth->GetParticles();
- for (size_t i = 0; i < initialParticles.size(); ++i)
- {
- EXPECT_NEAR(particles[i].GetW(), initialParticles[i].GetW() / globalMass, Tolerance);
- }
- // The inverse masses (W element) should have been copied into the previous particles inside NvCloth
- // to take effect for the next simulation update.
- const nv::cloth::MappedRange<const physx::PxVec4> nvClothPreviousParticles = nv::cloth::readPreviousParticles(*m_nvCloth);
- for (size_t i = 0; i < initialParticles.size(); ++i)
- {
- EXPECT_NEAR(nvClothPreviousParticles[static_cast<uint32_t>(i)].w, initialParticles[i].GetW() / globalMass, Tolerance);
- }
- }
- } // namespace UnitTest
|