TrajectoryHistory.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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 <TrajectoryHistory.h>
  9. #include <EMotionFX/Source/ActorInstance.h>
  10. #include <EMotionFX/Source/TransformData.h>
  11. #include <EMotionFX/Source/EMotionFXManager.h>
  12. namespace EMotionFX::MotionMatching
  13. {
  14. TrajectoryHistory::Sample operator*(TrajectoryHistory::Sample sample, float weight)
  15. {
  16. return {sample.m_position * weight, sample.m_facingDirection * weight};
  17. }
  18. TrajectoryHistory::Sample operator*(float weight, TrajectoryHistory::Sample sample)
  19. {
  20. return {weight * sample.m_position, weight * sample.m_facingDirection};
  21. }
  22. TrajectoryHistory::Sample operator-(TrajectoryHistory::Sample lhs, const TrajectoryHistory::Sample& rhs)
  23. {
  24. return {lhs.m_position - rhs.m_position, lhs.m_facingDirection - rhs.m_facingDirection};
  25. }
  26. TrajectoryHistory::Sample operator+(TrajectoryHistory::Sample lhs, const TrajectoryHistory::Sample& rhs)
  27. {
  28. return {lhs.m_position + rhs.m_position, lhs.m_facingDirection + rhs.m_facingDirection};
  29. }
  30. void TrajectoryHistory::Init(const Pose& pose, size_t jointIndex, const AZ::Vector3& facingAxisDir, float numSecondsToTrack)
  31. {
  32. AZ_Assert(numSecondsToTrack > 0.0f, "Number of seconds to track has to be greater than zero.");
  33. Clear();
  34. m_jointIndex = jointIndex;
  35. m_facingAxisDir = facingAxisDir;
  36. m_numSecondsToTrack = numSecondsToTrack;
  37. // Pre-fill the history with samples from the current joint position.
  38. PrefillSamples(pose, /*timeDelta=*/1.0f / 60.0f);
  39. }
  40. void TrajectoryHistory::AddSample(const Pose& pose)
  41. {
  42. Sample sample;
  43. const Transform worldSpaceTransform = pose.GetWorldSpaceTransform(m_jointIndex);
  44. sample.m_position = worldSpaceTransform.m_position;
  45. sample.m_facingDirection = worldSpaceTransform.TransformVector(m_facingAxisDir).GetNormalizedSafe();
  46. // The new key will be added at the end of the keytrack.
  47. m_keytrack.AddKey(m_currentTime, sample);
  48. while (m_keytrack.GetNumKeys() > 2 &&
  49. ((m_keytrack.GetKey(m_keytrack.GetNumKeys() - 2)->GetTime() - m_keytrack.GetFirstTime()) > m_numSecondsToTrack))
  50. {
  51. m_keytrack.RemoveKey(0); // Remove first (oldest) key
  52. }
  53. }
  54. void TrajectoryHistory::PrefillSamples(const Pose& pose, float timeDelta)
  55. {
  56. const size_t numKeyframes = aznumeric_caster<>(m_numSecondsToTrack / timeDelta);
  57. for (size_t i = 0; i < numKeyframes; ++i)
  58. {
  59. AddSample(pose);
  60. Update(timeDelta);
  61. }
  62. }
  63. void TrajectoryHistory::Clear()
  64. {
  65. m_jointIndex = 0;
  66. m_currentTime = 0.0f;
  67. m_keytrack.ClearKeys();
  68. }
  69. void TrajectoryHistory::Update(float timeDelta)
  70. {
  71. m_currentTime += timeDelta;
  72. }
  73. TrajectoryHistory::Sample TrajectoryHistory::Evaluate(float time) const
  74. {
  75. if (m_keytrack.GetNumKeys() == 0)
  76. {
  77. return {};
  78. }
  79. return m_keytrack.GetValueAtTime(m_keytrack.GetLastTime() - time);
  80. }
  81. TrajectoryHistory::Sample TrajectoryHistory::EvaluateNormalized(float normalizedTime) const
  82. {
  83. const float firstTime = m_keytrack.GetFirstTime();
  84. const float lastTime = m_keytrack.GetLastTime();
  85. const float range = lastTime - firstTime;
  86. const float time = (1.0f - normalizedTime) * range + firstTime;
  87. return m_keytrack.GetValueAtTime(time);
  88. }
  89. void TrajectoryHistory::DebugDraw(AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Color& color, float timeStart) const
  90. {
  91. const size_t numKeyframes = m_keytrack.GetNumKeys();
  92. if (numKeyframes == 0)
  93. {
  94. return;
  95. }
  96. // Clip some of the newest samples.
  97. const float adjustedLastTime = m_keytrack.GetLastTime() - timeStart;
  98. size_t adjustedLastKey = m_keytrack.FindKeyNumber(adjustedLastTime);
  99. if (adjustedLastKey == InvalidIndex)
  100. {
  101. adjustedLastKey = m_keytrack.GetNumKeys() - 1;
  102. }
  103. const float firstTime = m_keytrack.GetFirstTime();
  104. const float range = adjustedLastTime - firstTime;
  105. debugDisplay.DepthTestOff();
  106. for (size_t i = 0; i < adjustedLastKey; ++i)
  107. {
  108. const float time = m_keytrack.GetKey(i)->GetTime();
  109. const float normalized = (time - firstTime) / range;
  110. if (normalized < 0.3f)
  111. {
  112. continue;
  113. }
  114. // Decrease size and fade out alpha the older the sample is.
  115. AZ::Color finalColor = color;
  116. finalColor.SetA(finalColor.GetA() * 0.6f * normalized);
  117. const float markerSize = m_debugMarkerSize * 0.7f * normalized;
  118. const Sample currentSample = m_keytrack.GetKey(i)->GetValue();
  119. debugDisplay.SetColor(finalColor);
  120. debugDisplay.DrawBall(currentSample.m_position, markerSize, /*drawShaded=*/false);
  121. const float facingDirectionLength = m_debugMarkerSize * 10.0f * normalized;
  122. debugDisplay.DrawLine(currentSample.m_position, currentSample.m_position + currentSample.m_facingDirection * facingDirectionLength);
  123. }
  124. }
  125. void TrajectoryHistory::DebugDrawSampled(AzFramework::DebugDisplayRequests& debugDisplay,
  126. size_t numSamples,
  127. const AZ::Color& color) const
  128. {
  129. debugDisplay.DepthTestOff();
  130. debugDisplay.SetColor(color);
  131. Sample lastSample = EvaluateNormalized(0.0f);
  132. for (size_t i = 0; i < numSamples; ++i)
  133. {
  134. const float sampleTime = i / static_cast<float>(numSamples - 1);
  135. const Sample currentSample = EvaluateNormalized(sampleTime);
  136. if (i > 0)
  137. {
  138. debugDisplay.DrawLine(lastSample.m_position, currentSample.m_position);
  139. }
  140. debugDisplay.DrawBall(currentSample.m_position, m_debugMarkerSize, /*drawShaded=*/false);
  141. lastSample = currentSample;
  142. }
  143. }
  144. } // namespace EMotionFX::MotionMatching