diff --git a/Gems/MotionMatching/Code/Include/MotionMatching/MotionMatchingBus.h b/Gems/MotionMatching/Code/Include/MotionMatching/MotionMatchingBus.h index 5b2bc1847a..dbf38e802b 100644 --- a/Gems/MotionMatching/Code/Include/MotionMatching/MotionMatchingBus.h +++ b/Gems/MotionMatching/Code/Include/MotionMatching/MotionMatchingBus.h @@ -11,8 +11,20 @@ #include #include +#include + namespace EMotionFX::MotionMatching { + class DebugDrawRequests + : public AZ::EBusTraits + { + public: + AZ_RTTI(DebugDrawRequests, "{7BBA4249-EC00-445C-8A0C-4472841049C3}"); + + virtual void DebugDraw(AzFramework::DebugDisplayRequests& debugDisplay) = 0; + }; + using DebugDrawRequestBus = AZ::EBus; + class MotionMatchingRequests { public: diff --git a/Gems/MotionMatching/Code/Source/BlendTreeMotionMatchNode.cpp b/Gems/MotionMatching/Code/Source/BlendTreeMotionMatchNode.cpp index 6661233b66..1546be4669 100644 --- a/Gems/MotionMatching/Code/Source/BlendTreeMotionMatchNode.cpp +++ b/Gems/MotionMatching/Code/Source/BlendTreeMotionMatchNode.cpp @@ -297,8 +297,6 @@ namespace EMotionFX::MotionMatching ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::PushPerformanceHistogramValue, "Output", m_outputTimeInMs); #endif } - - instance->DebugDraw(); } AZ::Crc32 BlendTreeMotionMatchNode::GetTrajectoryPathSettingsVisibility() const diff --git a/Gems/MotionMatching/Code/Source/ImGuiMonitor.cpp b/Gems/MotionMatching/Code/Source/ImGuiMonitor.cpp index 97b666c693..158a4b0d23 100644 --- a/Gems/MotionMatching/Code/Source/ImGuiMonitor.cpp +++ b/Gems/MotionMatching/Code/Source/ImGuiMonitor.cpp @@ -16,10 +16,11 @@ namespace EMotionFX::MotionMatching ImGuiMonitor::ImGuiMonitor() { - m_performanceStats.m_name = "Performance Statistics"; + m_performanceStats.SetName("Performance Statistics"); + m_performanceStats.SetHistogramBinCount(500); - m_featureCosts.m_name = "Feature Costs"; - m_featureCosts.m_histogramContainerCount = 100; + m_featureCosts.SetName("Feature Costs"); + m_featureCosts.SetHistogramBinCount(100); ImGui::ImGuiUpdateListenerBus::Handler::BusConnect(); ImGuiMonitorRequestBus::Handler::BusConnect(); @@ -40,18 +41,40 @@ namespace EMotionFX::MotionMatching if (ImGui::Begin("Motion Matching")) { + if (ImGui::CollapsingHeader("Motion Database", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed)) + { + if (ImGui::BeginTable("MDB", 2)) + { + ImGui::TableNextColumn(); ImGui::Text("Memory Usage: %.2f MB", m_frameDatabaseInfo.m_memoryUsedInBytes / 1024.0f / 1024.0f); + ImGui::TableNextColumn(); ImGui::Text("Motion Data: %.0f minutes", m_frameDatabaseInfo.m_motionDataInSeconds / 60.0f); + ImGui::TableNextColumn(); ImGui::Text("Num Frames: %zu", m_frameDatabaseInfo.m_numFrames); + ImGui::TableNextColumn(); ImGui::Text("Num Motions: %zu", m_frameDatabaseInfo.m_numMotions); + ImGui::EndTable(); + } + } + if (ImGui::CollapsingHeader("Feature Matrix", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed)) { - ImGui::Text("Memory Usage: %.2f MB", m_featureMatrixMemoryUsageInBytes / 1024.0f / 1024.0f); - ImGui::Text("Num Frames: %zu", m_featureMatrixNumFrames); - ImGui::Text("Num Feature Components: %zu", m_featureMatrixNumComponents); + if (ImGui::BeginTable("FM", 2)) + { + ImGui::TableNextColumn(); ImGui::Text("Memory Usage: %.2f MB", m_featurMatrixInfo.m_memoryUsedInBytes / 1024.0f / 1024.0f); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); ImGui::Text("Num Frames: %zu", m_featurMatrixInfo.m_numFrames); + ImGui::TableNextColumn(); ImGui::Text("Num Feature Components: %zu", m_featurMatrixInfo.m_numDimensions); + ImGui::EndTable(); + } } if (ImGui::CollapsingHeader("Kd-Tree", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed)) { - ImGui::Text("Memory Usage: %.2f MB", m_kdTreeMemoryUsageInBytes / 1024.0f / 1024.0f); - ImGui::Text("Num Nodes: %zu", m_kdTreeNumNodes); - ImGui::Text("Num Dimensions: %zu", m_kdTreeNumDimensions); + if (ImGui::BeginTable("KDT", 2)) + { + ImGui::TableNextColumn(); ImGui::Text("Memory Usage: %.2f MB", m_kdTreeInfo.m_memoryUsedInBytes / 1024.0f / 1024.0f); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); ImGui::Text("Num Nodes: %zu", m_kdTreeInfo.m_numNodes); + ImGui::TableNextColumn(); ImGui::Text("Num Dimensions: %zu", m_kdTreeInfo.m_numDimensions); + ImGui::EndTable(); + } } m_performanceStats.OnImGuiUpdate(); @@ -63,8 +86,8 @@ namespace EMotionFX::MotionMatching { if (ImGui::BeginMenu("Motion Matching")) { - ImGui::MenuItem(m_performanceStats.m_name.c_str(), "", &m_performanceStats.m_show); - ImGui::MenuItem(m_featureCosts.m_name.c_str(), "", &m_featureCosts.m_show); + ImGui::MenuItem(m_performanceStats.GetName(), "", &m_performanceStats.m_show); + ImGui::MenuItem(m_featureCosts.GetName(), "", &m_featureCosts.m_show); ImGui::EndMenu(); } } @@ -78,67 +101,6 @@ namespace EMotionFX::MotionMatching { m_featureCosts.PushHistogramValue(costName, value, color); } - - void ImGuiMonitor::HistogramGroup::PushHistogramValue(const char* valueName, float value, const AZ::Color& color) - { - auto iterator = m_histogramIndexByName.find(valueName); - if (iterator != m_histogramIndexByName.end()) - { - ImGui::LYImGuiUtils::HistogramContainer& histogramContiner = m_histograms[iterator->second]; - histogramContiner.PushValue(value); - histogramContiner.SetBarLineColor(ImColor(color.GetR(), color.GetG(), color.GetB(), color.GetA())); - } - else - { - ImGui::LYImGuiUtils::HistogramContainer newHistogram; - newHistogram.Init(/*histogramName=*/valueName, - /*containerCount=*/m_histogramContainerCount, - /*viewType=*/ImGui::LYImGuiUtils::HistogramContainer::ViewType::Histogram, - /*displayOverlays=*/true, - /*min=*/0.0f, - /*max=*/0.0f); - - newHistogram.SetMoveDirection(ImGui::LYImGuiUtils::HistogramContainer::PushRightMoveLeft); - newHistogram.PushValue(value); - - m_histogramIndexByName[valueName] = m_histograms.size(); - m_histograms.push_back(newHistogram); - } - } - - void ImGuiMonitor::HistogramGroup::OnImGuiUpdate() - { - if (!m_show) - { - return; - } - - if (ImGui::CollapsingHeader(m_name.c_str(), ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed)) - { - for (auto& histogram : m_histograms) - { - ImGui::BeginGroup(); - { - histogram.Draw(ImGui::GetColumnWidth() - 70, s_histogramHeight); - - ImGui::SameLine(); - - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0,0,0,255)); - { - const ImColor color = histogram.GetBarLineColor(); - ImGui::PushStyleColor(ImGuiCol_Button, color.Value); - { - const AZStd::string valueString = AZStd::string::format("%.2f", histogram.GetLastValue()); - ImGui::Button(valueString.c_str()); - } - ImGui::PopStyleColor(); - } - ImGui::PopStyleColor(); - } - ImGui::EndGroup(); - } - } - } } // namespace EMotionFX::MotionMatching #endif // IMGUI_ENABLED diff --git a/Gems/MotionMatching/Code/Source/ImGuiMonitor.h b/Gems/MotionMatching/Code/Source/ImGuiMonitor.h index 0583d0ba41..a2af477987 100644 --- a/Gems/MotionMatching/Code/Source/ImGuiMonitor.h +++ b/Gems/MotionMatching/Code/Source/ImGuiMonitor.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include namespace EMotionFX::MotionMatching { @@ -43,41 +43,17 @@ namespace EMotionFX::MotionMatching void PushPerformanceHistogramValue(const char* performanceMetricName, float value) override; void PushCostHistogramValue(const char* costName, float value, const AZ::Color& color) override; - void SetFeatureMatrixMemoryUsage(size_t sizeInBytes) override { m_featureMatrixMemoryUsageInBytes = sizeInBytes; } - void SetFeatureMatrixNumFrames(size_t numFrames) override { m_featureMatrixNumFrames = numFrames; } - void SetFeatureMatrixNumComponents(size_t numFeatureComponents) override { m_featureMatrixNumComponents = numFeatureComponents; } - - void SetKdTreeMemoryUsage(size_t sizeInBytes) override { m_kdTreeMemoryUsageInBytes = sizeInBytes; } - void SetKdTreeNumNodes(size_t numNodes) override { m_kdTreeNumNodes = numNodes; } - void SetKdTreeNumDimensions(size_t numDimensions) override { m_kdTreeNumDimensions = numDimensions; } + void SetFrameDatabaseInfo(const ImGuiMonitorRequests::FrameDatabaseInfo& info) override { m_frameDatabaseInfo = info; } + void SetFeatureMatrixInfo(const ImGuiMonitorRequests::FeatureMatrixInfo& info) override { m_featurMatrixInfo = info; } + void SetKdTreeInfo(const ImGuiMonitorRequests::KdTreeInfo& info) override { m_kdTreeInfo = info; } private: - //! Named and sub-divided group containing several histograms. - struct HistogramGroup - { - void OnImGuiUpdate(); - void PushHistogramValue(const char* valueName, float value, const AZ::Color& color); - - bool m_show = true; - AZStd::string m_name; - using HistogramIndexByNames = AZStd::unordered_map; - HistogramIndexByNames m_histogramIndexByName; - AZStd::vector m_histograms; - int m_histogramContainerCount = 500; - - static constexpr float s_histogramHeight = 95.0f; - }; - - HistogramGroup m_performanceStats; - HistogramGroup m_featureCosts; - - size_t m_featureMatrixMemoryUsageInBytes = 0; - size_t m_featureMatrixNumFrames = 0; - size_t m_featureMatrixNumComponents = 0; + ImGui::LYImGuiUtils::HistogramGroup m_performanceStats; + ImGui::LYImGuiUtils::HistogramGroup m_featureCosts; - size_t m_kdTreeMemoryUsageInBytes = 0; - size_t m_kdTreeNumNodes = 0; - size_t m_kdTreeNumDimensions = 0; + ImGuiMonitorRequests::FrameDatabaseInfo m_frameDatabaseInfo; + ImGuiMonitorRequests::FeatureMatrixInfo m_featurMatrixInfo; + ImGuiMonitorRequests::KdTreeInfo m_kdTreeInfo; }; } // namespace EMotionFX::MotionMatching diff --git a/Gems/MotionMatching/Code/Source/ImGuiMonitorBus.h b/Gems/MotionMatching/Code/Source/ImGuiMonitorBus.h index 7c50b317c5..faadd79681 100644 --- a/Gems/MotionMatching/Code/Source/ImGuiMonitorBus.h +++ b/Gems/MotionMatching/Code/Source/ImGuiMonitorBus.h @@ -25,13 +25,30 @@ namespace EMotionFX::MotionMatching virtual void PushPerformanceHistogramValue(const char* performanceMetricName, float value) = 0; virtual void PushCostHistogramValue(const char* costName, float value, const AZ::Color& color) = 0; - virtual void SetFeatureMatrixMemoryUsage(size_t sizeInBytes) = 0; - virtual void SetFeatureMatrixNumFrames(size_t numFrames) = 0; - virtual void SetFeatureMatrixNumComponents(size_t numFeatureComponents) = 0; + struct FrameDatabaseInfo + { + size_t m_memoryUsedInBytes = 0; + size_t m_numFrames; + size_t m_numMotions; + float m_motionDataInSeconds; + }; + virtual void SetFrameDatabaseInfo(const FrameDatabaseInfo& info) = 0; - virtual void SetKdTreeMemoryUsage(size_t sizeInBytes) = 0; - virtual void SetKdTreeNumNodes(size_t numNodes) = 0; - virtual void SetKdTreeNumDimensions(size_t numDimensions) = 0; + struct FeatureMatrixInfo + { + size_t m_memoryUsedInBytes = 0; + size_t m_numFrames = 0; + size_t m_numDimensions = 0; + }; + virtual void SetFeatureMatrixInfo(const FeatureMatrixInfo& info) = 0; + + struct KdTreeInfo + { + size_t m_memoryUsedInBytes = 0; + size_t m_numNodes = 0; + size_t m_numDimensions = 0; + }; + virtual void SetKdTreeInfo(const KdTreeInfo& info) = 0; }; using ImGuiMonitorRequestBus = AZ::EBus; } // namespace EMotionFX::MotionMatching diff --git a/Gems/MotionMatching/Code/Source/MotionMatchingInstance.cpp b/Gems/MotionMatching/Code/Source/MotionMatchingInstance.cpp index 54fc2918e6..36a51f2677 100644 --- a/Gems/MotionMatching/Code/Source/MotionMatchingInstance.cpp +++ b/Gems/MotionMatching/Code/Source/MotionMatchingInstance.cpp @@ -28,14 +28,14 @@ #include #include -#include - namespace EMotionFX::MotionMatching { AZ_CLASS_ALLOCATOR_IMPL(MotionMatchingInstance, MotionMatchAllocator, 0) MotionMatchingInstance::~MotionMatchingInstance() { + DebugDrawRequestBus::Handler::BusDisconnect(); + if (m_motionInstance) { GetMotionInstancePool().Free(m_motionInstance); @@ -58,6 +58,8 @@ namespace EMotionFX::MotionMatching AZ_Assert(settings.m_actorInstance, "The actor instance cannot be a nullptr."); AZ_Assert(settings.m_data, "The motion match data cannot be nullptr."); + DebugDrawRequestBus::Handler::BusConnect(); + // Update the cached pointer to the trajectory feature. const FeatureSchema& featureSchema = settings.m_data->GetFeatureSchema(); for (Feature* feature : featureSchema.GetFeatures()) @@ -69,29 +71,6 @@ namespace EMotionFX::MotionMatching } } - // Debug display initialization. - const auto AddDebugDisplay = [=](AZ::s32 debugDisplayId) - { - if (debugDisplayId == -1) - { - return; - } - - AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; - AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, debugDisplayId); - - AzFramework::DebugDisplayRequests* debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); - if (debugDisplay) - { - m_debugDisplays.emplace_back(debugDisplay); - } - }; - // Draw the debug visualizations to the Animation Editor as well as the LY Editor viewport. - AZ::s32 animationEditorViewportId = -1; - EMStudio::ViewportPluginRequestBus::BroadcastResult(animationEditorViewportId, &EMStudio::ViewportPluginRequestBus::Events::GetViewportId); - AddDebugDisplay(animationEditorViewportId); - AddDebugDisplay(AzFramework::g_defaultSceneEntityDebugDisplayId); - m_actorInstance = settings.m_actorInstance; m_data = settings.m_data; if (settings.m_data->GetFrameDatabase().GetNumFrames() == 0) @@ -123,30 +102,17 @@ namespace EMotionFX::MotionMatching m_queryFeatureValues.resize(numValuesInKdTree); // Initialize the trajectory history. - size_t rootJointIndex = m_actorInstance->GetActor()->GetMotionExtractionNodeIndex(); - if (rootJointIndex == InvalidIndex32) + if (m_cachedTrajectoryFeature) { - rootJointIndex = 0; - } - m_trajectoryHistory.Init(*m_actorInstance->GetTransformData()->GetCurrentPose(), - rootJointIndex, - m_cachedTrajectoryFeature->GetFacingAxisDir(), - m_trajectorySecsToTrack); - } - - void MotionMatchingInstance::DebugDraw() - { - if (m_data && !m_debugDisplays.empty()) - { - for (AzFramework::DebugDisplayRequests* debugDisplay : m_debugDisplays) + size_t rootJointIndex = m_actorInstance->GetActor()->GetMotionExtractionNodeIndex(); + if (rootJointIndex == InvalidIndex32) { - if (debugDisplay) - { - const AZ::u32 prevState = debugDisplay->GetState(); - DebugDraw(*debugDisplay); - debugDisplay->SetState(prevState); - } + rootJointIndex = 0; } + m_trajectoryHistory.Init(*m_actorInstance->GetTransformData()->GetCurrentPose(), + rootJointIndex, + m_cachedTrajectoryFeature->GetFacingAxisDir(), + m_trajectorySecsToTrack); } } @@ -306,7 +272,7 @@ namespace EMotionFX::MotionMatching { AZ_PROFILE_SCOPE(Animation, "MotionMatchingInstance::Update"); - if (!m_data) + if (!m_data || !m_motionInstance) { return; } @@ -322,7 +288,7 @@ namespace EMotionFX::MotionMatching // Update the time. After this there is no sample for the updated time in the history as we're about to prepare this with the current update. m_trajectoryHistory.Update(timePassedInSeconds); - // Register the current actor instance position to the history data of the spline. + // Update the trajectory query control points. m_trajectoryQuery.Update(m_actorInstance, m_cachedTrajectoryFeature, m_trajectoryHistory, @@ -371,8 +337,7 @@ namespace EMotionFX::MotionMatching SamplePose(m_motionInstance->GetMotion(), m_queryPose, newMotionTime); // Copy over the motion extraction joint transform from the current pose to the newly sampled pose. - // When sampling a motion, the motion extraction joint is in animation space, while we need the query pose to be in - // world space. + // When sampling a motion, the motion extraction joint is in animation space, while we need the query pose to be in world space. // Note: This does not yet take the extraction delta from the current tick into account. if (m_actorInstance->GetActor()->GetMotionExtractionNode()) { @@ -433,16 +398,17 @@ namespace EMotionFX::MotionMatching // ImGui monitor { #ifdef IMGUI_ENABLED - const KdTree& kdTree = m_data->GetKdTree(); - ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetKdTreeMemoryUsage, kdTree.CalcMemoryUsageInBytes()); - ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetKdTreeNumNodes, kdTree.GetNumNodes()); - ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetKdTreeNumDimensions, kdTree.GetNumDimensions()); - // TODO: add memory usage for frame database + const FrameDatabase& frameDatabase = m_data->GetFrameDatabase(); + ImGuiMonitorRequests::FrameDatabaseInfo frameDatabaseInfo{frameDatabase.CalcMemoryUsageInBytes(), frameDatabase.GetNumFrames(), frameDatabase.GetNumUsedMotions(), frameDatabase.GetNumFrames() / (float)frameDatabase.GetSampleRate()}; + ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetFrameDatabaseInfo, frameDatabaseInfo); + const KdTree& kdTree = m_data->GetKdTree(); + ImGuiMonitorRequests::KdTreeInfo kdTreeInfo{kdTree.CalcMemoryUsageInBytes(), kdTree.GetNumNodes(), kdTree.GetNumDimensions()}; + ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetKdTreeInfo, kdTreeInfo); + const FeatureMatrix& featureMatrix = m_data->GetFeatureMatrix(); - ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetFeatureMatrixMemoryUsage, featureMatrix.CalcMemoryUsageInBytes()); - ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetFeatureMatrixNumFrames, featureMatrix.rows()); - ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetFeatureMatrixNumComponents, featureMatrix.cols()); + ImGuiMonitorRequests::FeatureMatrixInfo featureMatrixInfo{featureMatrix.CalcMemoryUsageInBytes(), static_cast(featureMatrix.rows()), static_cast(featureMatrix.cols())}; + ImGuiMonitorRequestBus::Broadcast(&ImGuiMonitorRequests::SetFeatureMatrixInfo, featureMatrixInfo); #endif } } diff --git a/Gems/MotionMatching/Code/Source/MotionMatchingInstance.h b/Gems/MotionMatching/Code/Source/MotionMatchingInstance.h index 49c781162d..0969763809 100644 --- a/Gems/MotionMatching/Code/Source/MotionMatchingInstance.h +++ b/Gems/MotionMatching/Code/Source/MotionMatchingInstance.h @@ -19,6 +19,8 @@ #include #include +#include + namespace AZ { class ReflectContext; @@ -34,12 +36,17 @@ namespace EMotionFX::MotionMatching { class MotionMatchingData; + //! The instance is where everything comes together. It stores the trajectory history, the trajectory query along with the query vector, knows about the + //! last lowest cost frame frame index and stores the time of the animation that the instance is currently playing. It is responsible for motion extraction, + //! blending towards a new frame in the motion capture database in case the algorithm found a better matching frame and executes the actual search. class EMFX_API MotionMatchingInstance + : public DebugDrawRequestBus::Handler { public: AZ_RTTI(MotionMatchingInstance, "{1ED03AD8-0FB2-431B-AF01-02F7E930EB73}") AZ_CLASS_ALLOCATOR_DECL + MotionMatchingInstance() = default; virtual ~MotionMatchingInstance(); struct EMFX_API InitSettings @@ -49,8 +56,8 @@ namespace EMotionFX::MotionMatching }; void Init(const InitSettings& settings); - void DebugDraw(); - void DebugDraw(AzFramework::DebugDisplayRequests& debugDisplay); + // DebugDrawRequestBus::Handler overrides + void DebugDraw(AzFramework::DebugDisplayRequests& debugDisplay) override; void Update(float timePassedInSeconds, const AZ::Vector3& targetPos, const AZ::Vector3& targetFacingDir, TrajectoryQuery::EMode mode, float pathRadius, float pathSpeed); void PostUpdate(float timeDelta); @@ -64,10 +71,8 @@ namespace EMotionFX::MotionMatching void SetLowestCostSearchFrequency(float frequency) { m_lowestCostSearchFrequency = frequency; } float GetNewMotionTime() const { return m_newMotionTime; } - /** - * Get the cached trajectory feature. - * The trajectory feature is searched in the feature schema used in the current instance at init time. - */ + //! Get the cached trajectory feature. + //! The trajectory feature is searched in the feature schema used in the current instance at init time. FeatureTrajectory* GetTrajectoryFeature() const { return m_cachedTrajectoryFeature; } const TrajectoryQuery& GetTrajectoryQuery() const { return m_trajectoryQuery; } const TrajectoryHistory& GetTrajectoryHistory() const { return m_trajectoryHistory; } @@ -90,10 +95,10 @@ namespace EMotionFX::MotionMatching Transform m_motionExtractionDelta = Transform::CreateIdentity(); /// Buffers used for the broad-phase KD-tree search. - AZStd::vector m_queryFeatureValues; /** The input query features to be compared to every entry/row in the feature matrix with the motion matching search. */ - AZStd::vector m_nearestFrames; /** Stores the nearest matching frames / search result from the KD-tree. */ + AZStd::vector m_queryFeatureValues; //< The input query features to be compared to every entry/row in the feature matrix with the motion matching search. + AZStd::vector m_nearestFrames; //< Stores the nearest matching frames / search result from the KD-tree. - FeatureTrajectory* m_cachedTrajectoryFeature = nullptr; /** Cached pointer to the trajectory feature in the feature schema. */ + FeatureTrajectory* m_cachedTrajectoryFeature = nullptr; //< Cached pointer to the trajectory feature in the feature schema. TrajectoryQuery m_trajectoryQuery; TrajectoryHistory m_trajectoryHistory; static constexpr float m_trajectorySecsToTrack = 5.0f; @@ -105,7 +110,7 @@ namespace EMotionFX::MotionMatching bool m_blending = false; float m_blendWeight = 1.0f; - float m_blendProgressTime = 0.0f; // How long are we already blending? In seconds. + float m_blendProgressTime = 0.0f; //< How long are we already blending? In seconds. /// Buffers used for FindLowestCostFrameIndex(). AZStd::vector m_tempCosts; diff --git a/Gems/MotionMatching/Code/Source/MotionMatchingSystemComponent.cpp b/Gems/MotionMatching/Code/Source/MotionMatchingSystemComponent.cpp index 073362d741..9091c60c0a 100644 --- a/Gems/MotionMatching/Code/Source/MotionMatchingSystemComponent.cpp +++ b/Gems/MotionMatching/Code/Source/MotionMatchingSystemComponent.cpp @@ -16,6 +16,8 @@ #include +#include + #include #include #include @@ -39,7 +41,7 @@ namespace EMotionFX::MotionMatching { ec->Class("MotionMatching", "[Description of functionality provided by this System Component]") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } @@ -69,9 +71,9 @@ namespace EMotionFX::MotionMatching incompatible.push_back(AZ_CRC_CE("MotionMatchingService")); } - void MotionMatchingSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + void MotionMatchingSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - required.push_back(AZ_CRC("EMotionFXAnimationService", 0x3f8a6369)); + required.push_back(AZ_CRC_CE("EMotionFXAnimationService")); } void MotionMatchingSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) @@ -122,7 +124,33 @@ namespace EMotionFX::MotionMatching MotionMatchingRequestBus::Handler::BusDisconnect(); } + void MotionMatchingSystemComponent::DebugDraw(AZ::s32 debugDisplayId) + { + AZ_PROFILE_SCOPE(Animation, "MotionMatchingSystemComponent::DebugDraw"); + + if (debugDisplayId == -1) + { + return; + } + + AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; + AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, debugDisplayId); + + AzFramework::DebugDisplayRequests* debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); + if (debugDisplay) + { + const AZ::u32 prevState = debugDisplay->GetState(); + EMotionFX::MotionMatching::DebugDrawRequestBus::Broadcast(&EMotionFX::MotionMatching::DebugDrawRequests::DebugDraw, *debugDisplay); + debugDisplay->SetState(prevState); + } + } + void MotionMatchingSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { + // Draw the debug visualizations to the Animation Editor as well as the LY Editor viewport. + AZ::s32 animationEditorViewportId = -1; + EMStudio::ViewportPluginRequestBus::BroadcastResult(animationEditorViewportId, &EMStudio::ViewportPluginRequestBus::Events::GetViewportId); + DebugDraw(animationEditorViewportId); + DebugDraw(AzFramework::g_defaultSceneEntityDebugDisplayId); } } // namespace EMotionFX::MotionMatching diff --git a/Gems/MotionMatching/Code/Source/MotionMatchingSystemComponent.h b/Gems/MotionMatching/Code/Source/MotionMatchingSystemComponent.h index 6a5b5a7b73..09d47b9dc3 100644 --- a/Gems/MotionMatching/Code/Source/MotionMatchingSystemComponent.h +++ b/Gems/MotionMatching/Code/Source/MotionMatchingSystemComponent.h @@ -33,8 +33,7 @@ namespace EMotionFX::MotionMatching ~MotionMatchingSystemComponent(); protected: - //////////////////////////////////////////////////////////////////////// - // MotionMatchingRequestBus interface implementation + void DebugDraw(AZ::s32 debugDisplayId); //////////////////////////////////////////////////////////////////////// // AZ::Component interface implementation @@ -45,6 +44,10 @@ namespace EMotionFX::MotionMatching //////////////////////////////////////////////////////////////////////// // AZTickBus interface implementation + int GetTickOrder() override + { + return AZ::TICK_PRE_RENDER; + } void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; //////////////////////////////////////////////////////////////////////// };