QuaternionParameterTests.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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/AnimGraph.h>
  9. #include <EMotionFX/Source/AnimGraphBindPoseNode.h>
  10. #include <EMotionFX/Source/AnimGraphStateMachine.h>
  11. #include <EMotionFX/Source/BlendTree.h>
  12. #include <EMotionFX/Source/BlendTreeParameterNode.h>
  13. #include <EMotionFX/Source/BlendTreeTwoLinkIKNode.h>
  14. #include <EMotionFX/Source/EMotionFXManager.h>
  15. #include <EMotionFX/Source/Parameter/RotationParameter.h>
  16. #include <MCore/Source/ReflectionSerializer.h>
  17. #include <Tests/AnimGraphFixture.h>
  18. namespace EMotionFX
  19. {
  20. class QuaternionParameterFixture
  21. : public AnimGraphFixture
  22. , public ::testing::WithParamInterface<AZ::Quaternion>
  23. {
  24. public:
  25. void ConstructGraph() override
  26. {
  27. AnimGraphFixture::ConstructGraph();
  28. m_param = GetParam();
  29. m_blendTreeAnimGraph = AnimGraphFactory::Create<OneBlendTreeNodeAnimGraph>();
  30. m_rootStateMachine = m_blendTreeAnimGraph->GetRootStateMachine();
  31. m_blendTree = m_blendTreeAnimGraph->GetBlendTreeNode();
  32. AddParameter<RotationParameter, AZ::Quaternion>("quaternionTest", m_param);
  33. /*
  34. +------------+
  35. |bindPoseNode+---+
  36. +------------+ |
  37. +-->+-------------+ +---------+
  38. +-----------+ |twoLinkIKNode+---->+finalNode|
  39. |m_paramNode+------>+-------------+ +---------+
  40. +-----------+
  41. */
  42. BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
  43. AnimGraphBindPoseNode* bindPoseNode = aznew AnimGraphBindPoseNode();
  44. m_paramNode = aznew BlendTreeParameterNode();
  45. // Using two link IK Node because its GoalRot input port uses quaternion.
  46. m_twoLinkIKNode = aznew BlendTreeTwoLinkIKNode();
  47. m_blendTree->AddChildNode(finalNode);
  48. m_blendTree->AddChildNode(m_twoLinkIKNode);
  49. m_blendTree->AddChildNode(bindPoseNode);
  50. m_blendTree->AddChildNode(m_paramNode);
  51. m_twoLinkIKNode->AddConnection(bindPoseNode, AnimGraphBindPoseNode::PORTID_OUTPUT_POSE, BlendTreeTwoLinkIKNode::PORTID_INPUT_POSE);
  52. finalNode->AddConnection(m_twoLinkIKNode, BlendTreeTwoLinkIKNode::PORTID_OUTPUT_POSE, BlendTreeFinalNode::PORTID_INPUT_POSE);
  53. m_blendTreeAnimGraph->InitAfterLoading();
  54. };
  55. void SetUp() override
  56. {
  57. AnimGraphFixture::SetUp();
  58. m_animGraphInstance->Destroy();
  59. m_animGraphInstance = m_blendTreeAnimGraph->GetAnimGraphInstance(m_actorInstance, m_motionSet);
  60. }
  61. template <class paramType, class inputType>
  62. void ParamSetValue(const AZStd::string& paramName, const inputType& value)
  63. {
  64. const AZ::Outcome<size_t> parameterIndex = m_animGraphInstance->FindParameterIndex(paramName);
  65. MCore::Attribute* param = m_animGraphInstance->GetParameterValue(static_cast<AZ::u32>(parameterIndex.GetValue()));
  66. paramType* typeParam = static_cast<paramType*>(param);
  67. typeParam->SetValue(value);
  68. };
  69. protected:
  70. AZ::Quaternion m_param;
  71. BlendTree* m_blendTree = nullptr;
  72. BlendTreeParameterNode* m_paramNode = nullptr;
  73. BlendTreeTwoLinkIKNode* m_twoLinkIKNode = nullptr;
  74. private:
  75. template<class ParameterType, class ValueType>
  76. void AddParameter(const AZStd::string& name, const ValueType& defaultValue)
  77. {
  78. ParameterType* parameter = aznew ParameterType();
  79. parameter->SetName(name);
  80. parameter->SetDefaultValue(defaultValue);
  81. m_blendTreeAnimGraph->AddParameter(parameter);
  82. }
  83. };
  84. TEST_P(QuaternionParameterFixture, ParameterOutputsCorrectQuaternion)
  85. {
  86. // Parameter node needs to connect to another node, otherwise it will not update.
  87. m_twoLinkIKNode->AddConnection(m_paramNode, aznumeric_caster(m_paramNode->FindOutputPortIndex("quaternionTest")), BlendTreeTwoLinkIKNode::PORTID_INPUT_GOALROT);
  88. GetEMotionFX().Update(1.0f / 60.0f);
  89. // Check correct output for quaternion parameter.
  90. const AZ::Quaternion& quaternionTestParam = m_paramNode->GetOutputQuaternion(m_animGraphInstance,
  91. m_paramNode->FindOutputPortIndex("quaternionTest"))->GetValue();
  92. EXPECT_TRUE(quaternionTestParam.GetX() == m_param.GetX()) << "Quaternion X value should be the same as expected Quaternion X value.";
  93. EXPECT_TRUE(quaternionTestParam.GetY() == m_param.GetY()) << "Quaternion Y value should be the same as expected Quaternion Y value.";
  94. EXPECT_TRUE(quaternionTestParam.GetZ() == m_param.GetZ()) << "Quaternion Z value should be the same as expected Quaternion Z value.";
  95. EXPECT_TRUE(quaternionTestParam.GetW() == m_param.GetW()) << "Quaternion W value should be the same as expected Quaternion W value.";
  96. }
  97. TEST_P(QuaternionParameterFixture, QuaternionSetValueOutputsCorrectQuaternion)
  98. {
  99. m_twoLinkIKNode->AddConnection(m_paramNode, aznumeric_caster(m_paramNode->FindOutputPortIndex("quaternionTest")), BlendTreeTwoLinkIKNode::PORTID_INPUT_GOALROT);
  100. GetEMotionFX().Update(1.0f / 60.0f);
  101. // Shuffle the Quaternion parameter values to check changing quaternion values will be processed correctly.
  102. ParamSetValue<MCore::AttributeQuaternion, AZ::Quaternion>("quaternionTest", AZ::Quaternion(m_param.GetY(), m_param.GetZ(), m_param.GetX(), m_param.GetW()));
  103. GetEMotionFX().Update(1.0f / 60.0f);
  104. const AZ::Quaternion& quaternionTestParam = m_paramNode->GetOutputQuaternion(m_animGraphInstance,
  105. m_paramNode->FindOutputPortIndex("quaternionTest"))->GetValue();
  106. EXPECT_FLOAT_EQ(quaternionTestParam.GetX(), m_param.GetY()) << "Input Quaternion X value should be the same as expected Quaternion Y value.";
  107. EXPECT_FLOAT_EQ(quaternionTestParam.GetY(), m_param.GetZ()) << "Input Quaternion Y value should be the same as expected Quaternion Z value.";
  108. EXPECT_FLOAT_EQ(quaternionTestParam.GetZ(), m_param.GetX()) << "Input Quaternion Z value should be the same as expected Quaternion X value.";
  109. EXPECT_FLOAT_EQ(quaternionTestParam.GetW(), m_param.GetW()) << "Input Quaternion W value should be the same as expected Quaternion W value.";
  110. };
  111. std::vector<AZ::Quaternion> quaternionParameterTestData
  112. {
  113. AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f),
  114. AZ::Quaternion(1.0f, 0.5f, -0.5f, 1.0f),
  115. AZ::Quaternion(AZ::Constants::FloatMax, -AZ::Constants::FloatMax, AZ::Constants::FloatEpsilon, 1.0f)
  116. };
  117. INSTANTIATE_TEST_CASE_P(QuaternionParameter_ValidOutputTests,
  118. QuaternionParameterFixture,
  119. ::testing::ValuesIn(quaternionParameterTestData)
  120. );
  121. } // end namespace EMotionFX