3
0

MorphTargetRuntimeTests.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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 <AzCore/std/smart_ptr/unique_ptr.h>
  9. #include "SystemComponentFixture.h"
  10. #include <EMotionFX/Source/Actor.h>
  11. #include <EMotionFX/Source/ActorInstance.h>
  12. #include <EMotionFX/Source/AnimGraph.h>
  13. #include <EMotionFX/Source/AnimGraphInstance.h>
  14. #include <EMotionFX/Source/AnimGraphMotionNode.h>
  15. #include <EMotionFX/Source/AnimGraphStateMachine.h>
  16. #include <EMotionFX/Source/BlendTree.h>
  17. #include <EMotionFX/Source/BlendTreeFinalNode.h>
  18. #include <EMotionFX/Source/BlendTreeMorphTargetNode.h>
  19. #include <EMotionFX/Source/BlendTreeParameterNode.h>
  20. #include <EMotionFX/Source/EMotionFXManager.h>
  21. #include <EMotionFX/Source/Mesh.h>
  22. #include <EMotionFX/Source/MorphSetup.h>
  23. #include <EMotionFX/Source/MorphTargetStandard.h>
  24. #include <EMotionFX/Source/MotionSet.h>
  25. #include <EMotionFX/Source/Node.h>
  26. #include <EMotionFX/Source/Parameter/FloatSliderParameter.h>
  27. #include <EMotionFX/Source/Parameter/ParameterFactory.h>
  28. #include <EMotionFX/Source/Pose.h>
  29. #include <MCore/Source/ReflectionSerializer.h>
  30. #include <AzCore/Serialization/SerializeContext.h>
  31. #include <Tests/Printers.h>
  32. #include <Tests/Matchers.h>
  33. #include <Tests/TestAssetCode/SimpleActors.h>
  34. #include <Tests/TestAssetCode/ActorFactory.h>
  35. namespace EMotionFX
  36. {
  37. class MorphTargetRuntimeFixture
  38. : public SystemComponentFixture
  39. {
  40. public:
  41. void ScaleMesh(Mesh* mesh)
  42. {
  43. const uint32 vertexCount = mesh->GetNumVertices();
  44. AZ::Vector3* positions = static_cast<AZ::Vector3*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_POSITIONS));
  45. for (uint32 vertexNum = 0; vertexNum < vertexCount; ++vertexNum)
  46. {
  47. positions[vertexNum] *= m_scaleFactor;
  48. }
  49. }
  50. void AddParam(const char* name, const AZ::TypeId& type, const AZStd::string& defaultValue)
  51. {
  52. EMotionFX::Parameter* parameter = EMotionFX::ParameterFactory::Create(type);
  53. parameter->SetName(name);
  54. MCore::ReflectionSerializer::DeserializeIntoMember(parameter, "defaultValue", defaultValue);
  55. m_animGraph->AddParameter(parameter);
  56. }
  57. void SetUp() override
  58. {
  59. SystemComponentFixture::SetUp();
  60. m_actor = ActorFactory::CreateAndInit<PlaneActor>("testActor");
  61. m_morphSetup = MorphSetup::Create();
  62. m_actor->SetMorphSetup(0, m_morphSetup);
  63. AZStd::unique_ptr<Actor> morphActor = m_actor->Clone();
  64. Mesh* morphMesh = morphActor->GetMesh(0, 0);
  65. ScaleMesh(morphMesh);
  66. MorphTargetStandard* morphTarget = MorphTargetStandard::Create(
  67. /*captureTransforms=*/ false,
  68. m_actor.get(),
  69. morphActor.get(),
  70. "morphTarget"
  71. );
  72. m_morphSetup->AddMorphTarget(morphTarget);
  73. // Without this call, the bind pose does not know about newly added
  74. // morph target (m_morphWeights.size() == 0)
  75. m_actor->ResizeTransformData();
  76. m_actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*convertUnitType=*/false);
  77. m_animGraph = AZStd::make_unique<AnimGraph>();
  78. AddParam("FloatParam", azrtti_typeid<EMotionFX::FloatSliderParameter>(), "0.0");
  79. BlendTreeParameterNode* parameterNode = aznew BlendTreeParameterNode();
  80. BlendTreeMorphTargetNode* morphTargetNode = aznew BlendTreeMorphTargetNode();
  81. morphTargetNode->SetMorphTargetNames({"morphTarget"});
  82. BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
  83. BlendTree* blendTree = aznew BlendTree();
  84. blendTree->SetName("testBlendTree");
  85. blendTree->AddChildNode(parameterNode);
  86. blendTree->AddChildNode(morphTargetNode);
  87. blendTree->AddChildNode(finalNode);
  88. blendTree->SetFinalNodeId(finalNode->GetId());
  89. m_stateMachine = aznew AnimGraphStateMachine();
  90. m_stateMachine->SetName("rootStateMachine");
  91. m_animGraph->SetRootStateMachine(m_stateMachine);
  92. m_stateMachine->AddChildNode(blendTree);
  93. m_stateMachine->SetEntryState(blendTree);
  94. m_stateMachine->InitAfterLoading(m_animGraph.get());
  95. // Create the connections once the port indices are known. The
  96. // parameter node's ports are not known until after
  97. // InitAfterLoading() is called
  98. morphTargetNode->AddConnection(
  99. parameterNode,
  100. aznumeric_caster(parameterNode->FindOutputPortIndex("FloatParam")),
  101. BlendTreeMorphTargetNode::PORTID_INPUT_WEIGHT
  102. );
  103. finalNode->AddConnection(
  104. morphTargetNode,
  105. BlendTreeMorphTargetNode::PORTID_OUTPUT_POSE,
  106. BlendTreeFinalNode::PORTID_INPUT_POSE
  107. );
  108. m_motionSet = AZStd::make_unique<MotionSet>();
  109. m_motionSet->SetName("testMotionSet");
  110. m_actorInstance = Integration::EMotionFXPtr<ActorInstance>::MakeFromNew(ActorInstance::Create(m_actor.get()));
  111. m_animGraphInstance = AnimGraphInstance::Create(m_animGraph.get(), m_actorInstance.get(), m_motionSet.get());
  112. m_actorInstance->SetAnimGraphInstance(m_animGraphInstance);
  113. }
  114. void TearDown() override
  115. {
  116. m_actor.reset();
  117. m_actorInstance.reset();
  118. m_motionSet.reset();
  119. m_animGraph.reset();
  120. SystemComponentFixture::TearDown();
  121. }
  122. // The members that are EMotionFXPtrs are the ones that are owned by
  123. // the test fixture. The others are created by the fixture but owned by
  124. // the EMotionFX runtime.
  125. AZStd::unique_ptr<Actor> m_actor;
  126. MorphSetup* m_morphSetup = nullptr;
  127. AZStd::unique_ptr<AnimGraph> m_animGraph;
  128. AnimGraphStateMachine* m_stateMachine = nullptr;
  129. AZStd::unique_ptr<MotionSet> m_motionSet;
  130. Integration::EMotionFXPtr<ActorInstance> m_actorInstance;
  131. AnimGraphInstance* m_animGraphInstance = nullptr;
  132. const float m_scaleFactor = 10.0f;
  133. };
  134. TEST_F(MorphTargetRuntimeFixture, DISABLED_TestMorphTargetMeshRuntime)
  135. {
  136. const float fps = 30.0f;
  137. const float updateInterval = 1.0f / fps;
  138. const Mesh* mesh = m_actor->GetMesh(0, 0);
  139. const uint32 vertexCount = mesh->GetNumOrgVertices();
  140. const AZ::Vector3* positions = static_cast<AZ::Vector3*>(mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_POSITIONS));
  141. const AZStd::vector<AZ::Vector3> neutralPoints = [vertexCount, &positions](){
  142. AZStd::vector<AZ::Vector3> p;
  143. for (uint32 vertexNum = 0; vertexNum < vertexCount; ++vertexNum)
  144. {
  145. p.emplace_back(positions[vertexNum]);
  146. }
  147. return p;
  148. }();
  149. const AZStd::array<float, 4> weights {
  150. {0.0f, 0.5f, 1.0f, 0.0f}
  151. };
  152. AZStd::vector<AZ::Vector3> gotWeightedPoints;
  153. AZStd::vector<AZ::Vector3> expectedWeightedPoints;
  154. for (const float weight : weights)
  155. {
  156. gotWeightedPoints.clear();
  157. expectedWeightedPoints.clear();
  158. static_cast<MCore::AttributeFloat*>(m_animGraphInstance->FindParameter("FloatParam"))->SetValue(weight);
  159. GetEMotionFX().Update(updateInterval);
  160. m_actorInstance->UpdateMeshDeformers(updateInterval);
  161. for (uint32 vertexNum = 0; vertexNum < vertexCount; ++vertexNum)
  162. {
  163. gotWeightedPoints.emplace_back(positions[vertexNum]);
  164. }
  165. for (const AZ::Vector3& neutralPoint : neutralPoints)
  166. {
  167. const AZ::Vector3 delta = (neutralPoint * m_scaleFactor) - neutralPoint;
  168. expectedWeightedPoints.emplace_back(neutralPoint + delta * weight);
  169. }
  170. EXPECT_THAT(gotWeightedPoints, ::testing::Pointwise(::IsClose(), expectedWeightedPoints));
  171. }
  172. }
  173. } // namespace EMotionFX