123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651 |
- /*
- * 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 <AzCore/Interface/Interface.h>
- #include <AzCore/UnitTest/UnitTest.h>
- #include <UnitTestHelper.h>
- #include <TriangleInputHelper.h>
- #include <NvCloth/IFabricCooker.h>
- #include <System/SystemComponent.h>
- namespace NvCloth
- {
- namespace Internal
- {
- FabricId ComputeFabricId(
- const AZStd::vector<SimParticleFormat>& particles,
- const AZStd::vector<SimIndexType>& indices,
- const AZ::Vector3& fabricGravity,
- bool useGeodesicTether);
- void CopyCookedData(FabricCookedData::InternalCookedData& azCookedData, const nv::cloth::CookedData& nvCookedData);
- AZStd::optional<FabricCookedData> Cook(
- const AZStd::vector<SimParticleFormat>& particles,
- const AZStd::vector<SimIndexType>& indices,
- const AZ::Vector3& fabricGravity,
- bool useGeodesicTether);
- void WeldVertices(
- const AZStd::vector<SimParticleFormat>& particles,
- const AZStd::vector<SimIndexType>& indices,
- AZStd::vector<SimParticleFormat>& weldedParticles,
- AZStd::vector<SimIndexType>& weldedIndices,
- AZStd::vector<int>& remappedVertices,
- float weldingDistance = AZ::Constants::FloatEpsilon);
- void RemoveStaticTriangles(
- const AZStd::vector<SimParticleFormat>& particles,
- const AZStd::vector<SimIndexType>& indices,
- AZStd::vector<SimParticleFormat>& simplifiedParticles,
- AZStd::vector<SimIndexType>& simplifiedIndices,
- AZStd::vector<int>& remappedVertices);
- } // namespace Internal
- } // namespace NvCloth
- namespace UnitTest
- {
- TEST(NvClothSystem, FactoryCooker_ComputeFabricIdWithNoData_IsValid)
- {
- NvCloth::FabricId fabricId = NvCloth::Internal::ComputeFabricId({}, {}, {}, false);
- EXPECT_TRUE(fabricId.IsValid());
- }
- TEST(NvClothSystem, FactoryCooker_ComputeFabricIdWithData_IsValid)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> particles = {{
- NvCloth::SimParticleFormat(1.0f,0.0f,0.0f,1.0f),
- NvCloth::SimParticleFormat(0.0f,1.0f,0.0f,1.0f),
- NvCloth::SimParticleFormat(0.0f,0.0f,1.0f,1.0f),
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{
- 0, 1, 2
- }};
- const AZ::Vector3 gravity(0.0f, 0.0f, -9.8f);
- const bool useGeodesicTether = true;
- NvCloth::FabricId fabricId = NvCloth::Internal::ComputeFabricId(particles, indices, gravity, useGeodesicTether);
- EXPECT_TRUE(fabricId.IsValid());
- }
- TEST(NvClothSystem, FactoryCooker_ComputeFabricIdsWithDifferentGravityParameter_ResultInDifferentIDs)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> particles = {{
- NvCloth::SimParticleFormat(1.0f,0.0f,0.0f,1.0f),
- NvCloth::SimParticleFormat(0.0f,1.0f,0.0f,1.0f),
- NvCloth::SimParticleFormat(0.0f,0.0f,1.0f,1.0f),
- } };
- const AZStd::vector<NvCloth::SimIndexType> indices = {{
- 0, 1, 2
- }};
- const AZ::Vector3 gravity(0.0f, 0.0f, -9.8f);
- const bool useGeodesicTether = true;
- NvCloth::FabricId fabricId1 = NvCloth::Internal::ComputeFabricId(particles, indices, gravity, useGeodesicTether);
- NvCloth::FabricId fabricId2 = NvCloth::Internal::ComputeFabricId(particles, indices, 0.5f * gravity, useGeodesicTether);
- EXPECT_TRUE(fabricId1.IsValid());
- EXPECT_TRUE(fabricId2.IsValid());
- EXPECT_NE(fabricId1, fabricId2);
- }
- TEST(NvClothSystem, FactoryCooker_ComputeFabricIdsWithDifferentUseGeodesicTetherParameter_ResultInDifferentIDs)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> particles = {{
- NvCloth::SimParticleFormat(1.0f,0.0f,0.0f,1.0f),
- NvCloth::SimParticleFormat(0.0f,1.0f,0.0f,1.0f),
- NvCloth::SimParticleFormat(0.0f,0.0f,1.0f,1.0f),
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{
- 0, 1, 2
- }};
- const AZ::Vector3 gravity(0.0f, 0.0f, -9.8f);
- const bool useGeodesicTether = true;
- NvCloth::FabricId fabricId1 = NvCloth::Internal::ComputeFabricId(particles, indices, gravity, useGeodesicTether);
- NvCloth::FabricId fabricId2 = NvCloth::Internal::ComputeFabricId(particles, indices, gravity, !useGeodesicTether);
- EXPECT_TRUE(fabricId1.IsValid());
- EXPECT_TRUE(fabricId2.IsValid());
- EXPECT_NE(fabricId1, fabricId2);
- }
- TEST(NvClothSystem, FactoryCooker_CopyInternalCookedDataEmpty_CopiedDataIsEmpty)
- {
- nv::cloth::CookedData nvCookedData;
- nvCookedData.mNumParticles = 0;
- NvCloth::FabricCookedData::InternalCookedData azCookedData;
- NvCloth::Internal::CopyCookedData(azCookedData, nvCookedData);
- EXPECT_EQ(azCookedData.m_numParticles, 0);
- EXPECT_TRUE(azCookedData.m_phaseIndices.empty());
- EXPECT_TRUE(azCookedData.m_phaseTypes.empty());
- EXPECT_TRUE(azCookedData.m_sets.empty());
- EXPECT_TRUE(azCookedData.m_restValues.empty());
- EXPECT_TRUE(azCookedData.m_stiffnessValues.empty());
- EXPECT_TRUE(azCookedData.m_indices.empty());
- EXPECT_TRUE(azCookedData.m_anchors.empty());
- EXPECT_TRUE(azCookedData.m_tetherLengths.empty());
- EXPECT_TRUE(azCookedData.m_triangles.empty());
- ExpectEq(azCookedData, nvCookedData);
- }
- TEST(NvClothSystem, FactoryCooker_CopyInternalCookedData_CopiedDataMatchesSource)
- {
- nv::cloth::CookedData nvCookedData;
- nvCookedData.mNumParticles = 0;
- NvCloth::FabricCookedData::InternalCookedData azCookedData;
- NvCloth::Internal::CopyCookedData(azCookedData, nvCookedData);
- ExpectEq(azCookedData, nvCookedData);
- }
- TEST(NvClothSystem, FactoryCooker_CookEmptyMesh_ReturnsNoData)
- {
- AZ_TEST_START_TRACE_SUPPRESSION;
- EXPECT_TRUE(NvCloth::SystemComponent::CheckLastClothError());
- AZStd::optional<NvCloth::FabricCookedData> fabricCookedData = NvCloth::Internal::Cook({}, {}, {}, false);
- NvCloth::SystemComponent::ResetLastClothError(); // Reset the nvcloth error left in SystemComponent
- AZ_TEST_STOP_TRACE_SUPPRESSION(1); // Expect 1 error
- EXPECT_FALSE(fabricCookedData.has_value());
- }
- TEST(NvClothSystem, FactoryCooker_CookWithIncorrectIndices_ReturnsNoData)
- {
- const AZStd::vector<NvCloth::SimIndexType> incorrectIndices = {{ 0, 1 }}; // Use incorrect number of indices for a triangle (multiple of 3)
- AZ_TEST_START_TRACE_SUPPRESSION;
- EXPECT_TRUE(NvCloth::SystemComponent::CheckLastClothError());
- AZStd::optional<NvCloth::FabricCookedData> fabricCookedData = NvCloth::Internal::Cook({}, incorrectIndices, {}, false);
- NvCloth::SystemComponent::ResetLastClothError(); // Reset the nvcloth error left in SystemComponent
- AZ_TEST_STOP_TRACE_SUPPRESSION(1); // Expect 1 error
- EXPECT_FALSE(fabricCookedData.has_value());
- }
- TEST(NvClothSystem, FactoryCooker_CookTriangle_CooksDataCorrectly)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat(-1.0f, 0.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f, 0.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(0.0f, 1.0f, 0.0f, 1.0f),
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = { {0, 1, 2} };
- const AZ::Vector3 gravity(0.0f, 0.0f, -9.8f);
- const bool useGeodesicTether = true;
- AZStd::optional<NvCloth::FabricCookedData> fabricCookedData =
- NvCloth::Internal::Cook(vertices, indices, gravity, useGeodesicTether);
- EXPECT_TRUE(fabricCookedData.has_value());
- EXPECT_TRUE(fabricCookedData->m_id.IsValid());
- EXPECT_THAT(fabricCookedData->m_particles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), vertices));
- EXPECT_EQ(fabricCookedData->m_indices, indices);
- EXPECT_THAT(fabricCookedData->m_gravity, IsCloseTolerance(gravity, Tolerance));
- EXPECT_EQ(fabricCookedData->m_useGeodesicTether, useGeodesicTether);
- EXPECT_EQ(fabricCookedData->m_internalData.m_numParticles, vertices.size());
- }
- TEST(NvClothSystem, FactoryCooker_CookTriangleAllStatic_CooksDataCorrectly)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat(-1.0f, 0.0f, 0.0f, 0.0f),
- NvCloth::SimParticleFormat(1.0f, 0.0f, 0.0f, 0.0f),
- NvCloth::SimParticleFormat(0.0f, 1.0f, 0.0f, 0.0f),
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 0, 1, 2 }};
- const AZ::Vector3 gravity(0.0f, 0.0f, -9.8f);
- const bool useGeodesicTether = true;
- AZStd::optional<NvCloth::FabricCookedData> fabricCookedData =
- NvCloth::Internal::Cook(vertices, indices, gravity, useGeodesicTether);
- EXPECT_TRUE(fabricCookedData.has_value());
- EXPECT_TRUE(fabricCookedData->m_id.IsValid());
- EXPECT_THAT(fabricCookedData->m_particles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), vertices));
- EXPECT_EQ(fabricCookedData->m_indices, indices);
- EXPECT_THAT(fabricCookedData->m_gravity, IsCloseTolerance(gravity, Tolerance));
- EXPECT_EQ(fabricCookedData->m_useGeodesicTether, useGeodesicTether);
- EXPECT_EQ(fabricCookedData->m_internalData.m_numParticles, vertices.size());
- }
- TEST(NvClothSystem, FactoryCooker_CookMesh_CooksDataCorrectly)
- {
- const float width = 1.0f;
- const float height = 1.0f;
- const AZ::u32 segmentsX = 10;
- const AZ::u32 segmentsY = 10;
- const AZ::Vector3 gravity(0.0f, 0.0f, -9.8f);
- const bool useGeodesicTether = true;
- const TriangleInput planeXY = CreatePlane(width, height, segmentsX, segmentsY);
- AZStd::optional<NvCloth::FabricCookedData> fabricCookedData =
- NvCloth::Internal::Cook(planeXY.m_vertices, planeXY.m_indices, gravity, useGeodesicTether);
- EXPECT_TRUE(fabricCookedData.has_value());
- EXPECT_TRUE(fabricCookedData->m_id.IsValid());
- EXPECT_THAT(fabricCookedData->m_particles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), planeXY.m_vertices));
- EXPECT_EQ(fabricCookedData->m_indices, planeXY.m_indices);
- EXPECT_THAT(fabricCookedData->m_gravity, IsCloseTolerance(gravity, Tolerance));
- EXPECT_EQ(fabricCookedData->m_useGeodesicTether, useGeodesicTether);
- EXPECT_EQ(fabricCookedData->m_internalData.m_numParticles, planeXY.m_vertices.size());
- }
- TEST(NvClothSystem, FactoryCooker_WeldVerticesEmptyMesh_ReturnsEmptyData)
- {
- AZStd::vector<NvCloth::SimParticleFormat> weldedVertices;
- AZStd::vector<NvCloth::SimIndexType> weldedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::WeldVertices({}, {}, weldedVertices, weldedIndices, remappedVertices);
- EXPECT_TRUE(weldedVertices.empty());
- EXPECT_TRUE(weldedIndices.empty());
- EXPECT_TRUE(remappedVertices.empty());
- }
- TEST(NvClothSystem, FactoryCooker_WeldVerticesTriangle_KeepsLowestInverseMass)
- {
- const AZ::Vector3 vertexPosition(100.2f, 300.2f, -30.62f);
- const size_t expectedSizeAfterWelding = 1;
- const float lowestInverseMass = 0.2f;
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat::CreateFromVector3AndFloat(vertexPosition, 1.0f),
- NvCloth::SimParticleFormat::CreateFromVector3AndFloat(vertexPosition, lowestInverseMass), // This vertex has the lowest inverse mass
- NvCloth::SimParticleFormat::CreateFromVector3AndFloat(vertexPosition, 0.5f)
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 0, 1, 2 }};
- AZStd::vector<NvCloth::SimParticleFormat> weldedVertices;
- AZStd::vector<NvCloth::SimIndexType> weldedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::WeldVertices(vertices, indices, weldedVertices, weldedIndices, remappedVertices);
- ASSERT_EQ(weldedVertices.size(), expectedSizeAfterWelding);
- EXPECT_THAT(weldedVertices[0].GetAsVector3(), IsCloseTolerance(vertexPosition, Tolerance));
- EXPECT_NEAR(weldedVertices[0].GetW(), lowestInverseMass, Tolerance);
- }
- TEST(NvClothSystem, FactoryCooker_WeldVerticesSquareWithDuplicatedVertices_DuplicatedVerticesAreRemoved)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat(-1.0f, 1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat( 1.0f, 1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat( 1.0f, 1.0f, 0.0f, 1.0f), // Duplicated vertex
- NvCloth::SimParticleFormat( 1.0f,-1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 1.0f) // Duplicated vertex
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 0, 1, 2, 3, 4, 5 }};
- const size_t expectedSizeAfterWelding = vertices.size() - 2;
- AZStd::vector<NvCloth::SimParticleFormat> weldedVertices;
- AZStd::vector<NvCloth::SimIndexType> weldedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::WeldVertices(vertices, indices, weldedVertices, weldedIndices, remappedVertices);
- ASSERT_EQ(weldedVertices.size(), expectedSizeAfterWelding);
- ASSERT_EQ(weldedIndices.size(), indices.size());
- ASSERT_EQ(remappedVertices.size(), vertices.size());
- for (size_t i = 0; i < remappedVertices.size(); ++i)
- {
- EXPECT_GE(remappedVertices[i], 0);
- EXPECT_LT(remappedVertices[i], weldedVertices.size());
- EXPECT_THAT(weldedVertices[remappedVertices[i]], IsCloseTolerance(vertices[i], Tolerance));
- }
- for (size_t i = 0; i < weldedIndices.size(); ++i)
- {
- EXPECT_GE(weldedIndices[i], 0);
- EXPECT_LT(weldedIndices[i], weldedVertices.size());
- EXPECT_EQ(weldedIndices[i], remappedVertices[indices[i]]);
- EXPECT_THAT(weldedVertices[weldedIndices[i]], IsCloseTolerance(vertices[indices[i]], Tolerance));
- }
- }
- TEST(NvClothSystem, FactoryCooker_WeldVerticesTrianglesWithoutDuplicatedVertices_ResultIsTheSame)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat(-1.0f, 1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f, 1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f, 1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f,-1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 1.0f, 1.0f)
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 0, 1, 2, 3, 4, 5 }};
- AZStd::vector<NvCloth::SimParticleFormat> weldedVertices;
- AZStd::vector<NvCloth::SimIndexType> weldedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::WeldVertices(vertices, indices, weldedVertices, weldedIndices, remappedVertices);
- // The result after calling WeldVertices is expected to have the same size.
- // The vertices inside will be reordered though due to the welding process.
- ASSERT_EQ(weldedVertices.size(), vertices.size());
- ASSERT_EQ(weldedIndices.size(), indices.size());
- ASSERT_EQ(remappedVertices.size(), vertices.size());
- for (size_t i = 0; i < remappedVertices.size(); ++i)
- {
- EXPECT_GE(remappedVertices[i], 0);
- EXPECT_LT(remappedVertices[i], weldedVertices.size());
- EXPECT_THAT(weldedVertices[remappedVertices[i]], IsCloseTolerance(vertices[i], Tolerance));
- }
- for (size_t i = 0; i < weldedIndices.size(); ++i)
- {
- EXPECT_GE(weldedIndices[i], 0);
- EXPECT_LT(weldedIndices[i], weldedVertices.size());
- EXPECT_EQ(weldedIndices[i], remappedVertices[indices[i]]);
- EXPECT_THAT(weldedVertices[weldedIndices[i]], IsCloseTolerance(vertices[indices[i]], Tolerance));
- }
- }
- TEST(NvClothSystem, FactoryCooker_RemoveStaticTrianglesEmptyMesh_ReturnsEmptyData)
- {
- AZStd::vector<NvCloth::SimParticleFormat> simplifiedVertices;
- AZStd::vector<NvCloth::SimIndexType> simplifiedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::RemoveStaticTriangles({}, {}, simplifiedVertices, simplifiedIndices, remappedVertices);
- EXPECT_TRUE(simplifiedVertices.empty());
- EXPECT_TRUE(simplifiedIndices.empty());
- EXPECT_TRUE(remappedVertices.empty());
- }
- TEST(NvClothSystem, FactoryCooker_RemoveStaticTrianglesWithOneStaticTriangle_RemovesAllVerticesAndIndices)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat(-1.0f, 1.0f, 0.0f, 0.0f),
- NvCloth::SimParticleFormat(1.0f, 1.0f, 0.0f, 0.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 0.0f)
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 0, 1, 2 }};
- AZStd::vector<NvCloth::SimParticleFormat> simplifiedVertices;
- AZStd::vector<NvCloth::SimIndexType> simplifiedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::RemoveStaticTriangles(vertices, indices, simplifiedVertices, simplifiedIndices, remappedVertices);
- EXPECT_TRUE(simplifiedVertices.empty());
- EXPECT_TRUE(simplifiedIndices.empty());
- EXPECT_EQ(remappedVertices.size(), vertices.size());
- for (const auto& remappedVertex : remappedVertices)
- {
- EXPECT_LT(remappedVertex, 0); // Remapping must be negative, meaning vertex has been removed.
- }
- }
- TEST(NvClothSystem, FactoryCooker_RemoveStaticTrianglesWithStaticTriangles_StaticTriangleAndVerticesAreRemoved)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat(-1.0f, 1.0f, 0.0f, 0.0f), // This static vertex will be removed
- NvCloth::SimParticleFormat(1.0f, 1.0f, 0.0f, 0.0f), // This static vertex will be removed
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 0.0f), // This static vertex will be removed
- NvCloth::SimParticleFormat(1.0f, 1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f,-1.0f, 1.0f, 0.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 1.0f, 1.0f)
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 0, 1, 2, 3, 4, 5 }}; // First triangle from the triplet 0,1,2 uses all static vertices and will be removed
- const size_t expectedVerticesSizeAfterSimplification = vertices.size() - 3;
- const size_t expectedIndicesSizeAfterSimplification = indices.size() - 3; // 1 triangles less is 3 indices less.
- AZStd::vector<NvCloth::SimParticleFormat> simplifiedVertices;
- AZStd::vector<NvCloth::SimIndexType> simplifiedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::RemoveStaticTriangles(vertices, indices, simplifiedVertices, simplifiedIndices, remappedVertices);
- ASSERT_EQ(simplifiedVertices.size(), expectedVerticesSizeAfterSimplification);
- ASSERT_EQ(simplifiedIndices.size(), expectedIndicesSizeAfterSimplification);
- ASSERT_EQ(remappedVertices.size(), vertices.size());
- for (size_t i = 0; i < remappedVertices.size(); ++i)
- {
- // The first 3 vertices should have been removed, so the remapping should be negative
- if (i < 3)
- {
- EXPECT_LT(remappedVertices[i], 0);
- }
- else
- {
- EXPECT_GE(remappedVertices[i], 0);
- EXPECT_LT(remappedVertices[i], simplifiedVertices.size());
- EXPECT_THAT(simplifiedVertices[remappedVertices[i]], IsCloseTolerance(vertices[i], Tolerance));
- }
- }
- for (size_t i = 0; i < simplifiedIndices.size(); ++i)
- {
- EXPECT_GE(simplifiedIndices[i], 0);
- EXPECT_LT(simplifiedIndices[i], simplifiedVertices.size());
- }
- for (size_t i = 0; i < indices.size(); ++i)
- {
- int remappedVertex = remappedVertices[indices[i]];
- if (remappedVertex >= 0) // If the vertex has not been removed
- {
- EXPECT_THAT(simplifiedVertices[remappedVertex], IsCloseTolerance(vertices[indices[i]], Tolerance));
- }
- }
- }
- TEST(NvClothSystem, FactoryCooker_RemoveStaticTrianglesWithStaticTrianglesSharedVertices_StaticTriangleAndVerticesAreRemoved)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat(-1.0f, 1.0f, 0.0f, 0.0f), // This static vertex will be removed
- NvCloth::SimParticleFormat(1.0f, 1.0f, 0.0f, 0.0f), // This static vertex will remain because it's also used in the third triangle too
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 0.0f), // This static vertex will be removed
- NvCloth::SimParticleFormat(1.0f, 1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f,-1.0f, 1.0f, 0.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 1.0f, 1.0f)
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 3, 4, 5, 0, 1, 2, 3, 1, 5 }}; // Second triangle from the triplet 0,1,2 uses all static vertices and will be removed
- const size_t expectedVerticesSizeAfterSimplification = vertices.size() - 2;
- const size_t expectedIndicesSizeAfterSimplification = indices.size() - 3; // 1 triangles less is 3 indices less.
- AZStd::vector<NvCloth::SimParticleFormat> simplifiedVertices;
- AZStd::vector<NvCloth::SimIndexType> simplifiedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::RemoveStaticTriangles(vertices, indices, simplifiedVertices, simplifiedIndices, remappedVertices);
- ASSERT_EQ(simplifiedVertices.size(), expectedVerticesSizeAfterSimplification);
- ASSERT_EQ(simplifiedIndices.size(), expectedIndicesSizeAfterSimplification);
- ASSERT_EQ(remappedVertices.size(), vertices.size());
- for (size_t i = 0; i < remappedVertices.size(); ++i)
- {
- // The first and third vertex should have been removed, so the remapping should be negative.
- if (i == 0 || i == 2)
- {
- EXPECT_LT(remappedVertices[i], 0);
- }
- else
- {
- EXPECT_GE(remappedVertices[i], 0);
- EXPECT_LT(remappedVertices[i], simplifiedVertices.size());
- EXPECT_THAT(simplifiedVertices[remappedVertices[i]], IsCloseTolerance(vertices[i], Tolerance));
- }
- }
- for (size_t i = 0; i < simplifiedIndices.size(); ++i)
- {
- EXPECT_GE(simplifiedIndices[i], 0);
- EXPECT_LT(simplifiedIndices[i], simplifiedVertices.size());
- }
- for (size_t i = 0; i < indices.size(); ++i)
- {
- int remappedVertex = remappedVertices[indices[i]];
- if (remappedVertex >= 0) // If the vertex has not been removed
- {
- EXPECT_THAT(simplifiedVertices[remappedVertex], IsCloseTolerance(vertices[indices[i]], Tolerance));
- }
- }
- }
- TEST(NvClothSystem, FactoryCooker_RemoveStaticTrianglesWithNonStaticTriangles_ResultIsTheSame)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = {{
- NvCloth::SimParticleFormat(-1.0f, 1.0f, 0.0f, 0.0f),
- NvCloth::SimParticleFormat(1.0f, 1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f, 1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f,-1.0f, 1.0f, 0.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 1.0f, 1.0f)
- }};
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 0, 1, 2, 3, 4, 5 }};
- AZStd::vector<NvCloth::SimParticleFormat> simplifiedVertices;
- AZStd::vector<NvCloth::SimIndexType> simplifiedIndices;
- AZStd::vector<int> remappedVertices;
- NvCloth::Internal::RemoveStaticTriangles(vertices, indices, simplifiedVertices, simplifiedIndices, remappedVertices);
- // The result after calling RemoveStaticTriangles is expected to have the same size.
- // The vertices will be reordered though due to the processing during simplification.
- ASSERT_EQ(simplifiedVertices.size(), vertices.size());
- ASSERT_EQ(simplifiedIndices.size(), indices.size());
- ASSERT_EQ(remappedVertices.size(), vertices.size());
- for (size_t i = 0; i < remappedVertices.size(); ++i)
- {
- EXPECT_GE(remappedVertices[i], 0);
- EXPECT_LT(remappedVertices[i], simplifiedVertices.size());
- EXPECT_THAT(simplifiedVertices[remappedVertices[i]], IsCloseTolerance(vertices[i], Tolerance));
- }
- for (size_t i = 0; i < simplifiedIndices.size(); ++i)
- {
- EXPECT_GE(simplifiedIndices[i], 0);
- EXPECT_LT(simplifiedIndices[i], simplifiedVertices.size());
- EXPECT_EQ(simplifiedIndices[i], remappedVertices[indices[i]]);
- EXPECT_THAT(simplifiedVertices[simplifiedIndices[i]], IsCloseTolerance(vertices[indices[i]], Tolerance));
- }
- }
- TEST(NvClothSystem, FactoryCooker_SimplifiyMeshWithDuplicatedVerticesAndStaticTriangles_DuplicatedVerticesAndStaticTrianglesAreRemoved)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = { {
- NvCloth::SimParticleFormat(-1.0f, 1.0f, 0.0f, 0.0f), // This static vertex will be removed
- NvCloth::SimParticleFormat(1.0f, 1.0f, 0.0f, 0.0f), // This static vertex will remain because it's also used in the third triangle too
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 0.0f), // This static vertex will be removed
- NvCloth::SimParticleFormat(1.0f, 1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f,-1.0f, 1.0f, 0.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f, 1.0f, 1.0f, 1.0f), // Duplicated vertex
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 1.0f, 1.0f) // Duplicated vertex
- } };
- const AZStd::vector<NvCloth::SimIndexType> indices = {{ 3, 4, 5, 0, 1, 2, 6, 1, 7 }}; // Second triangle from the triplet 0,1,2 uses all static vertices and will be removed
- const size_t expectedVerticesSizeAfterSimplification = vertices.size() - 4;
- const size_t expectedIndicesSizeAfterSimplification = indices.size() - 3; // 1 triangles less is 3 indices less.
- const bool removeStaticTriangles = true;
- AZStd::vector<NvCloth::SimParticleFormat> simplifiedVertices;
- AZStd::vector<NvCloth::SimIndexType> simplifiedIndices;
- AZStd::vector<int> remappedVertices;
- AZ::Interface<NvCloth::IFabricCooker>::Get()->SimplifyMesh(vertices, indices, simplifiedVertices, simplifiedIndices, remappedVertices, removeStaticTriangles);
- ASSERT_EQ(simplifiedVertices.size(), expectedVerticesSizeAfterSimplification);
- ASSERT_EQ(simplifiedIndices.size(), expectedIndicesSizeAfterSimplification);
- ASSERT_EQ(remappedVertices.size(), vertices.size());
- for (size_t i = 0; i < remappedVertices.size(); ++i)
- {
- // The first and third vertex should have been removed, so the remapping should be negative.
- if (i == 0 || i == 2)
- {
- EXPECT_LT(remappedVertices[i], 0);
- }
- else
- {
- EXPECT_GE(remappedVertices[i], 0);
- EXPECT_LT(remappedVertices[i], simplifiedVertices.size());
- EXPECT_THAT(simplifiedVertices[remappedVertices[i]], IsCloseTolerance(vertices[i], Tolerance));
- }
- }
- for (size_t i = 0; i < simplifiedIndices.size(); ++i)
- {
- EXPECT_GE(simplifiedIndices[i], 0);
- EXPECT_LT(simplifiedIndices[i], simplifiedVertices.size());
- }
- for (size_t i = 0; i < indices.size(); ++i)
- {
- int remappedVertex = remappedVertices[indices[i]];
- if (remappedVertex >= 0) // If the vertex has not been removed
- {
- EXPECT_THAT(simplifiedVertices[remappedVertex], IsCloseTolerance(vertices[indices[i]], Tolerance));
- }
- }
- }
- TEST(NvClothSystem, FactoryCooker_SimplifiyMeshWithoutRemovingStaticTriangles_DuplicatedVerticesRemovedAndStaticTrianglesRemain)
- {
- const AZStd::vector<NvCloth::SimParticleFormat> vertices = { {
- NvCloth::SimParticleFormat(-1.0f, 1.0f, 0.0f, 0.0f), // This static vertex will remain because we won't remove static triangles
- NvCloth::SimParticleFormat(1.0f, 1.0f, 0.0f, 0.0f), // This static vertex will remain because it's also used in the third triangle too
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 0.0f, 0.0f), // This static vertex will remain because we won't remove static triangles
- NvCloth::SimParticleFormat(1.0f, 1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f,-1.0f, 1.0f, 0.0f),
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 1.0f, 1.0f),
- NvCloth::SimParticleFormat(1.0f, 1.0f, 1.0f, 1.0f), // Duplicated vertex
- NvCloth::SimParticleFormat(-1.0f,-1.0f, 1.0f, 1.0f) // Duplicated vertex
- } };
- const AZStd::vector<NvCloth::SimIndexType> indices = { { 3, 4, 5, 0, 1, 2, 6, 1, 7 } }; // Second triangle from the triplet 0,1,2 uses all static vertices and will be removed
- const size_t expectedVerticesSizeAfterSimplification = vertices.size() - 2;
- const size_t expectedIndicesSizeAfterSimplification = indices.size();
- const bool removeStaticTriangles = false;
- AZStd::vector<NvCloth::SimParticleFormat> simplifiedVertices;
- AZStd::vector<NvCloth::SimIndexType> simplifiedIndices;
- AZStd::vector<int> remappedVertices;
- AZ::Interface<NvCloth::IFabricCooker>::Get()->SimplifyMesh(vertices, indices, simplifiedVertices, simplifiedIndices, remappedVertices, removeStaticTriangles);
- ASSERT_EQ(simplifiedVertices.size(), expectedVerticesSizeAfterSimplification);
- ASSERT_EQ(simplifiedIndices.size(), expectedIndicesSizeAfterSimplification);
- ASSERT_EQ(remappedVertices.size(), vertices.size());
- for (size_t i = 0; i < remappedVertices.size(); ++i)
- {
- EXPECT_GE(remappedVertices[i], 0);
- EXPECT_LT(remappedVertices[i], simplifiedVertices.size());
- EXPECT_THAT(simplifiedVertices[remappedVertices[i]], IsCloseTolerance(vertices[i], Tolerance));
- }
- for (size_t i = 0; i < simplifiedIndices.size(); ++i)
- {
- EXPECT_GE(simplifiedIndices[i], 0);
- EXPECT_LT(simplifiedIndices[i], simplifiedVertices.size());
- EXPECT_EQ(simplifiedIndices[i], remappedVertices[indices[i]]);
- EXPECT_THAT(simplifiedVertices[simplifiedIndices[i]], IsCloseTolerance(vertices[indices[i]], Tolerance));
- }
- }
- } // namespace UnitTest
|