diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp index a6dc818fc5..82ee19b6a5 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace AZ::Render { @@ -212,6 +213,13 @@ namespace AZ::Render m_auxVertices.clear(); m_auxVertices.reserve(numJoints * 2); + m_auxColors.clear(); + m_auxColors.reserve(numJoints * 2); + AZ::Color renderColor; + + const AZStd::unordered_set* cachedSelectedJointIndices; + EMotionFX::JointSelectionRequestBus::BroadcastResult( + cachedSelectedJointIndices, &EMotionFX::JointSelectionRequests::FindSelectedJointIndices, instance); for (size_t jointIndex = 0; jointIndex < numJoints; ++jointIndex) { @@ -227,18 +235,29 @@ namespace AZ::Render continue; } + if (cachedSelectedJointIndices && cachedSelectedJointIndices->find(jointIndex) != cachedSelectedJointIndices->end()) + { + renderColor = SelectedColor; + } + else + { + renderColor = skeletonColor; + } + const AZ::Vector3 parentPos = pose->GetWorldSpaceTransform(parentIndex).m_position; m_auxVertices.emplace_back(parentPos); + m_auxColors.emplace_back(renderColor); const AZ::Vector3 bonePos = pose->GetWorldSpaceTransform(jointIndex).m_position; m_auxVertices.emplace_back(bonePos); + m_auxColors.emplace_back(renderColor); } RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &skeletonColor; - lineArgs.m_colorCount = 1; + lineArgs.m_colors = m_auxColors.data(); + lineArgs.m_colorCount = lineArgs.m_vertCount; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); } @@ -251,6 +270,12 @@ namespace AZ::Render const EMotionFX::Skeleton* skeleton = instance->GetActor()->GetSkeleton(); const EMotionFX::Pose* pose = transformData->GetCurrentPose(); const size_t numEnabled = instance->GetNumEnabledNodes(); + + AZ::Color renderColor = skeletonColor; + const AZStd::unordered_set* cachedSelectedJointIndices; + EMotionFX::JointSelectionRequestBus::BroadcastResult( + cachedSelectedJointIndices, &EMotionFX::JointSelectionRequests::FindSelectedJointIndices, instance); + for (size_t i = 0; i < numEnabled; ++i) { EMotionFX::Node* joint = skeleton->GetNode(instance->GetEnabledNode(i)); @@ -273,9 +298,17 @@ namespace AZ::Render const float parentBoneScale = CalculateBoneScale(instance, skeleton->GetNode(parentIndex)); const float cylinderSize = boneLength - boneScale - parentBoneScale; + if (cachedSelectedJointIndices && cachedSelectedJointIndices->find(jointIndex) != cachedSelectedJointIndices->end()) + { + renderColor = SelectedColor; + } + else + { + renderColor = skeletonColor; + } // Render the bone cylinder, the cylinder will be directed towards the node's parent and must fit between the spheres - auxGeom->DrawCylinder(centerWorldPos, boneDirection, boneScale, cylinderSize, skeletonColor); - auxGeom->DrawSphere(nodeWorldPos, boneScale, skeletonColor); + auxGeom->DrawCylinder(centerWorldPos, boneDirection, boneScale, cylinderSize, renderColor); + auxGeom->DrawSphere(nodeWorldPos, boneScale, renderColor); } } @@ -597,6 +630,10 @@ namespace AZ::Render return; } + const AZStd::unordered_set* cachedSelectedJointIndices; + EMotionFX::JointSelectionRequestBus::BroadcastResult( + cachedSelectedJointIndices, &EMotionFX::JointSelectionRequests::FindSelectedJointIndices, actorInstance); + const EMotionFX::Actor* actor = actorInstance->GetActor(); const EMotionFX::Skeleton* skeleton = actor->GetSkeleton(); const EMotionFX::TransformData* transformData = actorInstance->GetTransformData(); @@ -607,7 +644,6 @@ namespace AZ::Render AzFramework::WindowSize viewportSize = viewportContext->GetViewportSize(); m_drawParams.m_position = AZ::Vector3(static_cast(viewportSize.m_width), 0.0f, 1.0f) + TopRightBorderPadding * viewportContext->GetDpiScalingFactor(); - m_drawParams.m_color = jointNameColor; m_drawParams.m_scale = AZ::Vector2(BaseFontSize); m_drawParams.m_hAlign = AzFramework::TextHorizontalAlignment::Right; m_drawParams.m_monospace = false; @@ -624,6 +660,14 @@ namespace AZ::Render const AZ::Vector3 worldPos = pose->GetWorldSpaceTransform(jointIndex).m_position; m_drawParams.m_position = worldPos; + if (cachedSelectedJointIndices && cachedSelectedJointIndices->find(jointIndex) != cachedSelectedJointIndices->end()) + { + m_drawParams.m_color = SelectedColor; + } + else + { + m_drawParams.m_color = jointNameColor; + } m_fontDrawInterface->DrawScreenAlignedText3d(m_drawParams, joint->GetName()); } } @@ -640,6 +684,10 @@ namespace AZ::Render const EMotionFX::Pose* pose = transformData->GetCurrentPose(); const float constPreScale = scale * unitScale * 3.0f; + const AZStd::unordered_set* cachedSelectedJointIndices; + EMotionFX::JointSelectionRequestBus::BroadcastResult( + cachedSelectedJointIndices, &EMotionFX::JointSelectionRequests::FindSelectedJointIndices, actorInstance); + const size_t numEnabled = actorInstance->GetNumEnabledNodes(); for (size_t i = 0; i < numEnabled; ++i) { @@ -649,7 +697,12 @@ namespace AZ::Render static const float axisBoneScale = 50.0f; const float size = CalculateBoneScale(actorInstance, joint) * constPreScale * axisBoneScale; AZ::Transform worldTM = pose->GetWorldSpaceTransform(jointIndex).ToAZTransform(); - RenderLineAxis(debugDisplay, worldTM, size, false /*selected*/); + bool selected = false; + if (cachedSelectedJointIndices && cachedSelectedJointIndices->find(jointIndex) != cachedSelectedJointIndices->end()) + { + selected = true; + } + RenderLineAxis(debugDisplay, worldTM, size, selected); } } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h index d3a6bc44f3..3c0258cfef 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h @@ -84,6 +84,7 @@ namespace AZ::Render static constexpr float BaseFontSize = 0.7f; const Vector3 TopRightBorderPadding = AZ::Vector3(-40.0f, 22.0f, 0.0f); + const AZ::Color SelectedColor = AZ::Color{ 1.0f, 0.67f, 0.0f, 1.0f }; RPI::AuxGeomFeatureProcessorInterface* m_auxGeomFeatureProcessor = nullptr; AZStd::vector m_auxVertices; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/JointSelectionBus.h b/Gems/EMotionFX/Code/EMotionFX/Source/JointSelectionBus.h new file mode 100644 index 0000000000..634456c82f --- /dev/null +++ b/Gems/EMotionFX/Code/EMotionFX/Source/JointSelectionBus.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace EMotionFX +{ + class JointSelectionRequests + : public AZ::EBusTraits + { + public: + virtual const AZStd::unordered_set* FindSelectedJointIndices(EMotionFX::ActorInstance* instance) const = 0; + }; + using JointSelectionRequestBus = AZ::EBus; +} diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp index b385de62be..6881e49429 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp @@ -97,6 +97,7 @@ namespace EMStudio m_compileDate = AZStd::string::format("%s", MCORE_DATE); EMotionFX::SkeletonOutlinerNotificationBus::Handler::BusConnect(); + EMotionFX::JointSelectionRequestBus::Handler::BusConnect(); // log some information LogInfo(); @@ -107,6 +108,7 @@ namespace EMStudio // destructor EMStudioManager::~EMStudioManager() { + EMotionFX::JointSelectionRequestBus::Handler::BusDisconnect(); EMotionFX::SkeletonOutlinerNotificationBus::Handler::BusDisconnect(); if (m_eventProcessingCallback) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h index 4c3139b77a..1d60773e1f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h @@ -19,6 +19,8 @@ // include the gizmos #include +#include + // include the EMStudio Config #include "EMStudioConfig.h" #include @@ -52,6 +54,7 @@ namespace EMStudio */ class EMSTUDIO_API EMStudioManager : private EMotionFX::SkeletonOutlinerNotificationBus::Handler + , private EMotionFX::JointSelectionRequestBus::Handler { public: AZ_RTTI(EMStudio::EMStudioManager, "{D45E95CF-0C7B-44F1-A9D4-99A1E12A5AB5}") @@ -103,6 +106,15 @@ namespace EMStudio void SetSelectedJointIndices(const AZStd::unordered_set& selectedJointIndices); const AZStd::unordered_set& GetSelectedJointIndices() const { return m_selectedJointIndices; } + const AZStd::unordered_set* FindSelectedJointIndices(EMotionFX::ActorInstance* instance) const + { + if (instance == m_commandManager->GetCurrentSelection().GetSingleActorInstance()) + { + return &m_selectedJointIndices; + } + return nullptr; + } + Workspace* GetWorkspace() { return &m_workspace; } // functions for adding/removing gizmos diff --git a/Gems/EMotionFX/Code/EMotionFX/emotionfx_files.cmake b/Gems/EMotionFX/Code/EMotionFX/emotionfx_files.cmake index 9947850471..f0443ade44 100644 --- a/Gems/EMotionFX/Code/EMotionFX/emotionfx_files.cmake +++ b/Gems/EMotionFX/Code/EMotionFX/emotionfx_files.cmake @@ -42,6 +42,7 @@ set(FILES Source/EMotionFXManager.h Source/EMotionFXAllocatorInitializer.cpp Source/EMotionFXAllocatorInitializer.h + Source/JointSelectionBus.h Source/KeyFrame.h Source/KeyFrame.inl Source/KeyFrameFinder.h