ActorAssetHelperTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AZTestShared/Math/MathTestHelpers.h>
  9. #include <AzCore/Component/Entity.h>
  10. #include <AzFramework/Components/TransformComponent.h>
  11. #include <Utils/MeshAssetHelper.h>
  12. #include <UnitTestHelper.h>
  13. #include <ActorHelper.h>
  14. #include <Integration/Components/ActorComponent.h>
  15. namespace UnitTest
  16. {
  17. //! Fixture to setup entity with actor component and the tests data.
  18. class NvClothMeshAssetHelper
  19. : public ::testing::Test
  20. {
  21. public:
  22. const AZStd::string RootNodeName = "root_node";
  23. const AZStd::string MeshNode1Name = "cloth_node_1";
  24. const AZStd::string MeshNode2Name = "cloth_node_2";
  25. const AZStd::string OtherNodeName = "other_node";
  26. const AZStd::vector<AZ::Vector3> MeshVertices = {{
  27. AZ::Vector3(-1.0f, 0.0f, 0.0f),
  28. AZ::Vector3(1.0f, 0.0f, 0.0f),
  29. AZ::Vector3(0.0f, 1.0f, 0.0f)
  30. }};
  31. const AZStd::vector<NvCloth::SimIndexType> MeshIndices = {{
  32. 0, 1, 2
  33. }};
  34. const AZStd::vector<VertexSkinInfluences> MeshSkinningInfo = {{
  35. VertexSkinInfluences{ SkinInfluence(1, 1.0f) },
  36. VertexSkinInfluences{ SkinInfluence(1, 1.0f) },
  37. VertexSkinInfluences{ SkinInfluence(1, 1.0f) }
  38. }};
  39. const AZStd::vector<AZ::Vector2> MeshUVs = {{
  40. AZ::Vector2(0.0f, 0.0f),
  41. AZ::Vector2(1.0f, 0.0f),
  42. AZ::Vector2(0.5f, 1.0f)
  43. }};
  44. // [inverse mass, motion constrain radius, backstop offset, backstop radius]
  45. const AZStd::vector<AZ::Color> MeshClothData = {{
  46. AZ::Color(0.75f, 0.6f, 0.5f, 0.1f),
  47. AZ::Color(1.0f, 0.16f, 0.1f, 1.0f),
  48. AZ::Color(0.25f, 1.0f, 0.9f, 0.5f)
  49. }};
  50. const AZ::u32 LodLevel = 0;
  51. protected:
  52. // ::testing::Test overrides ...
  53. void SetUp() override;
  54. void TearDown() override;
  55. EMotionFX::Integration::ActorComponent* m_actorComponent = nullptr;
  56. private:
  57. AZStd::unique_ptr<AZ::Entity> m_entity;
  58. };
  59. void NvClothMeshAssetHelper::SetUp()
  60. {
  61. m_entity = AZStd::make_unique<AZ::Entity>();
  62. m_entity->CreateComponent<AzFramework::TransformComponent>();
  63. m_actorComponent = m_entity->CreateComponent<EMotionFX::Integration::ActorComponent>();
  64. m_entity->Init();
  65. m_entity->Activate();
  66. }
  67. void NvClothMeshAssetHelper::TearDown()
  68. {
  69. m_entity->Deactivate();
  70. m_actorComponent = nullptr;
  71. m_entity.reset();
  72. }
  73. TEST_F(NvClothMeshAssetHelper, MeshAssetHelper_CreateAssetHelperWithInvalidEntityId_ReturnsNull)
  74. {
  75. AZ::EntityId entityId;
  76. AZStd::unique_ptr<NvCloth::AssetHelper> assetHelper = NvCloth::AssetHelper::CreateAssetHelper(entityId);
  77. EXPECT_TRUE(assetHelper.get() == nullptr);
  78. }
  79. TEST_F(NvClothMeshAssetHelper, MeshAssetHelper_CreateAssetHelperWithValidEntityId_ReturnsValidMeshAssetHelper)
  80. {
  81. AZStd::unique_ptr<AZ::Entity> entity = AZStd::make_unique<AZ::Entity>();
  82. AZStd::unique_ptr<NvCloth::AssetHelper> assetHelper = NvCloth::AssetHelper::CreateAssetHelper(entity->GetId());
  83. EXPECT_TRUE(assetHelper.get() != nullptr);
  84. EXPECT_TRUE(azrtti_cast<NvCloth::MeshAssetHelper*>(assetHelper.get()) != nullptr);
  85. }
  86. TEST_F(NvClothMeshAssetHelper, MeshAssetHelper_CreateAssetHelperWithActor_ReturnsValidMeshAssetHelper)
  87. {
  88. {
  89. auto actor = AZStd::make_unique<ActorHelper>("actor_test");
  90. actor->FinishSetup();
  91. m_actorComponent->SetActorAsset(CreateAssetFromActor(AZStd::move(actor)));
  92. }
  93. AZStd::unique_ptr<NvCloth::AssetHelper> assetHelper = NvCloth::AssetHelper::CreateAssetHelper(m_actorComponent->GetEntityId());
  94. EXPECT_TRUE(assetHelper.get() != nullptr);
  95. EXPECT_TRUE(azrtti_cast<NvCloth::MeshAssetHelper*>(assetHelper.get()) != nullptr);
  96. }
  97. TEST_F(NvClothMeshAssetHelper, MeshAssetHelper_GatherClothMeshNodesWithEmptyActor_ReturnsEmptyInfo)
  98. {
  99. {
  100. auto actor = AZStd::make_unique<ActorHelper>("actor_test");
  101. actor->FinishSetup();
  102. m_actorComponent->SetActorAsset(CreateAssetFromActor(AZStd::move(actor)));
  103. }
  104. AZStd::unique_ptr<NvCloth::AssetHelper> assetHelper = NvCloth::AssetHelper::CreateAssetHelper(m_actorComponent->GetEntityId());
  105. NvCloth::MeshNodeList meshNodes;
  106. assetHelper->GatherClothMeshNodes(meshNodes);
  107. EXPECT_TRUE(meshNodes.empty());
  108. }
  109. TEST_F(NvClothMeshAssetHelper, MeshAssetHelper_ObtainClothMeshNodeInfoWithEmptyActor_ReturnsFalse)
  110. {
  111. {
  112. auto actor = AZStd::make_unique<ActorHelper>("actor_test");
  113. actor->FinishSetup();
  114. m_actorComponent->SetActorAsset(CreateAssetFromActor(AZStd::move(actor)));
  115. }
  116. AZStd::unique_ptr<NvCloth::AssetHelper> assetHelper = NvCloth::AssetHelper::CreateAssetHelper(m_actorComponent->GetEntityId());
  117. NvCloth::MeshNodeInfo meshNodeInfo;
  118. NvCloth::MeshClothInfo meshClothInfo;
  119. bool infoObtained = assetHelper->ObtainClothMeshNodeInfo("", meshNodeInfo, meshClothInfo);
  120. EXPECT_FALSE(infoObtained);
  121. }
  122. // [TODO LYN-1891]
  123. // Revisit when Cloth Component Mesh works with Actors adapted to Atom models.
  124. // Editor Cloth component now uses the new AZ::Render::MeshComponentNotificationBus::OnModelReady
  125. // notification and this test does not setup a model yet.
  126. TEST_F(NvClothMeshAssetHelper, DISABLED_MeshAssetHelper_GatherClothMeshNodesWithActor_ReturnsCorrectMeshNodeList)
  127. {
  128. {
  129. auto actor = AZStd::make_unique<ActorHelper>("actor_test");
  130. actor->AddJoint(RootNodeName);
  131. auto meshNode1Index = actor->AddJoint(MeshNode1Name, AZ::Transform::CreateTranslation(AZ::Vector3(3.0f, -2.0f, 0.0f)), RootNodeName);
  132. auto otherNodeIndex = actor->AddJoint(OtherNodeName, AZ::Transform::CreateTranslation(AZ::Vector3(0.5f, 0.0f, 0.0f)), RootNodeName);
  133. auto meshNode2Index = actor->AddJoint(MeshNode2Name, AZ::Transform::CreateTranslation(AZ::Vector3(0.2f, 0.6f, 1.0f)), OtherNodeName);
  134. actor->SetMesh(LodLevel, meshNode1Index, CreateEMotionFXMesh(MeshVertices, MeshIndices, MeshSkinningInfo, MeshUVs/*, MeshClothData*/));
  135. actor->SetMesh(LodLevel, otherNodeIndex, CreateEMotionFXMesh(MeshVertices, MeshIndices));
  136. actor->SetMesh(LodLevel, meshNode2Index, CreateEMotionFXMesh(MeshVertices, MeshIndices, MeshSkinningInfo, MeshUVs/*, MeshClothData*/));
  137. actor->FinishSetup();
  138. m_actorComponent->SetActorAsset(CreateAssetFromActor(AZStd::move(actor)));
  139. }
  140. AZStd::unique_ptr<NvCloth::AssetHelper> assetHelper = NvCloth::AssetHelper::CreateAssetHelper(m_actorComponent->GetEntityId());
  141. NvCloth::MeshNodeList meshNodes;
  142. assetHelper->GatherClothMeshNodes(meshNodes);
  143. ASSERT_EQ(meshNodes.size(), 2);
  144. EXPECT_TRUE(meshNodes[0] == MeshNode1Name);
  145. EXPECT_TRUE(meshNodes[1] == MeshNode2Name);
  146. }
  147. // [TODO LYN-1891]
  148. // Revisit when Cloth Component Mesh works with Actors adapted to Atom models.
  149. // Editor Cloth component now uses the new AZ::Render::MeshComponentNotificationBus::OnModelReady
  150. // notification and this test does not setup a model yet.
  151. TEST_F(NvClothMeshAssetHelper, DISABLED_MeshAssetHelper_ObtainClothMeshNodeInfoWithActor_ReturnsCorrectClothInfo)
  152. {
  153. {
  154. auto actor = AZStd::make_unique<ActorHelper>("actor_test");
  155. actor->AddJoint(RootNodeName);
  156. auto meshNode1Index = actor->AddJoint(MeshNode1Name, AZ::Transform::CreateTranslation(AZ::Vector3(3.0f, -2.0f, 0.0f)), RootNodeName);
  157. auto otherNodeIndex = actor->AddJoint(OtherNodeName, AZ::Transform::CreateTranslation(AZ::Vector3(0.5f, 0.0f, 0.0f)), RootNodeName);
  158. auto meshNode2Index = actor->AddJoint(MeshNode2Name, AZ::Transform::CreateTranslation(AZ::Vector3(0.2f, 0.6f, 1.0f)), OtherNodeName);
  159. actor->SetMesh(LodLevel, meshNode1Index, CreateEMotionFXMesh(MeshVertices, MeshIndices, MeshSkinningInfo, MeshUVs/*, MeshClothData*/));
  160. actor->SetMesh(LodLevel, otherNodeIndex, CreateEMotionFXMesh(MeshVertices, MeshIndices));
  161. actor->SetMesh(LodLevel, meshNode2Index, CreateEMotionFXMesh(MeshVertices, MeshIndices, MeshSkinningInfo, MeshUVs/*, MeshClothData*/));
  162. actor->FinishSetup();
  163. m_actorComponent->SetActorAsset(CreateAssetFromActor(AZStd::move(actor)));
  164. }
  165. AZStd::unique_ptr<NvCloth::AssetHelper> assetHelper = NvCloth::AssetHelper::CreateAssetHelper(m_actorComponent->GetEntityId());
  166. NvCloth::MeshNodeInfo meshNodeInfo;
  167. NvCloth::MeshClothInfo meshClothInfo;
  168. bool infoObtained = assetHelper->ObtainClothMeshNodeInfo(MeshNode2Name, meshNodeInfo, meshClothInfo);
  169. EXPECT_TRUE(infoObtained);
  170. EXPECT_EQ(meshNodeInfo.m_lodLevel, LodLevel);
  171. ASSERT_EQ(meshNodeInfo.m_subMeshes.size(), 1);
  172. EXPECT_EQ(meshNodeInfo.m_subMeshes[0].m_primitiveIndex, 2);
  173. EXPECT_EQ(meshNodeInfo.m_subMeshes[0].m_verticesFirstIndex, 0);
  174. EXPECT_EQ(meshNodeInfo.m_subMeshes[0].m_numVertices, MeshVertices.size());
  175. EXPECT_EQ(meshNodeInfo.m_subMeshes[0].m_indicesFirstIndex, 0);
  176. EXPECT_EQ(meshNodeInfo.m_subMeshes[0].m_numIndices, MeshIndices.size());
  177. EXPECT_EQ(meshClothInfo.m_particles.size(), MeshVertices.size());
  178. EXPECT_EQ(meshClothInfo.m_particles.size(), MeshClothData.size());
  179. for (size_t i = 0; i < meshClothInfo.m_particles.size(); ++i)
  180. {
  181. EXPECT_THAT(meshClothInfo.m_particles[i].GetAsVector3(), IsCloseTolerance(MeshVertices[i], Tolerance));
  182. EXPECT_NEAR(meshClothInfo.m_particles[i].GetW(), MeshClothData[i].GetR(), ToleranceU8);
  183. }
  184. EXPECT_EQ(meshClothInfo.m_indices, MeshIndices);
  185. EXPECT_THAT(meshClothInfo.m_uvs, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), MeshUVs));
  186. EXPECT_EQ(meshClothInfo.m_motionConstraints.size(), MeshClothData.size());
  187. for (size_t i = 0; i < meshClothInfo.m_motionConstraints.size(); ++i)
  188. {
  189. EXPECT_NEAR(meshClothInfo.m_motionConstraints[i], MeshClothData[i].GetG(), ToleranceU8);
  190. }
  191. EXPECT_EQ(meshClothInfo.m_backstopData.size(), MeshClothData.size());
  192. for (size_t i = 0; i < meshClothInfo.m_backstopData.size(); ++i)
  193. {
  194. EXPECT_THAT(meshClothInfo.m_backstopData[i], IsCloseTolerance(AZ::Vector2(MeshClothData[i].GetB() * 2.0f - 1.0f, MeshClothData[i].GetA()), ToleranceU8));
  195. }
  196. }
  197. } // namespace UnitTest