/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include namespace UnitTest { //! Fixture to hold the tests data. class NvClothConstraints : public ::testing::Test { public: const AZStd::vector MeshMotionConstraintsData = {{ 1.0f, 0.5f, 0.0f }}; const float MotionConstraintsMaxDistance = 3.0f; const AZStd::vector MeshBackstopOffsetAndRadiusData = {{ AZ::Vector2(1.0f, 1.0f), AZ::Vector2(0.0f, 0.5f), AZ::Vector2(-1.0f, 0.1f) }}; const float BackstopMaxRadius = 3.0f; const float BackstopMaxBackOffset = 2.0f; const float BackstopMaxFrontOffset = 5.0f; const AZStd::vector MeshRemappedVertices = {{ 0, 1, 2 }}; const AZStd::vector SimulationParticles = {{ NvCloth::SimParticleFormat(1.0f,0.0f,0.0f,1.0f), NvCloth::SimParticleFormat(0.0f,1.0f,0.0f,0.0f), NvCloth::SimParticleFormat(0.0f,0.0f,1.0f,1.0f), }}; const AZStd::vector SimulationIndices = {{ 0, 1, 2 }}; }; TEST_F(NvClothConstraints, ClothConstraints_DefaultConstruct_ReturnsEmptyData) { NvCloth::ClothConstraints clothConstraints; EXPECT_TRUE(clothConstraints.GetMotionConstraints().empty()); EXPECT_TRUE(clothConstraints.GetSeparationConstraints().empty()); clothConstraints.CalculateConstraints({}, {}); EXPECT_TRUE(clothConstraints.GetMotionConstraints().empty()); EXPECT_TRUE(clothConstraints.GetSeparationConstraints().empty()); clothConstraints.CalculateConstraints(SimulationParticles, SimulationIndices); EXPECT_TRUE(clothConstraints.GetMotionConstraints().empty()); EXPECT_TRUE(clothConstraints.GetSeparationConstraints().empty()); } TEST_F(NvClothConstraints, ClothConstraints_CreateWithNoInfo_ReturnsEmptyData) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( {}, 0.0f, {}, 0.0f, 0.0f, 0.0f, {}, {}, {}); EXPECT_TRUE(clothConstraints->GetMotionConstraints().empty()); EXPECT_TRUE(clothConstraints->GetSeparationConstraints().empty()); } TEST_F(NvClothConstraints, ClothConstraints_CreateWithMotionConstraintsInfo_ReturnsValidMotionConstraints) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( MeshMotionConstraintsData, MotionConstraintsMaxDistance, {}, 0.0f, 0.0f, 0.0f, SimulationParticles, SimulationIndices, MeshRemappedVertices); const AZStd::vector& motionConstraints = clothConstraints->GetMotionConstraints(); EXPECT_TRUE(motionConstraints.size() == SimulationParticles.size()); EXPECT_THAT(motionConstraints[0].GetAsVector3(), IsCloseTolerance(SimulationParticles[0].GetAsVector3(), Tolerance)); EXPECT_THAT(motionConstraints[1].GetAsVector3(), IsCloseTolerance(SimulationParticles[1].GetAsVector3(), Tolerance)); EXPECT_THAT(motionConstraints[2].GetAsVector3(), IsCloseTolerance(SimulationParticles[2].GetAsVector3(), Tolerance)); EXPECT_NEAR(motionConstraints[0].GetW(), 3.0f, Tolerance); EXPECT_NEAR(motionConstraints[1].GetW(), 0.0f, Tolerance); EXPECT_NEAR(motionConstraints[2].GetW(), 0.0f, Tolerance); } TEST_F(NvClothConstraints, ClothConstraints_SetMotionConstraintMaxDistance_UpdatesMotionsConstraints) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( MeshMotionConstraintsData, MotionConstraintsMaxDistance, {}, 0.0f, 0.0f, 0.0f, SimulationParticles, SimulationIndices, MeshRemappedVertices); const float newMotionConstraintsMaxDistance = 6.0f; clothConstraints->SetMotionConstraintMaxDistance(newMotionConstraintsMaxDistance); const AZStd::vector& motionConstraints = clothConstraints->GetMotionConstraints(); EXPECT_TRUE(motionConstraints.size() == SimulationParticles.size()); EXPECT_NEAR(motionConstraints[0].GetW(), 6.0f, Tolerance); EXPECT_NEAR(motionConstraints[1].GetW(), 0.0f, Tolerance); EXPECT_NEAR(motionConstraints[2].GetW(), 0.0f, Tolerance); } TEST_F(NvClothConstraints, ClothConstraints_CreateWithBackstopInfo_ReturnsValidSeparationConstraints) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( {}, 0.0f, MeshBackstopOffsetAndRadiusData, BackstopMaxRadius, BackstopMaxBackOffset, BackstopMaxFrontOffset, SimulationParticles, SimulationIndices, MeshRemappedVertices); const AZStd::vector& separationConstraints = clothConstraints->GetSeparationConstraints(); EXPECT_TRUE(separationConstraints.size() == SimulationParticles.size()); EXPECT_NEAR(separationConstraints[0].GetW(), 3.0f, Tolerance); EXPECT_NEAR(separationConstraints[1].GetW(), 1.5f, Tolerance); EXPECT_NEAR(separationConstraints[2].GetW(), 0.3f, Tolerance); EXPECT_THAT(separationConstraints[0].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-1.88675f, -2.88675f, -2.88675f), Tolerance)); EXPECT_THAT(separationConstraints[1].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-0.866025f, 0.133975f, -0.866025f), Tolerance)); EXPECT_THAT(separationConstraints[2].GetAsVector3(), IsCloseTolerance(AZ::Vector3(3.05996f, 3.05996f, 4.05996f), Tolerance)); } TEST_F(NvClothConstraints, ClothConstraints_SetBackstopMaxRadius_UpdatesSeparationConstraints) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( {}, 0.0f, MeshBackstopOffsetAndRadiusData, BackstopMaxRadius, BackstopMaxBackOffset, BackstopMaxFrontOffset, SimulationParticles, SimulationIndices, MeshRemappedVertices); const float newBackstopMaxRadius = 6.0f; clothConstraints->SetBackstopMaxRadius(newBackstopMaxRadius); const AZStd::vector& separationConstraints = clothConstraints->GetSeparationConstraints(); EXPECT_TRUE(separationConstraints.size() == SimulationParticles.size()); EXPECT_NEAR(separationConstraints[0].GetW(), 6.0f, Tolerance); EXPECT_NEAR(separationConstraints[1].GetW(), 3.0f, Tolerance); EXPECT_NEAR(separationConstraints[2].GetW(), 0.6f, Tolerance); EXPECT_THAT(separationConstraints[0].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-3.6188f, -4.6188f, -4.6188f), Tolerance)); EXPECT_THAT(separationConstraints[1].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-1.73205f, -0.732051f, -1.73205f), Tolerance)); EXPECT_THAT(separationConstraints[2].GetAsVector3(), IsCloseTolerance(AZ::Vector3(3.23316f, 3.23316f, 4.23316f), Tolerance)); } TEST_F(NvClothConstraints, ClothConstraints_SetBackstopMaxOffsets_UpdatesSeparationConstraints) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( {}, 0.0f, MeshBackstopOffsetAndRadiusData, BackstopMaxRadius, BackstopMaxBackOffset, BackstopMaxFrontOffset, SimulationParticles, SimulationIndices, MeshRemappedVertices); const float newBackstopMaxBackOffset = -4.0f; const float newBackstopMaxFrontOffset = 3.0f; clothConstraints->SetBackstopMaxOffsets(newBackstopMaxBackOffset, newBackstopMaxFrontOffset); const AZStd::vector& separationConstraints = clothConstraints->GetSeparationConstraints(); EXPECT_TRUE(separationConstraints.size() == SimulationParticles.size()); EXPECT_NEAR(separationConstraints[0].GetW(), 3.0f, Tolerance); EXPECT_NEAR(separationConstraints[1].GetW(), 1.5f, Tolerance); EXPECT_NEAR(separationConstraints[2].GetW(), 0.3f, Tolerance); EXPECT_THAT(separationConstraints[0].GetAsVector3(), IsCloseTolerance(AZ::Vector3(5.04145f, 4.04145f, 4.04145f), Tolerance)); EXPECT_THAT(separationConstraints[1].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-0.866025f, 0.133975f, -0.866025f), Tolerance)); EXPECT_THAT(separationConstraints[2].GetAsVector3(), IsCloseTolerance(AZ::Vector3(1.90526f, 1.90526f, 2.90526f), Tolerance)); } TEST_F(NvClothConstraints, ClothConstraints_CalculateConstraintsWithEmptyData_ConstraintsRemainUnchanged) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( MeshMotionConstraintsData, MotionConstraintsMaxDistance, MeshBackstopOffsetAndRadiusData, BackstopMaxRadius, BackstopMaxBackOffset, BackstopMaxFrontOffset, SimulationParticles, SimulationIndices, MeshRemappedVertices); const AZStd::vector motionConstraints = clothConstraints->GetMotionConstraints(); const AZStd::vector separationConstraints = clothConstraints->GetSeparationConstraints(); clothConstraints->CalculateConstraints({}, {}); EXPECT_THAT(motionConstraints, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), clothConstraints->GetMotionConstraints())); EXPECT_THAT(separationConstraints, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), clothConstraints->GetSeparationConstraints())); } TEST_F(NvClothConstraints, ClothConstraints_CalculateConstraintsWithSameData_ConstraintsRemainUnchanged) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( MeshMotionConstraintsData, MotionConstraintsMaxDistance, MeshBackstopOffsetAndRadiusData, BackstopMaxRadius, BackstopMaxBackOffset, BackstopMaxFrontOffset, SimulationParticles, SimulationIndices, MeshRemappedVertices); const AZStd::vector motionConstraints = clothConstraints->GetMotionConstraints(); const AZStd::vector separationConstraints = clothConstraints->GetSeparationConstraints(); clothConstraints->CalculateConstraints(SimulationParticles, SimulationIndices); EXPECT_THAT(motionConstraints, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), clothConstraints->GetMotionConstraints())); EXPECT_THAT(separationConstraints, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), clothConstraints->GetSeparationConstraints())); } TEST_F(NvClothConstraints, ClothConstraints_CalculateConstraintsWithNewParticles_ContraintsAreModified) { AZStd::unique_ptr clothConstraints = NvCloth::ClothConstraints::Create( MeshMotionConstraintsData, MotionConstraintsMaxDistance, MeshBackstopOffsetAndRadiusData, BackstopMaxRadius, BackstopMaxBackOffset, BackstopMaxFrontOffset, SimulationParticles, SimulationIndices, MeshRemappedVertices); const AZStd::vector newParticles = {{ NvCloth::SimParticleFormat(0.0f,0.0f,1.0f,1.0f), NvCloth::SimParticleFormat(0.0f,1.0f,0.0f,1.0f), NvCloth::SimParticleFormat(1.0f,0.0f,1.0f,0.0f), }}; clothConstraints->CalculateConstraints(newParticles, SimulationIndices); const AZStd::vector& motionConstraints = clothConstraints->GetMotionConstraints(); const AZStd::vector& separationConstraints = clothConstraints->GetSeparationConstraints(); EXPECT_TRUE(motionConstraints.size() == newParticles.size()); EXPECT_NEAR(motionConstraints[0].GetW(), 3.0f, Tolerance); EXPECT_NEAR(motionConstraints[1].GetW(), 1.5f, Tolerance); EXPECT_NEAR(motionConstraints[2].GetW(), 0.0f, Tolerance); EXPECT_TRUE(separationConstraints.size() == newParticles.size()); EXPECT_NEAR(separationConstraints[0].GetW(), 3.0f, Tolerance); EXPECT_NEAR(separationConstraints[1].GetW(), 1.5f, Tolerance); EXPECT_NEAR(separationConstraints[2].GetW(), 0.3f, Tolerance); const float tolerance = 1e-2f; EXPECT_THAT(separationConstraints[0].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-3.03902f, 2.80752f, 3.80752f), tolerance)); EXPECT_THAT(separationConstraints[1].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-1.41659f, 0.651243f, -0.348757f), tolerance)); EXPECT_THAT(separationConstraints[2].GetAsVector3(), IsCloseTolerance(AZ::Vector3(6.15313f, -0.876132f, 0.123868f), tolerance)); } } // namespace UnitTest