FrameDatabase.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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 <Allocators.h>
  10. #include <EMotionFX/Source/AnimGraphPose.h>
  11. #include <EMotionFX/Source/AnimGraphPosePool.h>
  12. #include <EMotionFX/Source/EMotionFXManager.h>
  13. #include <EMotionFX/Source/Motion.h>
  14. #include <CsvSerializers.h>
  15. #include <MotionMatchingInstance.h>
  16. #include <Frame.h>
  17. #include <Feature.h>
  18. #include <FrameDatabase.h>
  19. #include <EventData.h>
  20. #include <EMotionFX/Source/Pose.h>
  21. #include <EMotionFX/Source/TransformData.h>
  22. #include <EMotionFX/Source/MotionEvent.h>
  23. #include <EMotionFX/Source/MotionEventTable.h>
  24. #include <EMotionFX/Source/MotionEventTrack.h>
  25. #include <AzCore/Casting/numeric_cast.h>
  26. #include <AzCore/Serialization/SerializeContext.h>
  27. namespace EMotionFX::MotionMatching
  28. {
  29. AZ_CLASS_ALLOCATOR_IMPL(FrameDatabase, MotionMatchAllocator)
  30. FrameDatabase::FrameDatabase()
  31. {
  32. }
  33. FrameDatabase::~FrameDatabase()
  34. {
  35. Clear();
  36. }
  37. void FrameDatabase::Clear()
  38. {
  39. // Clear the frames.
  40. m_frames.clear();
  41. m_frames.shrink_to_fit();
  42. m_frameIndexByMotion.clear();
  43. // Clear other things.
  44. m_usedMotions.clear();
  45. m_usedMotions.shrink_to_fit();
  46. }
  47. void FrameDatabase::ExtractActiveMotionEventDatas(const Motion* motion, float time, AZStd::vector<EventData*>& activeEventDatas) const
  48. {
  49. activeEventDatas.clear();
  50. // Iterate over all motion event tracks and all events inside them.
  51. const MotionEventTable* eventTable = motion->GetEventTable();
  52. const size_t numTracks = eventTable->GetNumTracks();
  53. for (size_t t = 0; t < numTracks; ++t)
  54. {
  55. const MotionEventTrack* track = eventTable->GetTrack(t);
  56. const size_t numEvents = track->GetNumEvents();
  57. for (size_t e = 0; e < numEvents; ++e)
  58. {
  59. const MotionEvent& motionEvent = track->GetEvent(e);
  60. // Only handle range based events and events that include our time value.
  61. if (motionEvent.GetIsTickEvent() ||
  62. motionEvent.GetStartTime() > time ||
  63. motionEvent.GetEndTime() < time)
  64. {
  65. continue;
  66. }
  67. for (auto eventData : motionEvent.GetEventDatas())
  68. {
  69. activeEventDatas.emplace_back(const_cast<EventData*>(eventData.get()));
  70. }
  71. }
  72. }
  73. }
  74. bool FrameDatabase::IsFrameDiscarded(const Motion* motion, float frameTime, AZStd::vector<EventData*>& activeEvents) const
  75. {
  76. // Is frame discarded by a motion event?
  77. ExtractActiveMotionEventDatas(motion, frameTime, activeEvents);
  78. for (const EventData* eventData : activeEvents)
  79. {
  80. if (eventData->RTTI_GetType() == azrtti_typeid<DiscardFrameEventData>())
  81. {
  82. return true;
  83. }
  84. }
  85. return false;
  86. }
  87. AZStd::tuple<size_t, size_t> FrameDatabase::ImportFrames(Motion* motion, const FrameImportSettings& settings, bool mirrored)
  88. {
  89. AZ_PROFILE_SCOPE(Animation, "FrameDatabase::ImportFrames");
  90. AZ_Assert(motion, "The motion cannot be a nullptr");
  91. AZ_Assert(settings.m_sampleRate > 0, "The sample rate must be bigger than zero frames per second");
  92. AZ_Assert(settings.m_sampleRate <= 120, "The sample rate must be smaller than 120 frames per second");
  93. size_t numFramesImported = 0;
  94. size_t numFramesDiscarded = 0;
  95. // Calculate the number of frames we might need to import, in worst case.
  96. m_sampleRate = settings.m_sampleRate;
  97. const double timeStep = 1.0 / aznumeric_cast<double>(settings.m_sampleRate);
  98. const size_t worstCaseNumFrames = aznumeric_cast<size_t>(ceil(motion->GetDuration() / timeStep)) + 1;
  99. // Try to pre-allocate memory for the worst case scenario.
  100. if (m_frames.capacity() < m_frames.size() + worstCaseNumFrames)
  101. {
  102. m_frames.reserve(m_frames.size() + worstCaseNumFrames);
  103. }
  104. AZStd::vector<EventData*> activeEvents;
  105. // Iterate over all sample positions in the motion.
  106. const double totalTime = aznumeric_cast<double>(motion->GetDuration());
  107. double curTime = 0.0;
  108. while (curTime <= totalTime)
  109. {
  110. const float frameTime = aznumeric_cast<float>(curTime);
  111. if (!IsFrameDiscarded(motion, frameTime, activeEvents))
  112. {
  113. ImportFrame(motion, frameTime, mirrored);
  114. numFramesImported++;
  115. }
  116. else
  117. {
  118. numFramesDiscarded++;
  119. }
  120. curTime += timeStep;
  121. }
  122. // Make sure we include the last frame, if we stepped over it.
  123. if (curTime - timeStep < totalTime - 0.000001)
  124. {
  125. const float frameTime = aznumeric_cast<float>(totalTime);
  126. if (!IsFrameDiscarded(motion, frameTime, activeEvents))
  127. {
  128. ImportFrame(motion, frameTime, mirrored);
  129. numFramesImported++;
  130. }
  131. else
  132. {
  133. numFramesDiscarded++;
  134. }
  135. }
  136. // Automatically shrink the frame storage to their minimum size.
  137. if (settings.m_autoShrink)
  138. {
  139. m_frames.shrink_to_fit();
  140. }
  141. // Register the motion.
  142. if (AZStd::find(m_usedMotions.begin(), m_usedMotions.end(), motion) == m_usedMotions.end())
  143. {
  144. m_usedMotions.emplace_back(motion);
  145. }
  146. return { numFramesImported, numFramesDiscarded };
  147. }
  148. void FrameDatabase::ImportFrame(Motion* motion, float timeValue, bool mirrored)
  149. {
  150. m_frames.emplace_back(Frame(m_frames.size(), motion, timeValue, mirrored));
  151. m_frameIndexByMotion[motion].emplace_back(m_frames.back().GetFrameIndex());
  152. }
  153. size_t FrameDatabase::CalcMemoryUsageInBytes() const
  154. {
  155. size_t total = 0;
  156. total += m_frames.capacity() * sizeof(Frame);
  157. total += sizeof(m_frames);
  158. total += m_usedMotions.capacity() * sizeof(const Motion*);
  159. total += sizeof(m_usedMotions);
  160. return total;
  161. }
  162. size_t FrameDatabase::GetNumFrames() const
  163. {
  164. return m_frames.size();
  165. }
  166. size_t FrameDatabase::GetNumUsedMotions() const
  167. {
  168. return m_usedMotions.size();
  169. }
  170. const Motion* FrameDatabase::GetUsedMotion(size_t index) const
  171. {
  172. return m_usedMotions[index];
  173. }
  174. const Frame& FrameDatabase::GetFrame(size_t index) const
  175. {
  176. AZ_Assert(index < m_frames.size(), "Frame index is out of range!");
  177. return m_frames[index];
  178. }
  179. AZStd::vector<Frame>& FrameDatabase::GetFrames()
  180. {
  181. return m_frames;
  182. }
  183. const AZStd::vector<Frame>& FrameDatabase::GetFrames() const
  184. {
  185. return m_frames;
  186. }
  187. const AZStd::vector<const Motion*>& FrameDatabase::GetUsedMotions() const
  188. {
  189. return m_usedMotions;
  190. }
  191. size_t FrameDatabase::FindFrameIndex(Motion* motion, float playtime) const
  192. {
  193. auto iterator = m_frameIndexByMotion.find(motion);
  194. if (iterator == m_frameIndexByMotion.end())
  195. {
  196. return InvalidIndex;
  197. }
  198. const AZStd::vector<size_t>& frameIndices = iterator->second;
  199. for (const size_t frameIndex : frameIndices)
  200. {
  201. const Frame& frame = m_frames[frameIndex];
  202. if (playtime >= frame.GetSampleTime() &&
  203. frameIndex + 1 < m_frames.size() &&
  204. playtime <= m_frames[frameIndex + 1].GetSampleTime())
  205. {
  206. return frameIndex;
  207. }
  208. }
  209. return InvalidIndex;
  210. }
  211. void FrameDatabase::SaveAsCsv(const char* filename, ActorInstance* actorInstance, const ETransformSpace transformSpace, bool writePositions, bool writeRotations) const
  212. {
  213. PoseWriterCsv poseWriter;
  214. PoseWriterCsv::WriteSettings writeSettings{ writePositions, writeRotations };
  215. poseWriter.Begin(filename, actorInstance, writeSettings);
  216. Pose pose;
  217. pose.LinkToActorInstance(actorInstance);
  218. pose.InitFromBindPose(actorInstance);
  219. for (const Frame& currentFrame : m_frames)
  220. {
  221. currentFrame.SamplePose(&pose);
  222. poseWriter.WritePose(pose, transformSpace);
  223. }
  224. }
  225. } // namespace EMotionFX::MotionMatching