diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index c54ffc812b..9f7463e4e5 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -117,6 +117,9 @@ namespace AtomToolsFramework void StartTrackingTransform(const AZ::Transform& worldFromLocal) override; void StopTrackingTransform() override; bool IsTrackingTransform() const override; + void SetCameraPivotAttached(const AZ::Vector3& pivot) override; + void SetCameraPivotDetached(const AZ::Vector3& pivot) override; + void SetCameraOffset(const AZ::Vector3& offset) override; private: //! Combine the current camera transform with any potential roll from the tracked diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h index 4422751d6b..7dc5d0e3c9 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h @@ -29,25 +29,31 @@ namespace AtomToolsFramework static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - //! Begin a smooth transition of the camera to the requested transform. + //! Begins a smooth transition of the camera to the requested transform. //! @param worldFromLocal The transform of where the camera should end up. //! @return Returns true if the call began an interpolation and false otherwise. Calls to InterpolateToTransform //! will have no effect if an interpolation is currently in progress. virtual bool InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0; - //! Returns if the camera is currently interpolating to a new transform. virtual bool IsInterpolating() const = 0; - - //! Start tracking a transform. + //! Starts tracking a transform. //! Store the current camera transform and move to the next camera transform. virtual void StartTrackingTransform(const AZ::Transform& worldFromLocal) = 0; - - //! Stop tracking the set transform. + //! Stops tracking the set transform. //! The previously stored camera transform is restored. virtual void StopTrackingTransform() = 0; - - //! Return if the tracking transform is set. + //! Returns if the tracking transform is set. virtual bool IsTrackingTransform() const = 0; + //! Sets the current camera pivot, moving the camera offset with it (the camera appears + //! to follow the pivot, staying the same distance away from it). + virtual void SetCameraPivotAttached(const AZ::Vector3& pivot) = 0; + //! Sets the current camera pivot, leaving the camera offset in-place (the camera will + //! stay fixed and the pivot will appear to move around on its own). + virtual void SetCameraPivotDetached(const AZ::Vector3& pivot) = 0; + //! Sets the current camera offset from the pivot. + //! @note The offset value is in the current space of the camera, not world space. Setting + //! a negative Z value will move the camera backwards from the pivot. + virtual void SetCameraOffset(const AZ::Vector3& offset) = 0; protected: ~ModularViewportCameraControllerRequests() = default; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index 12e16c3dfa..2e84cde0e1 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -279,6 +279,21 @@ namespace AtomToolsFramework return false; } + void ModularViewportCameraControllerInstance::SetCameraPivotAttached(const AZ::Vector3& pivot) + { + m_targetCamera.m_pivot = pivot; + } + + void ModularViewportCameraControllerInstance::SetCameraPivotDetached(const AZ::Vector3& pivot) + { + AzFramework::MovePivotDetached(m_targetCamera, pivot); + } + + void ModularViewportCameraControllerInstance::SetCameraOffset(const AZ::Vector3& offset) + { + m_targetCamera.m_offset = offset; + } + bool ModularViewportCameraControllerInstance::IsInterpolating() const { return m_cameraMode == CameraMode::Animation; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index 43d8483a6b..ae70b5bd43 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -170,11 +170,32 @@ namespace EMStudio targetPosition.GetX() - CameraDistance, targetPosition.GetY() + CameraDistance, targetPosition.GetZ() + CameraDistance); break; } + GetViewportContext()->SetCameraTransform(AZ::Transform::CreateLookAt(cameraPosition, targetPosition)); + + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffset, + AZ::Vector3::CreateAxisY(-CameraDistance)); } void AnimViewportWidget::SetFollowCharacter(bool follow) { + if (follow) + { + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffset, + AZ::Vector3::CreateAxisY(-CameraDistance)); + } + else + { + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffset, + AZ::Vector3::CreateZero()); + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttached, + GetViewportContext()->GetCameraTransform().GetTranslation()); + } + m_followCharacter = follow; } @@ -190,7 +211,7 @@ namespace EMStudio { auto viewportContext = GetViewportContext(); auto windowSize = viewportContext->GetViewportSize(); - // Prevent devided by zero + // Prevent division by zero const float height = AZStd::max(aznumeric_cast(windowSize.m_height), 1.0f); const float aspectRatio = aznumeric_cast(windowSize.m_width) / height; @@ -216,14 +237,10 @@ namespace EMStudio { 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); + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttached, + m_renderer->GetCharacterCenter()); } - m_prevCharacterPos = m_renderer->GetCharacterCenter(); } void AnimViewportWidget::ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 336564a9e0..528cf61d09 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -64,6 +64,5 @@ namespace EMStudio AZStd::shared_ptr m_orbitDollyScrollCamera; EMotionFX::ActorRenderFlagBitset m_renderFlags; bool m_followCharacter = false; - AZ::Vector3 m_prevCharacterPos; }; }