FrameDatabase.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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. #pragma once
  9. #include <AzCore/Memory/Memory.h>
  10. #include <AzCore/RTTI/RTTI.h>
  11. #include <AzCore/std/containers/unordered_map.h>
  12. #include <AzCore/std/containers/vector.h>
  13. #include <AzCore/std/tuple.h>
  14. #include <EMotionFX/Source/EMotionFXConfig.h>
  15. #include <EMotionFX/Source/TransformSpace.h>
  16. #include <EventData.h>
  17. #include <Frame.h>
  18. namespace EMotionFX
  19. {
  20. class Motion;
  21. class ActorInstance;
  22. }
  23. namespace EMotionFX::MotionMatching
  24. {
  25. class MotionMatchingInstance;
  26. class MotionMatchEventData;
  27. //! A set of frames from your animations sampled at a given sample rate is stored in the frame database. A frame object knows about its index in the frame database,
  28. //! the animation it belongs to and the sample time in seconds. It does not hold the actual sampled pose for memory reasons as the `EMotionFX::Motion` already store the
  29. //! transform keyframes.
  30. //! The sample rate of the animation might differ from the sample rate used for the frame database. For example, your animations might be recorded with 60 Hz while we only want
  31. //! to extract the features with a sample rate of 30 Hz. As the motion matching algorithm is blending between the frames in the motion database while playing the animation window
  32. //! between the jumps/blends, it can make sense to have animations with a higher sample rate than we use to extract the features.
  33. //! A frame of the motion database can be used to sample a pose from which we can extract the features. It also provides functionality to sample a pose with a time offset to that frame.
  34. //! This can be handy in order to calculate joint velocities or trajectory samples.
  35. //! When importing animations, frames that are within the range of a discard frame motion event are ignored and won't be added to the motion database. Discard motion events can be
  36. //! used to cut out sections of the imported animations that are unwanted like a stretching part between two dance cards.
  37. class EMFX_API FrameDatabase
  38. {
  39. public:
  40. AZ_RTTI(FrameDatabase, "{3E5ED4F9-8975-41F2-B665-0086368F0DDA}")
  41. AZ_CLASS_ALLOCATOR_DECL
  42. //! The settings used when importing motions into the frame database.
  43. //! Used in combination with ImportFrames().
  44. struct EMFX_API FrameImportSettings
  45. {
  46. size_t m_sampleRate = 30; //< Sample at 30 frames per second on default.
  47. bool m_autoShrink = true; //< Automatically shrink the internal frame arrays to their minimum size afterwards.
  48. };
  49. FrameDatabase();
  50. virtual ~FrameDatabase();
  51. // Main functions.
  52. AZStd::tuple<size_t, size_t> ImportFrames(Motion* motion, const FrameImportSettings& settings, bool mirrored); //< Returns the number of imported frames and the number of discarded frames as second element.
  53. void Clear(); //< Clear the data, so you can re-initialize it with new data.
  54. // Statistics.
  55. size_t GetNumFrames() const;
  56. size_t GetNumUsedMotions() const;
  57. size_t CalcMemoryUsageInBytes() const;
  58. // Misc.
  59. const Motion* GetUsedMotion(size_t index) const;
  60. const Frame& GetFrame(size_t index) const;
  61. const AZStd::vector<Frame>& GetFrames() const;
  62. AZStd::vector<Frame>& GetFrames();
  63. const AZStd::vector<const Motion*>& GetUsedMotions() const;
  64. size_t GetSampleRate() const { return m_sampleRate; }
  65. //! Find the frame index for the given playtime and motion.
  66. //! NOTE: This is a slow operation and should not be used by the runtime without visual debugging.
  67. size_t FindFrameIndex(Motion* motion, float playtime) const;
  68. //! Save every frame as a row to a .csv file.
  69. void SaveAsCsv(const char* filename, ActorInstance* actorInstance, const ETransformSpace transformSpace, bool writePositions, bool writeRotations) const;
  70. private:
  71. void ImportFrame(Motion* motion, float timeValue, bool mirrored);
  72. bool IsFrameDiscarded(const Motion* motion, float frameTime, AZStd::vector<EventData*>& activeEvents) const;
  73. void ExtractActiveMotionEventDatas(const Motion* motion, float time, AZStd::vector<EventData*>& activeEventDatas) const; // Vector will be cleared internally.
  74. private:
  75. AZStd::vector<Frame> m_frames; //< The collection of frames. Keep in mind these don't hold a pose, but reference to a given frame/time value inside a given motion.
  76. AZStd::unordered_map<Motion*, AZStd::vector<size_t>> m_frameIndexByMotion;
  77. AZStd::vector<const Motion*> m_usedMotions; //< The list of used motions.
  78. size_t m_sampleRate = 0;
  79. };
  80. } // namespace EMotionFX::MotionMatching