CanMorphManyShapes.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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 <gtest/gtest.h>
  9. #include <AzQtComponents/Components/Widgets/SliderCombo.h>
  10. #include <EMotionFX/Source/AnimGraphStateMachine.h>
  11. #include <EMotionFX/Source/BlendTreeMorphTargetNode.h>
  12. #include <EMotionFX/Source/MorphSetup.h>
  13. #include <EMotionFX/Source/Mesh.h>
  14. #include <EMotionFX/Source/MorphTargetStandard.h>
  15. #include <EMotionStudio/Plugins/StandardPlugins/Source/MorphTargetsWindow/MorphTargetsWindowPlugin.h>
  16. #include <EMotionStudio/Plugins/StandardPlugins/Source/MorphTargetsWindow/MorphTargetGroupWidget.h>
  17. #include <EMotionFX/Source/Parameter/FloatSliderParameter.h>
  18. #include <EMotionFX/Source/Parameter/ParameterFactory.h>
  19. #include <MCore/Source/ReflectionSerializer.h>
  20. #include <Tests/TestAssetCode/ActorFactory.h>
  21. #include <Tests/TestAssetCode/SimpleActors.h>
  22. #include <Tests/UI/UIFixture.h>
  23. namespace EMotionFX
  24. {
  25. class CanMorphManyShapesFixture
  26. : public UIFixture
  27. {
  28. public:
  29. void ScaleMesh(Mesh* mesh)
  30. {
  31. const uint32 vertexCount = mesh->GetNumVertices();
  32. AZ::Vector3* positions = static_cast<AZ::Vector3*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_POSITIONS));
  33. for (uint32 vertexNum = 0; vertexNum < vertexCount; ++vertexNum)
  34. {
  35. positions[vertexNum] *= m_scaleFactor;
  36. }
  37. }
  38. void AddParam(const char* name, const AZ::TypeId& type, const AZStd::string& defaultValue)
  39. {
  40. EMotionFX::Parameter* parameter = EMotionFX::ParameterFactory::Create(type);
  41. parameter->SetName(name);
  42. MCore::ReflectionSerializer::DeserializeIntoMember(parameter, "defaultValue", defaultValue);
  43. m_animGraph->AddParameter(parameter);
  44. }
  45. void SetUp() override
  46. {
  47. UIFixture::SetUp();
  48. m_actor = ActorFactory::CreateAndInit<PlaneActor>("testActor");
  49. m_morphSetup = MorphSetup::Create();
  50. m_actor->SetMorphSetup(0, m_morphSetup);
  51. AZStd::unique_ptr<Actor> morphActor = m_actor->Clone();
  52. Mesh* morphMesh = morphActor->GetMesh(0, 0);
  53. ScaleMesh(morphMesh);
  54. MorphTargetStandard* morphTarget = MorphTargetStandard::Create(
  55. /*captureTransforms=*/ false,
  56. m_actor.get(),
  57. morphActor.get(),
  58. "morphTarget"
  59. );
  60. m_morphSetup->AddMorphTarget(morphTarget);
  61. // Without this call, the bind pose does not know about newly added morph target (m_morphWeights.size() == 0)
  62. m_actor->ResizeTransformData();
  63. m_actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*convertUnitType=*/false);
  64. m_animGraph = AZStd::make_unique<AnimGraph>();
  65. AddParam("FloatParam", azrtti_typeid<EMotionFX::FloatSliderParameter>(), "0.0");
  66. BlendTreeParameterNode* parameterNode = aznew BlendTreeParameterNode();
  67. BlendTreeMorphTargetNode* morphTargetNode = aznew BlendTreeMorphTargetNode();
  68. morphTargetNode->SetMorphTargetNames({ "morphTarget" });
  69. BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
  70. BlendTree* blendTree = aznew BlendTree();
  71. blendTree->SetName("testBlendTree");
  72. blendTree->AddChildNode(parameterNode);
  73. blendTree->AddChildNode(morphTargetNode);
  74. blendTree->AddChildNode(finalNode);
  75. blendTree->SetFinalNodeId(finalNode->GetId());
  76. m_stateMachine = aznew AnimGraphStateMachine();
  77. m_stateMachine->SetName("rootStateMachine");
  78. m_animGraph->SetRootStateMachine(m_stateMachine);
  79. m_stateMachine->AddChildNode(blendTree);
  80. m_stateMachine->SetEntryState(blendTree);
  81. m_stateMachine->InitAfterLoading(m_animGraph.get());
  82. // Create the connections once the port indices are known. The parameter node's ports are not known until after
  83. // InitAfterLoading() is called
  84. morphTargetNode->AddConnection(
  85. parameterNode,
  86. aznumeric_caster(parameterNode->FindOutputPortIndex("FloatParam")),
  87. BlendTreeMorphTargetNode::PORTID_INPUT_WEIGHT
  88. );
  89. finalNode->AddConnection(
  90. morphTargetNode,
  91. BlendTreeMorphTargetNode::PORTID_OUTPUT_POSE,
  92. BlendTreeFinalNode::PORTID_INPUT_POSE
  93. );
  94. m_motionSet = AZStd::make_unique<MotionSet>();
  95. m_motionSet->SetName("testMotionSet");
  96. m_actorInstance = Integration::EMotionFXPtr<ActorInstance>::MakeFromNew(ActorInstance::Create(m_actor.get()));
  97. m_animGraphInstance = AnimGraphInstance::Create(m_animGraph.get(), m_actorInstance.get(), m_motionSet.get());
  98. m_actorInstance->SetAnimGraphInstance(m_animGraphInstance);
  99. }
  100. void TearDown() override
  101. {
  102. m_actor.reset();
  103. m_actorInstance.reset();
  104. m_motionSet.reset();
  105. m_animGraph.reset();
  106. UIFixture::TearDown();
  107. }
  108. protected:
  109. AZStd::unique_ptr<Actor> m_actor;
  110. MorphSetup* m_morphSetup = nullptr;
  111. const float m_scaleFactor = 10.0f;
  112. AZStd::unique_ptr<AnimGraph> m_animGraph;
  113. AnimGraphStateMachine* m_stateMachine = nullptr;
  114. Integration::EMotionFXPtr<ActorInstance> m_actorInstance;
  115. AnimGraphInstance* m_animGraphInstance = nullptr;
  116. AZStd::unique_ptr<MotionSet> m_motionSet;
  117. };
  118. TEST_F(CanMorphManyShapesFixture, CanMorphManyShapes)
  119. {
  120. RecordProperty("test_case_id", "C1559259");
  121. // Change the Editor mode to Character
  122. EMStudio::GetMainWindow()->ApplicationModeChanged("Character");
  123. // Find the MorphTargetsWindowPlugin
  124. EMStudio::MorphTargetsWindowPlugin* morphTargetWindow = static_cast<EMStudio::MorphTargetsWindowPlugin*>(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::MorphTargetsWindowPlugin::CLASS_ID));
  125. ASSERT_TRUE(morphTargetWindow) << "MorphTargetsWindow plugin not found!";
  126. // Select the newly created actor instance
  127. AZStd::string result;
  128. EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(AZStd::string::format(("Select -actorInstanceID %s"), AZStd::to_string(m_actorInstance->GetID()).c_str()), result)) << result.c_str();
  129. EMStudio::MorphTargetGroupWidget* morphTargetGroupWidget = morphTargetWindow->GetDockWidget()->findChild<EMStudio::MorphTargetGroupWidget*>("EMFX.MorphTargetsWindowPlugin.MorphTargetGroupWidget");
  130. EXPECT_TRUE(morphTargetGroupWidget) << "Morph target Group not found";
  131. const EMStudio::MorphTargetGroupWidget::MorphTarget* morphTarget = morphTargetGroupWidget->GetMorphTarget(0);
  132. EXPECT_TRUE(morphTarget) << "Cannot access MorphTarget";
  133. // Switch the morphTarget to manual mode
  134. morphTarget->m_manualMode->click();
  135. // Set the slider to 0.5f;
  136. morphTarget->m_sliderWeight->slider()->setValue(0.5f);
  137. // Get the instance of the MorphTargetInstance
  138. EMotionFX::MorphSetupInstance::MorphTarget* morphTargetInstance = morphTarget->m_morphTargetInstance;
  139. ASSERT_TRUE(morphTargetInstance) << "Cannot get Instance of Morph Target";
  140. EXPECT_EQ(morphTargetInstance->GetWeight(), 0.5f) << "Morph Taget Instance is not set to the correct value";
  141. }
  142. } // namespace EMotionFX