AnimGraphDeferredInitTests.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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 <EMotionFX/Source/AnimGraphBindPoseNode.h>
  9. #include <EMotionFX/Source/AnimGraphMotionNode.h>
  10. #include <EMotionFX/Source/AnimGraphObject.h>
  11. #include <EMotionFX/Source/AnimGraphStateMachine.h>
  12. #include <EMotionFX/Source/AnimGraphStateTransition.h>
  13. #include <EMotionFX/Source/BlendTree.h>
  14. #include <EMotionFX/Source/BlendTreeBlend2Node.h>
  15. #include <EMotionFX/Source/BlendTreeBlendNNode.h>
  16. #include <EMotionFX/Source/BlendTreeParameterNode.h>
  17. #include <EMotionFX/Source/EMotionFXManager.h>
  18. #include <EMotionFX/Source/Parameter/FloatSliderParameter.h>
  19. #include <EMotionFX/Source/Parameter/ParameterFactory.h>
  20. #include <MCore/Source/AttributeFloat.h>
  21. #include <Tests/AnimGraphFixture.h>
  22. namespace EMotionFX
  23. {
  24. class DeferredInitBasicFixture
  25. : public AnimGraphFixture
  26. {
  27. public:
  28. void SetUp()
  29. {
  30. AnimGraphFixture::SetUp();
  31. // Add value parameter after m_animGraphInstance is created.
  32. AddValueParameter(azrtti_typeid<FloatSliderParameter>(), "weightParam");
  33. BlendTreeParameterNode* paramNode = aznew BlendTreeParameterNode();
  34. m_blendTree->AddChildNode(paramNode);
  35. paramNode->InitAfterLoading(m_animGraph.get());
  36. paramNode->InvalidateUniqueData(m_animGraphInstance);
  37. m_blend2Node->AddConnection(paramNode, static_cast<uint16>(paramNode->FindOutputPortByName("weightParam")->m_portId), BlendTreeBlend2Node::PORTID_INPUT_WEIGHT);
  38. }
  39. void ConstructGraph()
  40. {
  41. AnimGraphFixture::ConstructGraph();
  42. /*
  43. Inside rootStateMachine:
  44. +------------+ +--------------+
  45. | motionNode |------>| blendTreeNode|
  46. +------------+ +--------------+
  47. Inside blendTreeNode:
  48. +-----------+
  49. |motionNodeA|---+
  50. +-----------+ |
  51. +-->+----------+
  52. +-----------+ | | +---------+
  53. |motionNodeB|------>|blend2Node|---->|finalNode|
  54. +-----------+ | | +---------+
  55. +-->+----------+
  56. +---------+ |
  57. |paramNode|---+
  58. +---------+
  59. */
  60. m_stateStart = aznew AnimGraphMotionNode();
  61. m_blendTree = aznew BlendTree();
  62. AnimGraphMotionNode* motionNodeA = aznew AnimGraphMotionNode();
  63. AnimGraphMotionNode* motionNodeB = aznew AnimGraphMotionNode();
  64. m_blend2Node = aznew BlendTreeBlend2Node();
  65. BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
  66. m_blendTree->AddChildNode(motionNodeA);
  67. m_blendTree->AddChildNode(motionNodeB);
  68. m_blendTree->AddChildNode(m_blend2Node);
  69. m_blendTree->AddChildNode(finalNode);
  70. m_blend2Node->AddConnection(motionNodeA, AnimGraphMotionNode::PORTID_OUTPUT_POSE, BlendTreeBlend2Node::PORTID_INPUT_POSE_A);
  71. m_blend2Node->AddConnection(motionNodeB, AnimGraphMotionNode::PORTID_OUTPUT_POSE, BlendTreeBlend2Node::PORTID_INPUT_POSE_B);
  72. finalNode->AddConnection(m_blend2Node, BlendTreeBlend2Node::PORTID_OUTPUT_POSE, BlendTreeFinalNode::PORTID_INPUT_POSE);
  73. m_rootStateMachine->AddChildNode(m_stateStart);
  74. m_rootStateMachine->AddChildNode(m_blendTree);
  75. AddTransitionWithTimeCondition(m_stateStart, m_blendTree, 0.0f, 0.1f);
  76. m_rootStateMachine->SetEntryState(m_stateStart);
  77. }
  78. protected:
  79. AnimGraphMotionNode* m_stateStart = nullptr;
  80. BlendTree* m_blendTree = nullptr;
  81. BlendTreeBlend2Node* m_blend2Node = nullptr;
  82. };
  83. TEST_F(DeferredInitBasicFixture, DeferredInitTwoStateTests)
  84. {
  85. size_t expectedUniqueDatas = 0;
  86. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), expectedUniqueDatas) << "AnimGraph should not initialize nodes without update.";
  87. GetEMotionFX().Update(0.0f);
  88. // Root state machine, motion node, and time condition should be initialized.
  89. expectedUniqueDatas += 3;
  90. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), 3) << "Only root state machine, motion node, state transition time condition should be initialized.";
  91. // Activate the blend tree node by matching time condition.
  92. GetEMotionFX().Update(0.1f);
  93. // State transition, blend tree node, motion node A and B, parameter node, blend 2 node, and blend tree final node are initialized.
  94. expectedUniqueDatas += 7;
  95. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), expectedUniqueDatas) << " Seven new unique data should be added.";
  96. ParamSetValue<MCore::AttributeFloat, float>("weightParam", 1.0f);
  97. GetEMotionFX().Update(0.1f);
  98. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), 10) << "Number of initialized unique data should not change.";
  99. }
  100. ///////////////////////////////////////////////////////////////////////////
  101. class DeferredInitBlendNNodeFixture
  102. : public AnimGraphFixture
  103. {
  104. public:
  105. // Create a blend N nodes as well as 5 motion inputs and directly connects the input motions with the blend N node.
  106. BlendTreeBlendNNode* CreateBlendNNode(BlendTree* blendTree, BlendTreeParameterNode* parameterNode, const char* blendNNodeName)
  107. {
  108. BlendTreeBlendNNode* blendNNode = aznew BlendTreeBlendNNode();
  109. blendNNode->SetName(blendNNodeName);
  110. blendTree->AddChildNode(blendNNode);
  111. const uint16 motionNodeCount = 5;
  112. for (uint16 i = 0; i < motionNodeCount; ++i)
  113. {
  114. AnimGraphMotionNode* motionNode = aznew AnimGraphMotionNode();
  115. motionNode->SetName(AZStd::string::format("Motion %i (%s)", i, blendNNodeName).c_str());
  116. blendTree->AddChildNode(motionNode);
  117. blendNNode->AddConnection(motionNode, AnimGraphMotionNode::PORTID_OUTPUT_POSE, i);
  118. }
  119. blendNNode->UpdateParamWeights();
  120. blendNNode->SetParamWeightsEquallyDistributed(-1.0f, 1.0f);
  121. blendNNode->AddUnitializedConnection(parameterNode, 0, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
  122. blendNNode->SetSyncMode(AnimGraphObject::ESyncMode::SYNCMODE_DISABLED);
  123. return blendNNode;
  124. }
  125. void ConstructGraph() override
  126. {
  127. AnimGraphFixture::ConstructGraph();
  128. Parameter* parameter = ParameterFactory::Create(azrtti_typeid<FloatSliderParameter>());
  129. parameter->SetName("parameter_test");
  130. m_animGraph->AddParameter(parameter);
  131. AnimGraphMotionNode* entryMotionNode = aznew AnimGraphMotionNode();
  132. BlendTree* testBlendTree = aznew BlendTree();
  133. m_rootStateMachine->AddChildNode(entryMotionNode);
  134. m_rootStateMachine->AddChildNode(testBlendTree);
  135. AddTransitionWithTimeCondition(entryMotionNode, testBlendTree, 0.0f, 0.1f);
  136. m_rootStateMachine->SetEntryState(entryMotionNode);
  137. // Inside the blend tree.
  138. BlendTreeParameterNode* parameterNode = aznew BlendTreeParameterNode();
  139. testBlendTree->AddChildNode(parameterNode);
  140. BlendTreeBlendNNode* blendNNode = aznew BlendTreeBlendNNode();
  141. testBlendTree->AddChildNode(blendNNode);
  142. BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
  143. testBlendTree->AddChildNode(finalNode);
  144. blendNNode->AddUnitializedConnection(parameterNode, 0, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
  145. finalNode->AddConnection(blendNNode, BlendTreeBlendNNode::PORTID_OUTPUT_POSE, BlendTreeFinalNode::PORTID_INPUT_POSE);
  146. // Creates 5x blend N nodes as input for the blend N node created here. Each of these five blend N nodes have 5x input motions.
  147. for (uint16 i = 0; i < 5; ++i)
  148. {
  149. BlendTreeBlendNNode* inputNode = CreateBlendNNode(testBlendTree, parameterNode, AZStd::string::format("InputBlendNode%i", i).c_str());
  150. blendNNode->AddConnection(inputNode, AnimGraphMotionNode::PORTID_OUTPUT_POSE, i);
  151. }
  152. }
  153. };
  154. TEST_F(DeferredInitBlendNNodeFixture, DeferredInitBlendNNodeTests)
  155. {
  156. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), 0) << "AnimGraph should not initialize nodes without update.";
  157. MCore::AttributeFloat* testParameter = m_animGraphInstance->GetParameterValueChecked<MCore::AttributeFloat>(0);
  158. // Entry state active.
  159. GetEMotionFX().Update(0.0f);
  160. size_t expectedUniqueDatas = 3;
  161. size_t numInputBlendNNodes = 5;
  162. size_t numInputMotionNodes = 5;
  163. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), expectedUniqueDatas)
  164. << "Only the root state machine, the entry motion node as well as the time condition should have their unique data allocated.";
  165. // Transitioning to blend tree.
  166. GetEMotionFX().Update(0.1f);
  167. // Transition towards blend tree and blend tree node.
  168. expectedUniqueDatas += 2;
  169. // Final node, parameter node, blend N node; 5x blend N nodes; 5x input motions of the first, currently active input blend N.
  170. expectedUniqueDatas += 3 + numInputBlendNNodes + numInputMotionNodes;
  171. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), expectedUniqueDatas) << "Two of the blend N input nodes as well as everything in the root state machine should have their unique datas allocated.";
  172. // Changing the weight to activate more of the blend N inputs step by step.
  173. for (int i = 1; i < 5; ++i)
  174. {
  175. // Original param weight was 0, so i starts at 1 to avoid test redundancy.
  176. const float weight = 0.25f * i;
  177. testParameter->SetValue(weight);
  178. GetEMotionFX().Update(0.1f);
  179. expectedUniqueDatas += numInputMotionNodes;
  180. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), expectedUniqueDatas)
  181. << "Five new motion node unique datas should be allocated.";
  182. }
  183. EXPECT_EQ(m_animGraphInstance->CalcNumAllocatedUniqueDatas(), m_animGraphInstance->GetAnimGraph()->GetNumObjects())
  184. << "All objects should have their unique datas allocated.";
  185. }
  186. } // end namespace EMotionFX