AdditiveMotionSamplingTests.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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/ActorInstance.h>
  9. #include <EMotionFX/Source/Actor.h>
  10. #include <EMotionFX/Source/TransformData.h>
  11. #include <EMotionFX/Source/Pose.h>
  12. #include <EMotionFX/Source/MotionLayerSystem.h>
  13. #include <EMotionFX/Source/Motion.h>
  14. #include <EMotionFX/Source/MotionData/NonUniformMotionData.h>
  15. #include <Tests/ActorFixture.h>
  16. #include <Tests/Matchers.h>
  17. #include <string>
  18. #include <vector>
  19. namespace EMotionFX
  20. {
  21. class MotionSamplingFixture
  22. : public ActorFixture
  23. {
  24. public:
  25. void CreateSubMotionLikeBindPose(const std::string& name)
  26. {
  27. const Skeleton* skeleton = GetActor()->GetSkeleton();
  28. size_t jointIndex = InvalidIndex;
  29. const Node* node = skeleton->FindNodeAndIndexByName(name.c_str(), jointIndex);
  30. ASSERT_NE(node, nullptr);
  31. ASSERT_NE(jointIndex, InvalidIndex);
  32. const Pose* bindPose = m_actorInstance->GetTransformData()->GetBindPose();
  33. const Transform& transform = bindPose->GetLocalSpaceTransform(jointIndex);
  34. CreateSubMotion(name, transform);
  35. }
  36. void CreateSubMotion(const std::string& name, const Transform& transform)
  37. {
  38. // Find and store the joint index.
  39. const Skeleton* skeleton = GetActor()->GetSkeleton();
  40. size_t jointIndex = InvalidIndex;
  41. const Node* node = skeleton->FindNodeAndIndexByName(name.c_str(), jointIndex);
  42. ASSERT_NE(node, nullptr);
  43. ASSERT_NE(jointIndex, InvalidIndex32);
  44. m_jointIndices.emplace_back(jointIndex);
  45. m_motion->GetMotionData()->AddJoint(name.c_str(), transform, transform);
  46. }
  47. void SetUp() override
  48. {
  49. ActorFixture::SetUp();
  50. // Get the joint that isn't in the motion data.
  51. Node* footNode = GetActor()->GetSkeleton()->FindNodeAndIndexByName("l_ball", m_footIndex);
  52. ASSERT_NE(footNode, nullptr);
  53. ASSERT_NE(m_footIndex, InvalidIndex32);
  54. m_motion = aznew Motion("TestMotion");
  55. m_motion->SetMotionData(aznew NonUniformMotionData());
  56. // Create submotions for joints that exist in the actor.
  57. for (const std::string& jointName : m_jointNames)
  58. {
  59. CreateSubMotionLikeBindPose(jointName);
  60. }
  61. // Update the motion duration and mark it as additive.
  62. m_motion->UpdateDuration();
  63. m_motion->GetMotionData()->SetAdditive(true);
  64. // Play this motion, creating a motion instance, so we can easily sample it.
  65. MotionSystem* motionSystem = m_actorInstance->GetMotionSystem();
  66. ASSERT_NE(motionSystem, nullptr);
  67. m_motionInstance = motionSystem->PlayMotion(m_motion);
  68. }
  69. void TearDown() override
  70. {
  71. if (m_motion)
  72. {
  73. m_motion->Destroy();
  74. }
  75. ActorFixture::TearDown();
  76. }
  77. protected:
  78. Motion* m_motion = nullptr;
  79. MotionInstance* m_motionInstance = nullptr; // Automatically deleted internally when deleting the actor instance.
  80. std::vector<size_t> m_jointIndices;
  81. std::vector<std::string> m_jointNames { "l_upLeg", "l_loLeg", "l_ankle" };
  82. size_t m_footIndex = InvalidIndex;
  83. };
  84. TEST_F(MotionSamplingFixture, SampleAdditiveJoint)
  85. {
  86. const Skeleton* skeleton = GetActor()->GetSkeleton();
  87. // Sample the joints that exist in our actor skeleton as well as inside the motion data.
  88. const Pose* bindPose = m_actorInstance->GetTransformData()->GetBindPose();
  89. for (size_t jointIndex : m_jointIndices)
  90. {
  91. // Sample the motion.
  92. Transform transform = Transform::CreateZero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that.
  93. m_motion->CalcNodeTransform(m_motionInstance, &transform, GetActor(), skeleton->GetNode(jointIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
  94. const Transform& bindTransform = bindPose->GetLocalSpaceTransform(jointIndex);
  95. EXPECT_THAT(transform, IsClose(bindTransform));
  96. }
  97. // Sample the motion for the foot node.
  98. Transform footTransform = Transform::CreateZero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that.
  99. m_motion->CalcNodeTransform(m_motionInstance, &footTransform, GetActor(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
  100. // Make sure we get an identity transform back as we try to sample a node that doesn't have a submotion in an additive motion.
  101. EXPECT_THAT(footTransform, IsClose(Transform::CreateIdentity()));
  102. // Make it a non-additive motion, or at least act like it.
  103. m_motion->GetMotionData()->SetAdditive(false);
  104. // Make sure we do not get an identity transform back now that it is a non-additive motion.
  105. footTransform.Zero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that.
  106. const Transform& expectedFootTransform = m_actorInstance->GetTransformData()->GetCurrentPose()->GetLocalSpaceTransform(m_footIndex);
  107. m_motion->CalcNodeTransform(m_motionInstance, &footTransform, GetActor(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
  108. EXPECT_THAT(footTransform, IsClose(expectedFootTransform));
  109. }
  110. TEST_F(MotionSamplingFixture, SampleAdditivePose)
  111. {
  112. // Sample a pose from the motion.
  113. Pose pose;
  114. pose.LinkToActorInstance(m_actorInstance);
  115. pose.InitFromBindPose(GetActor());
  116. pose.Zero();
  117. m_motion->Update(&pose, &pose, m_motionInstance);
  118. // Test if the joints that exist in both motion and actor have the expected transforms.
  119. const Pose* bindPose = m_actorInstance->GetTransformData()->GetBindPose();
  120. for (size_t jointIndex : m_jointIndices)
  121. {
  122. const Transform& transform = pose.GetLocalSpaceTransform(jointIndex);
  123. const Transform& bindTransform = bindPose->GetLocalSpaceTransform(jointIndex);
  124. EXPECT_THAT(transform, IsClose(bindTransform));
  125. }
  126. // Sample the foot.
  127. Transform footTransform = pose.GetLocalSpaceTransform(m_footIndex);
  128. EXPECT_THAT(footTransform, IsClose(Transform::CreateIdentity()));
  129. // Make it a non-additive motion, or at least act like it.
  130. m_motion->GetMotionData()->SetAdditive(false);
  131. // Make sure we do not get an identity transform back now that it is a non-additive motion.
  132. pose.Zero();
  133. m_motion->Update(&pose, &pose, m_motionInstance);
  134. footTransform = pose.GetLocalSpaceTransform(m_footIndex);
  135. EXPECT_THAT(footTransform, IsClose(Transform::CreateZero()));
  136. }
  137. } // end namespace EMotionFX