AnimGraphStateMachineSyncTests.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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/EMotionFXManager.h>
  13. #include <EMotionFX/Source/MotionSet.h>
  14. #include <EMotionFX/Source/Motion.h>
  15. #include <EMotionFX/Source/MotionData/NonUniformMotionData.h>
  16. namespace EMotionFX
  17. {
  18. struct AnimGraphStateMachineSyncParam
  19. {
  20. float m_playSpeedA;
  21. float m_durationA;
  22. float m_playSpeedB;
  23. float m_durationB;
  24. bool m_syncEnabled;
  25. };
  26. class AnimGraphStateMachineSyncFixture
  27. : public AnimGraphFixture
  28. , public ::testing::WithParamInterface<AnimGraphStateMachineSyncParam>
  29. {
  30. public:
  31. void ConstructGraph() override
  32. {
  33. const AnimGraphStateMachineSyncParam param = GetParam();
  34. AnimGraphFixture::ConstructGraph();
  35. m_motionNodeAnimGraph = AnimGraphFactory::Create<TwoMotionNodeAnimGraph>();
  36. m_rootStateMachine = m_motionNodeAnimGraph->GetRootStateMachine();
  37. /*
  38. +---+ +---+
  39. =>| A |<----->| B |
  40. +-+-+ +-+-+
  41. */
  42. m_stateA = m_motionNodeAnimGraph->GetMotionNodeA();
  43. m_stateB = m_motionNodeAnimGraph->GetMotionNodeB();
  44. m_transition = AddTransitionWithTimeCondition(m_stateA,
  45. m_stateB,
  46. 1.0f/*blendTime*/,
  47. 0.0f/*countDownTime*/);
  48. if (param.m_syncEnabled)
  49. {
  50. m_transition->SetSyncMode(AnimGraphObject::SYNCMODE_CLIPBASED);
  51. }
  52. else
  53. {
  54. m_transition->SetSyncMode(AnimGraphObject::SYNCMODE_DISABLED);
  55. }
  56. m_motionNodeAnimGraph->InitAfterLoading();
  57. }
  58. void SetUpMotionNode(const char* motionId, float playSpeed, float duration, AnimGraphMotionNode* motionNode)
  59. {
  60. Motion* motion = aznew Motion(motionId);
  61. motion->SetMotionData(aznew NonUniformMotionData());
  62. motion->GetMotionData()->SetDuration(duration);
  63. MotionSet::MotionEntry* motionEntry = aznew MotionSet::MotionEntry(motion->GetName(), motion->GetName(), motion);
  64. m_motionSet->AddMotionEntry(motionEntry);
  65. motionNode->AddMotionId(motionId);
  66. motionNode->SetMotionPlaySpeed(playSpeed);
  67. motionNode->RecursiveOnChangeMotionSet(m_animGraphInstance, m_motionSet);
  68. motionNode->PickNewActiveMotion(m_animGraphInstance, static_cast<AnimGraphMotionNode::UniqueData*>(motionNode->FindOrCreateUniqueNodeData(m_animGraphInstance)));
  69. }
  70. void SetUp() override
  71. {
  72. const AnimGraphStateMachineSyncParam param = GetParam();
  73. AnimGraphFixture::SetUp();
  74. m_animGraphInstance->Destroy();
  75. m_animGraphInstance = m_motionNodeAnimGraph->GetAnimGraphInstance(m_actorInstance, m_motionSet);
  76. SetUpMotionNode("testMotionA", param.m_playSpeedA, param.m_durationA, m_stateA);
  77. SetUpMotionNode("testMotionB", param.m_playSpeedB, param.m_durationB, m_stateB);
  78. GetEMotionFX().Update(0.0f);
  79. }
  80. void TearDown() override
  81. {
  82. if (m_animGraphInstance)
  83. {
  84. m_animGraphInstance->Destroy();
  85. m_animGraphInstance = nullptr;
  86. }
  87. m_motionNodeAnimGraph.reset();
  88. AnimGraphFixture::TearDown();
  89. }
  90. public:
  91. AZStd::unique_ptr<TwoMotionNodeAnimGraph> m_motionNodeAnimGraph;
  92. AnimGraphMotionNode* m_stateA = nullptr;
  93. AnimGraphMotionNode* m_stateB = nullptr;
  94. AnimGraphStateTransition* m_transition = nullptr;
  95. };
  96. TEST_P(AnimGraphStateMachineSyncFixture, PlayspeedTests)
  97. {
  98. bool transitioned = false;
  99. Simulate(2.0f/*simulationTime*/, 10.0f/*expectedFps*/, 0.0f/*fpsVariance*/,
  100. /*preCallback*/[]([[maybe_unused]] AnimGraphInstance* animGraphInstance){},
  101. /*postCallback*/[]([[maybe_unused]] AnimGraphInstance* animGraphInstance){},
  102. /*preUpdateCallback*/[](AnimGraphInstance*, float, float, int){},
  103. /*postUpdateCallback*/[this, &transitioned](AnimGraphInstance* animGraphInstance, [[maybe_unused]] float time, [[maybe_unused]] float timeDelta, [[maybe_unused]] int frame)
  104. {
  105. if (m_rootStateMachine->IsTransitionActive(m_transition, animGraphInstance))
  106. {
  107. const float weight = m_transition->GetBlendWeight(animGraphInstance);
  108. const float motionPlaySpeedA = m_stateA->ExtractCustomPlaySpeed(animGraphInstance);
  109. const float durationA = m_stateA->GetDuration(animGraphInstance);
  110. const float statePlaySpeedA = m_stateA->GetPlaySpeed(animGraphInstance);
  111. const float motionPlaySpeedB = m_stateB->ExtractCustomPlaySpeed(animGraphInstance);
  112. const float durationB = m_stateB->GetDuration(animGraphInstance);
  113. const float statePlaySpeedB = m_stateB->GetPlaySpeed(animGraphInstance);
  114. if (m_transition->GetSyncMode() == AnimGraphObject::SYNCMODE_DISABLED)
  115. {
  116. // We don't blend playspeeds when sync is disabled, the source and the target states should keep their playspeeds.
  117. EXPECT_EQ(motionPlaySpeedA, statePlaySpeedA) << "Motion playspeeds should match the set playspeed in the motion node throughout transitioning.";
  118. EXPECT_EQ(motionPlaySpeedB, statePlaySpeedB);
  119. }
  120. else
  121. {
  122. float factorA;
  123. float factorB;
  124. float interpolatedSpeedA;
  125. AZStd::tie(interpolatedSpeedA, factorA, factorB) = AnimGraphNode::SyncPlaySpeeds(
  126. motionPlaySpeedA, durationA, motionPlaySpeedB, durationB, weight);
  127. EXPECT_FLOAT_EQ(statePlaySpeedA, interpolatedSpeedA * factorA);
  128. }
  129. transitioned = true;
  130. }
  131. // Check the parent state machine playspeed.
  132. const AZStd::vector<AnimGraphNode*>& activeStates = m_rootStateMachine->GetActiveStates(animGraphInstance);
  133. EXPECT_TRUE(activeStates.size() > 0);
  134. const float stateMachinePlaySpeed = m_rootStateMachine->GetPlaySpeed(animGraphInstance);
  135. const float activeStatePlaySpeed = activeStates[0]->GetPlaySpeed(animGraphInstance);
  136. EXPECT_FLOAT_EQ(stateMachinePlaySpeed, activeStatePlaySpeed) <<
  137. "The parent state machine playspeed equals the active state's in case we're not transitioning. In the transitioning case the current state playspeed is passed upwards.";
  138. }
  139. );
  140. EXPECT_TRUE(transitioned) << "The transition did not trigger and run. Test was unable to verify playspeeds.";
  141. }
  142. std::vector<AnimGraphStateMachineSyncParam> animGraphStateMachineSyncTestData
  143. {
  144. // Tests with syncing disabled
  145. {
  146. /*playSpeedA=*/0.3f,
  147. /*durationA=*/1.0f,
  148. /*playSpeedB=*/1.0f,
  149. /*durationB=*/1.0f,
  150. /*syncEnabled=*/false
  151. },
  152. {
  153. 2.0f,
  154. 0.5f,
  155. 3.0f,
  156. 1.0f,
  157. false
  158. },
  159. {
  160. 5.0f,
  161. 3.0f,
  162. 2.0f,
  163. 0.5f,
  164. false
  165. },
  166. // Tests with syncing
  167. {
  168. 0.0f,
  169. 1.0f,
  170. 1.0f,
  171. 1.0f,
  172. true
  173. },
  174. {
  175. 1.0f,
  176. 1.0f,
  177. 0.0f,
  178. 1.0f,
  179. true
  180. },
  181. {
  182. 0.3f,
  183. 0.5f,
  184. 1.0f,
  185. 2.0f,
  186. true
  187. },
  188. {
  189. 3.0f,
  190. 0.5f,
  191. 1.0f,
  192. 2.0f,
  193. true
  194. },
  195. {
  196. 2.0f,
  197. 3.0f,
  198. 3.0f,
  199. 0.5f,
  200. true
  201. }
  202. };
  203. INSTANTIATE_TEST_CASE_P(AnimGraphStateMachineSyncTests,
  204. AnimGraphStateMachineSyncFixture,
  205. ::testing::ValuesIn(animGraphStateMachineSyncTestData)
  206. );
  207. } // namespace EMotionFX