diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index a32af31d6d..396042c9f6 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -178,20 +178,13 @@ namespace EMStudio if (!m_actorEntities.empty()) { // Find the actor instance and calculate the center from aabb. - AZ::Vector3 actorCenter = AZ::Vector3::CreateZero(); EMotionFX::Integration::ActorComponent* actorComponent = m_actorEntities[0]->FindComponent(); EMotionFX::ActorInstance* actorInstance = actorComponent->GetActorInstance(); if (actorInstance) { - actorCenter += actorInstance->GetAabb().GetCenter(); + result = actorInstance->GetAabb().GetCenter(); } - - // Just return the position of the first entity. - AZ::Transform worldTransform; - AZ::TransformBus::EventResult(worldTransform, m_actorEntities[0]->GetId(), &AZ::TransformBus::Events::GetWorldTM); - result = worldTransform.GetTranslation(); - result += actorCenter; } return result; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h index da4a054c53..9a0bee1fec 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h @@ -36,6 +36,9 @@ namespace EMStudio //! Set the camera view mode. virtual void SetCameraViewMode(CameraViewMode mode) = 0; + //! Set the camera follow up + virtual void SetFollowCharacter(bool follow) = 0; + //! Toggle render option flag virtual void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) = 0; }; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp index 3b53103537..b95e82a090 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp @@ -87,6 +87,19 @@ namespace EMStudio // Send the reset camera event. AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::ResetCamera); }); + + cameraMenu->addSeparator(); + m_followCharacterAction = cameraMenu->addAction("Follow Character"); + m_followCharacterAction->setCheckable(true); + m_followCharacterAction->setChecked(false); + connect(m_followCharacterAction, &QAction::triggered, this, + [this]() + { + AnimViewportRequestBus::Broadcast( + &AnimViewportRequestBus::Events::SetFollowCharacter, m_followCharacterAction->isChecked()); + ; + }); + cameraButton->setMenu(cameraMenu); cameraButton->setText("Camera Option"); cameraButton->setPopupMode(QToolButton::InstantPopup); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h index 57633e5284..1443c54ee9 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h @@ -31,5 +31,6 @@ namespace EMStudio QMenu* menu, const char* menuEntryName, uint32_t actionIndex, bool visible = true, char* iconFileName = nullptr); QAction* m_actions[EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS] = { nullptr }; + QAction* m_followCharacterAction = nullptr; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index cd362bdaf5..86529d16ec 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -147,36 +147,43 @@ namespace EMStudio switch (mode) { case CameraViewMode::FRONT: - cameraPosition.Set(0.0f, CameraDistance, targetPosition.GetZ()); + cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY() + CameraDistance, targetPosition.GetZ()); break; case CameraViewMode::BACK: - cameraPosition.Set(0.0f, -CameraDistance, targetPosition.GetZ()); + cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY() - CameraDistance, targetPosition.GetZ()); break; case CameraViewMode::TOP: - cameraPosition.Set(0.0f, 0.0f, CameraDistance + targetPosition.GetZ()); + cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY(), CameraDistance + targetPosition.GetZ()); break; case CameraViewMode::BOTTOM: - cameraPosition.Set(0.0f, 0.0f, -CameraDistance + targetPosition.GetZ()); + cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY(), -CameraDistance + targetPosition.GetZ()); break; case CameraViewMode::LEFT: - cameraPosition.Set(-CameraDistance, 0.0f, targetPosition.GetZ()); + cameraPosition.Set(targetPosition.GetX() - CameraDistance, targetPosition.GetY(), targetPosition.GetZ()); break; case CameraViewMode::RIGHT: - cameraPosition.Set(CameraDistance, 0.0f, targetPosition.GetZ()); + cameraPosition.Set(targetPosition.GetX() + CameraDistance, targetPosition.GetY(), targetPosition.GetZ()); break; case CameraViewMode::DEFAULT: // The default view mode is looking from the top left of the character. - cameraPosition.Set(-CameraDistance, CameraDistance, CameraDistance + targetPosition.GetZ()); + cameraPosition.Set( + targetPosition.GetX() - CameraDistance, targetPosition.GetY() + CameraDistance, targetPosition.GetZ() + CameraDistance); break; } GetViewportContext()->SetCameraTransform(AZ::Transform::CreateLookAt(cameraPosition, targetPosition)); } + void AnimViewportWidget::SetFollowCharacter(bool follow) + { + m_followCharacter = follow; + } + void AnimViewportWidget::OnTick(float deltaTime, AZ::ScriptTimePoint time) { RenderViewportWidget::OnTick(deltaTime, time); CalculateCameraProjection(); RenderCustomPluginData(); + FollowCharacter(); } void AnimViewportWidget::CalculateCameraProjection() @@ -205,6 +212,20 @@ namespace EMStudio } } + void AnimViewportWidget::FollowCharacter() + { + if (m_followCharacter) + { + // When follow charater move is enabled, we are adding the delta of the character movement to the camera per frame. + AZ::Vector3 camPos = GetViewportContext()->GetCameraTransform().GetTranslation(); + camPos += m_renderer->GetCharacterCenter() - m_prevCharacterPos; + AZ::Transform newCamTransform = GetViewportContext()->GetCameraTransform(); + newCamTransform.SetTranslation(camPos); + GetViewportContext()->SetCameraTransform(newCamTransform); + } + m_prevCharacterPos = m_renderer->GetCharacterCenter(); + } + void AnimViewportWidget::ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) { m_renderFlags[flag] = !m_renderFlags[flag]; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 069aebb73e..336564a9e0 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -38,6 +38,7 @@ namespace EMStudio void CalculateCameraProjection(); void RenderCustomPluginData(); + void FollowCharacter(); void SetupCameras(); void SetupCameraController(); @@ -48,6 +49,7 @@ namespace EMStudio // AnimViewportRequestBus::Handler overrides void ResetCamera(); void SetCameraViewMode(CameraViewMode mode); + void SetFollowCharacter(bool follow); void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag); // ViewportPluginRequestBus::Handler overrides @@ -61,5 +63,7 @@ namespace EMStudio AZStd::shared_ptr m_translateCamera; AZStd::shared_ptr m_orbitDollyScrollCamera; EMotionFX::ActorRenderFlagBitset m_renderFlags; + bool m_followCharacter = false; + AZ::Vector3 m_prevCharacterPos; }; }