AnimGraphNodeProcessingTests.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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 <Tests/AnimGraphFixture.h>
  9. #include <EMotionFX/Source/AnimGraph.h>
  10. #include <EMotionFX/Source/AnimGraphStateMachine.h>
  11. #include <EMotionFX/Source/AnimGraphMotionNode.h>
  12. #include <EMotionFX/Source/BlendTree.h>
  13. #include <EMotionFX/Source/BlendTreeBlendNNode.h>
  14. #include <EMotionFX/Source/BlendTreeFloatConstantNode.h>
  15. #include <EMotionFX/Source/EMotionFXManager.h>
  16. #include <EMotionFX/Source/MotionData/NonUniformMotionData.h>
  17. #include <EMotionFX/Source/MotionSet.h>
  18. #include <EMotionFX/Source/Motion.h>
  19. #include <EMotionFX/Source/TransformData.h>
  20. #include <EMotionFX/Source/AnimGraphPosePool.h>
  21. namespace EMotionFX
  22. {
  23. struct NodeProcessingTestParam
  24. {
  25. size_t m_motionNodeCount;
  26. };
  27. class AnimGraphNodeProcessingTestFixture : public AnimGraphFixture
  28. , public ::testing::WithParamInterface<NodeProcessingTestParam>
  29. {
  30. public:
  31. void ConstructGraph() override
  32. {
  33. AnimGraphFixture::ConstructGraph();
  34. m_blendTreeAnimGraph = AnimGraphFactory::Create<OneBlendTreeNodeAnimGraph>();
  35. m_rootStateMachine = m_blendTreeAnimGraph->GetRootStateMachine();
  36. m_blendTree = m_blendTreeAnimGraph->GetBlendTreeNode();
  37. /*
  38. +----------+
  39. | Motion 1 +-----------+
  40. +----------+ |
  41. |
  42. +----------+ >+---------+ +-------+
  43. | Motion 2 +----------->| Blend N +-------------->+ Final |
  44. +----------+ ------>| | +-------+
  45. | >+---------+
  46. +----------+ | |
  47. | Motion N +-----+ |
  48. +----------+ |
  49. |
  50. +-------------+ |
  51. | Const Float +--------+
  52. +-------------+
  53. */
  54. const NodeProcessingTestParam& param = GetParam();
  55. m_blendNNode = aznew BlendTreeBlendNNode();
  56. m_blendTree->AddChildNode(m_blendNNode);
  57. BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
  58. m_blendTree->AddChildNode(finalNode);
  59. finalNode->AddConnection(m_blendNNode, BlendTreeBlendNNode::PORTID_OUTPUT_POSE, BlendTreeFinalNode::PORTID_INPUT_POSE);
  60. ASSERT_TRUE(param.m_motionNodeCount <= 10) << "The blend N node only has 10 pose inputs.";
  61. for (size_t i = 0; i < param.m_motionNodeCount; ++i)
  62. {
  63. AnimGraphMotionNode* motionNode = aznew AnimGraphMotionNode();
  64. motionNode->SetName(AZStd::string::format("MotionNode%zu", i).c_str());
  65. m_blendTree->AddChildNode(motionNode);
  66. m_blendNNode->AddConnection(motionNode, AnimGraphMotionNode::PORTID_OUTPUT_POSE, aznumeric_caster(i));
  67. m_motionNodes.push_back(motionNode);
  68. }
  69. m_blendNNode->UpdateParamWeights();
  70. m_blendNNode->SetParamWeightsEquallyDistributed(0.0f, 1.0f);
  71. m_blendNNode->SetSyncMode(AnimGraphObject::SYNCMODE_CLIPBASED);
  72. m_floatNode = aznew BlendTreeFloatConstantNode();
  73. m_blendTree->AddChildNode(m_floatNode);
  74. m_blendNNode->AddConnection(m_floatNode, BlendTreeFloatConstantNode::OUTPUTPORT_RESULT, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
  75. m_blendTreeAnimGraph->InitAfterLoading();
  76. }
  77. void SetUp() override
  78. {
  79. AnimGraphFixture::SetUp();
  80. m_animGraphInstance->Destroy();
  81. m_animGraphInstance = m_blendTreeAnimGraph->GetAnimGraphInstance(m_actorInstance, m_motionSet);
  82. for (size_t i = 0; i < m_motionNodes.size(); ++i)
  83. {
  84. const AZStd::string motionId = AZStd::string::format("testSkeletalMotion%zu", i);
  85. Motion* motion = aznew Motion(motionId.c_str());
  86. motion->SetMotionData(aznew NonUniformMotionData());
  87. motion->GetMotionData()->SetDuration(i + 1.0f);
  88. MotionSet::MotionEntry * motionEntry = aznew MotionSet::MotionEntry(motion->GetName(), motion->GetName(), motion);
  89. m_motionSet->AddMotionEntry(motionEntry);
  90. m_motionNodes[i]->AddMotionId(motionId.c_str());
  91. m_motionNodes[i]->RecursiveOnChangeMotionSet(m_animGraphInstance, m_motionSet); // Trigger create motion instance.
  92. m_motionNodes[i]->PickNewActiveMotion(m_animGraphInstance);
  93. }
  94. }
  95. public:
  96. std::vector<AnimGraphMotionNode*> m_motionNodes;
  97. BlendTree* m_blendTree = nullptr;
  98. BlendTreeFloatConstantNode* m_floatNode = nullptr;
  99. BlendTreeBlendNNode* m_blendNNode = nullptr;
  100. };
  101. TEST_P(AnimGraphNodeProcessingTestFixture, NodeProcessingWithBlendNTests)
  102. {
  103. // Calling update first to make sure unique data is created.
  104. GetEMotionFX().Update(0.0f);
  105. const float deltaTime = 0.1f;
  106. // Next, we will be mimicing the anim graph instance update in actor instance update function. We just call each steps individually so we can collect the data.
  107. for (int i = 0; i <= 10; ++i)
  108. {
  109. m_floatNode->SetValue(0.1f * i);
  110. // Check the pose ref data on the anim graph instance, make sure they are zeros before calling update.
  111. const size_t numUniqueData = m_animGraphInstance->GetNumUniqueObjectDatas();
  112. for (size_t i2 = 0; i2 < numUniqueData; ++i2)
  113. {
  114. const AnimGraphNodeData* uniqueData = static_cast<AnimGraphNodeData*>(m_animGraphInstance->GetUniqueObjectData(i2));
  115. EXPECT_EQ(uniqueData->GetPoseRefCount(), 0) << "Pose ref count data should be empty";
  116. }
  117. // Call update on the instance, make sure the pose ref count is increased.
  118. m_animGraphInstance->Update(deltaTime);
  119. for (size_t i2 = 0; i2 < numUniqueData; ++i2)
  120. {
  121. const AnimGraphNodeData* uniqueData = static_cast<AnimGraphNodeData*>(m_animGraphInstance->GetUniqueObjectData(i2));
  122. EXPECT_EQ(uniqueData->GetPoseRefCount(), 1) << "Pose ref count data should be 1";
  123. }
  124. // Call output function.
  125. m_animGraphInstance->Output(m_actorInstance->GetTransformData()->GetCurrentPose());
  126. // Collect active nodes
  127. AZStd::vector<AnimGraphNode*> activeNodes;
  128. m_animGraphInstance->CollectActiveAnimGraphNodes(&activeNodes, AZ::Uuid::CreateNull());
  129. AZStd::unordered_set<AZStd::string> activeNodeNames;
  130. for (const AnimGraphNode* node : activeNodes)
  131. {
  132. activeNodeNames.emplace(node->GetNameString());
  133. }
  134. // See which motion node is activated in the blendNNode.
  135. float blendWeight;
  136. AnimGraphNode* nodeA;
  137. AnimGraphNode* nodeB;
  138. uint32 poseIndexA;
  139. uint32 poseIndexB;
  140. m_blendNNode->FindBlendNodes(m_animGraphInstance, &nodeA, &nodeB, &poseIndexA, &poseIndexB, &blendWeight);
  141. // Make sure nodeA and nodeB are active.
  142. EXPECT_TRUE(activeNodeNames.find(nodeA->GetNameString()) != activeNodeNames.end()) << "%s should be activated", nodeA->GetName();
  143. if (nodeA != nodeB)
  144. {
  145. EXPECT_TRUE(activeNodeNames.find(nodeB->GetNameString()) != activeNodeNames.end()) << "%s should be activated", nodeB->GetName();
  146. // There will be 5 node always be activated, rootStateMachine, blendTree, floatConst, blendN, finalNode
  147. // If nodeA is not nodeB, then there will be two more motion node active.
  148. EXPECT_EQ(activeNodes.size(), 7);
  149. }
  150. else
  151. {
  152. EXPECT_EQ(activeNodes.size(), 6);
  153. }
  154. // Make sure we aren't blowing up the pose pool
  155. const AnimGraphPosePool& posePool = GetEMotionFX().GetThreadData(m_actorInstance->GetThreadIndex())->GetPosePool();
  156. EXPECT_EQ(posePool.GetNumUsedPoses(), 0) << "Pose pool should be freed after output called.";
  157. EXPECT_TRUE(posePool.GetNumMaxUsedPoses() <= 3) << "At most we are using 3 pose at the same time (two motion and a blendN).";
  158. }
  159. }
  160. std::vector<NodeProcessingTestParam> AnimGraphNodeProcessingTestTestData
  161. {
  162. {
  163. 2
  164. },
  165. {
  166. 5
  167. },
  168. {
  169. 10
  170. }
  171. };
  172. INSTANTIATE_TEST_CASE_P(AnimGraphNodeProcessingTests,
  173. AnimGraphNodeProcessingTestFixture,
  174. ::testing::ValuesIn(AnimGraphNodeProcessingTestTestData));
  175. } // namespace EMotionFX