From 6ffc2620e4f1a464cd429d6388034879c30a3acd Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Mon, 21 Feb 2022 09:44:21 +0000 Subject: [PATCH] Updates to EMFX cameras and better support for character follow behavior (#7676) * initial wip change to help resolve EMFX camera viewport issue Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * some updates to add/remove camera input API Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add additional comments and remove some optimize off calls Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * improvements to camera behavior in EMFX editor Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add some tests for add/remove logic for cameras Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> --- .../EditorModularViewportCameraComposer.cpp | 14 ++-- .../EditorModularViewportCameraComposer.h | 4 +- .../AzFramework/Viewport/CameraInput.cpp | 76 +++++++++++++++-- .../AzFramework/Viewport/CameraInput.h | 27 ++++-- .../AzFramework/Tests/CameraInputTests.cpp | 36 ++++++++ .../ModularViewportCameraController.h | 3 + ...odularViewportCameraControllerRequestBus.h | 10 +++ .../ModularViewportCameraController.cpp | 11 +++ .../Tools/EMStudio/AnimViewportSettings.cpp | 17 +++- .../Tools/EMStudio/AnimViewportSettings.h | 8 +- .../Tools/EMStudio/AnimViewportWidget.cpp | 82 +++++++++++++------ .../Code/Tools/EMStudio/AnimViewportWidget.h | 18 +++- 12 files changed, 248 insertions(+), 58 deletions(-) diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp index 3f66468584..062f016d8f 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.cpp +++ b/Code/Editor/EditorModularViewportCameraComposer.cpp @@ -287,16 +287,16 @@ namespace SandboxEditor return SandboxEditor::CameraBoostMultiplier(); }; - m_orbitDollyScrollCamera = AZStd::make_shared(); + m_orbitScrollDollyCamera = AZStd::make_shared(); - m_orbitDollyScrollCamera->m_scrollSpeedFn = [] + m_orbitScrollDollyCamera->m_scrollSpeedFn = [] { return SandboxEditor::CameraScrollSpeed(); }; - m_orbitDollyMoveCamera = AZStd::make_shared(SandboxEditor::CameraOrbitDollyChannelId()); + m_orbitMotionDollyCamera = AZStd::make_shared(SandboxEditor::CameraOrbitDollyChannelId()); - m_orbitDollyMoveCamera->m_motionSpeedFn = [] + m_orbitMotionDollyCamera->m_motionSpeedFn = [] { return SandboxEditor::CameraDollyMotionSpeed(); }; @@ -326,8 +326,8 @@ namespace SandboxEditor m_orbitCamera->m_orbitCameras.AddCamera(m_orbitRotateCamera); m_orbitCamera->m_orbitCameras.AddCamera(m_orbitTranslateCamera); - m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyScrollCamera); - m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyMoveCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitScrollDollyCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitMotionDollyCamera); m_orbitCamera->m_orbitCameras.AddCamera(m_orbitPanCamera); m_orbitCamera->m_orbitCameras.AddCamera(m_orbitFocusCamera); } @@ -344,7 +344,7 @@ namespace SandboxEditor m_orbitTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds); m_orbitPanCamera->SetPanInputChannelId(SandboxEditor::CameraOrbitPanChannelId()); m_orbitRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraOrbitLookChannelId()); - m_orbitDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId()); + m_orbitMotionDollyCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId()); m_orbitFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId()); } diff --git a/Code/Editor/EditorModularViewportCameraComposer.h b/Code/Editor/EditorModularViewportCameraComposer.h index 6cd5df533c..a4ab106347 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.h +++ b/Code/Editor/EditorModularViewportCameraComposer.h @@ -56,8 +56,8 @@ namespace SandboxEditor AZStd::shared_ptr m_orbitCamera; AZStd::shared_ptr m_orbitRotateCamera; AZStd::shared_ptr m_orbitTranslateCamera; - AZStd::shared_ptr m_orbitDollyScrollCamera; - AZStd::shared_ptr m_orbitDollyMoveCamera; + AZStd::shared_ptr m_orbitScrollDollyCamera; + AZStd::shared_ptr m_orbitMotionDollyCamera; AZStd::shared_ptr m_orbitPanCamera; AZStd::shared_ptr m_orbitFocusCamera; diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index cd33f60b91..b80d82a7b9 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -190,9 +190,67 @@ namespace AzFramework return nextCamera; } - void Cameras::AddCamera(AZStd::shared_ptr cameraInput) + bool Cameras::AddCamera(AZStd::shared_ptr cameraInput) { - m_idleCameraInputs.push_back(AZStd::move(cameraInput)); + const auto idleCameraIt = AZStd::find(m_idleCameraInputs.begin(), m_idleCameraInputs.end(), cameraInput); + const auto activeCameraIt = AZStd::find(m_activeCameraInputs.begin(), m_activeCameraInputs.end(), cameraInput); + + if (idleCameraIt == m_idleCameraInputs.end() && activeCameraIt == m_activeCameraInputs.end()) + { + m_idleCameraInputs.push_back(AZStd::move(cameraInput)); + return true; + } + + return false; + } + + bool Cameras::AddCameras(const AZStd::vector>& cameraInputs) + { + bool allAdded = true; + for (auto cameraInput : cameraInputs) + { + allAdded = AddCamera(AZStd::move(cameraInput)) && allAdded; + } + return allAdded; + } + + bool Cameras::RemoveCamera(const AZStd::shared_ptr& cameraInput) + { + if (const auto idleCameraIt = AZStd::find(m_idleCameraInputs.begin(), m_idleCameraInputs.end(), cameraInput); + idleCameraIt != m_idleCameraInputs.end()) + { + const auto idleIndex = idleCameraIt - m_idleCameraInputs.begin(); + using AZStd::swap; + swap(m_idleCameraInputs[idleIndex], m_idleCameraInputs[m_idleCameraInputs.size() - 1]); + m_idleCameraInputs.pop_back(); + + return true; + } + + if (const auto activeCameraIt = AZStd::find(m_activeCameraInputs.begin(), m_activeCameraInputs.end(), cameraInput); + activeCameraIt != m_activeCameraInputs.end()) + { + (*activeCameraIt)->Reset(); + + const auto activeIndex = activeCameraIt - m_idleCameraInputs.begin(); + using AZStd::swap; + swap(m_activeCameraInputs[activeIndex], m_activeCameraInputs[m_activeCameraInputs.size() - 1]); + m_activeCameraInputs.pop_back(); + + return true; + } + + return false; + } + + bool Cameras::RemoveCameras(const AZStd::vector>& cameraInputs) + { + bool allRemoved = true; + for (const auto& cameraInput : cameraInputs) + { + allRemoved = RemoveCamera(cameraInput) && allRemoved; + } + return allRemoved; } bool Cameras::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta) @@ -645,7 +703,7 @@ namespace AzFramework m_orbitChannelId = orbitChanneId; } - OrbitDollyScrollCameraInput::OrbitDollyScrollCameraInput() + OrbitScrollDollyCameraInput::OrbitScrollDollyCameraInput() { m_scrollSpeedFn = []() constexpr { @@ -653,7 +711,7 @@ namespace AzFramework }; } - bool OrbitDollyScrollCameraInput::HandleEvents( + bool OrbitScrollDollyCameraInput::HandleEvents( const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta) { if (const auto* scroll = AZStd::get_if(&event)) @@ -691,7 +749,7 @@ namespace AzFramework return nextCamera; } - Camera OrbitDollyScrollCameraInput::StepCamera( + Camera OrbitScrollDollyCameraInput::StepCamera( const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta, @@ -702,7 +760,7 @@ namespace AzFramework return nextCamera; } - OrbitDollyMotionCameraInput::OrbitDollyMotionCameraInput(const InputChannelId& dollyChannelId) + OrbitMotionDollyCameraInput::OrbitMotionDollyCameraInput(const InputChannelId& dollyChannelId) : m_dollyChannelId(dollyChannelId) { m_motionSpeedFn = []() constexpr @@ -711,14 +769,14 @@ namespace AzFramework }; } - bool OrbitDollyMotionCameraInput::HandleEvents( + bool OrbitMotionDollyCameraInput::HandleEvents( const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta) { HandleActivationEvents(event, m_dollyChannelId, cursorDelta, m_clickDetector, *this); return CameraInputUpdatingAfterMotion(*this); } - Camera OrbitDollyMotionCameraInput::StepCamera( + Camera OrbitMotionDollyCameraInput::StepCamera( const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta, @@ -727,7 +785,7 @@ namespace AzFramework return OrbitDolly(targetCamera, aznumeric_cast(cursorDelta.m_y) * m_motionSpeedFn()); } - void OrbitDollyMotionCameraInput::SetDollyInputChannelId(const InputChannelId& dollyChannelId) + void OrbitMotionDollyCameraInput::SetDollyInputChannelId(const InputChannelId& dollyChannelId) { m_dollyChannelId = dollyChannelId; } diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h index b652d616b2..28335f5c49 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h @@ -289,7 +289,17 @@ namespace AzFramework //! Add a camera input (behavior) to run in this set of camera inputs. //! The camera inputs added here will determine the overall behavior of the camera. - void AddCamera(AZStd::shared_ptr cameraInput); + //! @return Returns if the camera was successfully added (if the camera already exists it is not added and AddCamera returns false). + bool AddCamera(AZStd::shared_ptr cameraInput); + //! Add a collection of camera inputs (behaviors) to run in this set of camera inputs. + //! @return Returns if all cameras were added successfully. + bool AddCameras(const AZStd::vector>& cameraInputs); + //! Remove a camera input (behavior) to stop it running in the set of camera inputs. + //! @return Returns if the camera was removed successfully (if the could not be found RemoveCamera returns false). + bool RemoveCamera(const AZStd::shared_ptr& cameraInput); + //! Remove a collection of camera inputs (behaviors) to stop them running in the set of camera inputs. + //! @return Returns if all cameras were removed successfully. + bool RemoveCameras(const AZStd::vector>& cameraInputs); //! Reset the state of all cameras. void Reset(); //! Remove all cameras that were added. @@ -299,9 +309,10 @@ namespace AzFramework bool Exclusive() const; private: - AZStd::vector> m_activeCameraInputs; //!< Active camera inputs updating the camera (empty initially). - AZStd::vector> - m_idleCameraInputs; //!< Idle camera inputs not contributing to the update (filled initially). + //! Active camera inputs updating the camera (empty initially). + AZStd::vector> m_activeCameraInputs; + //! Idle camera inputs not contributing to the update (filled initially). + AZStd::vector> m_idleCameraInputs; }; //! Responsible for updating a series of cameras given various inputs. @@ -586,10 +597,10 @@ namespace AzFramework }; //! A camera input to handle discrete scroll events that can modify the camera offset. - class OrbitDollyScrollCameraInput : public CameraInput + class OrbitScrollDollyCameraInput : public CameraInput { public: - OrbitDollyScrollCameraInput(); + OrbitScrollDollyCameraInput(); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; @@ -599,10 +610,10 @@ namespace AzFramework }; //! A camera input to handle motion deltas that can modify the camera offset. - class OrbitDollyMotionCameraInput : public CameraInput + class OrbitMotionDollyCameraInput : public CameraInput { public: - explicit OrbitDollyMotionCameraInput(const InputChannelId& dollyChannelId); + explicit OrbitMotionDollyCameraInput(const InputChannelId& dollyChannelId); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; diff --git a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp index 0ddf9e89b9..cf4e4de1e0 100644 --- a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp +++ b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp @@ -490,4 +490,40 @@ namespace UnitTest EXPECT_THAT(m_orbitCamera->Ending(), IsFalse()); EXPECT_THAT(m_orbitCamera->Idle(), IsTrue()); } + + TEST_F(CameraInputFixture, NewCameraInputCanBeAddedToCameraSystem) + { + auto firstPersonPanCamera = AZStd::make_shared( + AzFramework::InputDeviceMouse::Button::Middle, AzFramework::LookPan, AzFramework::TranslatePivotLook); + const bool added = + m_cameraSystem->m_cameras.AddCameras(AZStd::vector>{ firstPersonPanCamera }); + + EXPECT_THAT(added, ::testing::IsTrue()); + } + + TEST_F(CameraInputFixture, ExistingCameraInputCannotBeAddedToCameraSystem) + { + const bool added = + m_cameraSystem->m_cameras.AddCameras(AZStd::vector>{ m_firstPersonRotateCamera }); + + EXPECT_THAT(added, ::testing::IsFalse()); + } + + TEST_F(CameraInputFixture, ExistingCameraInputCanBeRemovedFromCameraSystem) + { + const bool removed = m_cameraSystem->m_cameras.RemoveCameras( + AZStd::vector>{ m_firstPersonRotateCamera }); + + EXPECT_THAT(removed, ::testing::IsTrue()); + } + + TEST_F(CameraInputFixture, NonExistentCameraInputCannotBeRemovedFromCameraSystem) + { + auto firstPersonPanCamera = AZStd::make_shared( + AzFramework::InputDeviceMouse::Button::Middle, AzFramework::LookPan, AzFramework::TranslatePivotLook); + const bool removed = m_cameraSystem->m_cameras.RemoveCameras( + AZStd::vector>{ firstPersonPanCamera }); + + EXPECT_THAT(removed, ::testing::IsFalse()); + } } // namespace UnitTest 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 9f7463e4e5..1995aefabe 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -120,6 +121,8 @@ namespace AtomToolsFramework void SetCameraPivotAttached(const AZ::Vector3& pivot) override; void SetCameraPivotDetached(const AZ::Vector3& pivot) override; void SetCameraOffset(const AZ::Vector3& offset) override; + bool AddCameras(const AZStd::vector>& cameraInputs) override; + bool RemoveCameras(const AZStd::vector>& cameraInputs) 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 7dc5d0e3c9..86f62c1657 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include namespace AZ @@ -16,6 +17,11 @@ namespace AZ class Transform; } +namespace AzFramework +{ + class CameraInput; +} + namespace AtomToolsFramework { //! Provides an interface to control the modern viewport camera controller from the Editor. @@ -54,6 +60,10 @@ namespace AtomToolsFramework //! @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; + //! Add one or more camera inputs (behaviors) to run for the current camera. + virtual bool AddCameras(const AZStd::vector>& cameraInputs) = 0; + //! Remove one or more camera inputs (behaviors) to stop them running for the current camera. + virtual bool RemoveCameras(const AZStd::vector>& cameraInputs) = 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 2e84cde0e1..fbb61a80b8 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -294,6 +294,17 @@ namespace AtomToolsFramework m_targetCamera.m_offset = offset; } + bool ModularViewportCameraControllerInstance::AddCameras(const AZStd::vector>& cameraInputs) + { + return m_cameraSystem.m_cameras.AddCameras(cameraInputs); + } + + bool ModularViewportCameraControllerInstance::RemoveCameras( + const AZStd::vector>& cameraInputs) + { + return m_cameraSystem.m_cameras.RemoveCameras(cameraInputs); + } + bool ModularViewportCameraControllerInstance::IsInterpolating() const { return m_cameraMode == CameraMode::Animation; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp index 78dbcd6230..18d912d64e 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp @@ -24,6 +24,8 @@ namespace EMStudio::ViewportUtil constexpr AZStd::string_view CameraTranslateBoostIdSetting = "/Amazon/Preferences/Editor/Camera/TranslateBoostId"; constexpr AZStd::string_view CameraOrbitIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitId"; constexpr AZStd::string_view CameraDefaultOrbitDistanceSetting = "/Amazon/Preferences/Editor/Camera/DefaultOrbitDistance"; + constexpr AZStd::string_view CameraOrbitDollyIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitDollyId"; + constexpr AZStd::string_view CameraFreePanIdSetting = "/Amazon/Preferences/Editor/Camera/FreePanId"; AzFramework::TranslateCameraInputChannelIds TranslateCameraInputChannelIds() { @@ -78,12 +80,21 @@ namespace EMStudio::ViewportUtil AzFramework::InputChannelId OrbitCameraInputChannelId() { - return AzFramework::InputChannelId( - GetRegistry(CameraOrbitIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraOrbitIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str()); } AzFramework::InputChannelId OrbitLookCameraInputChannelId() { return AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str()); } -} + + AzFramework::InputChannelId OrbitDollyCameraInputChannelId() + { + return AzFramework::InputChannelId(GetRegistry(CameraOrbitDollyIdSetting, AZStd::string("mouse_button_right")).c_str()); + } + + AzFramework::InputChannelId PanCameraInputChannelId() + { + return AzFramework::InputChannelId(GetRegistry(CameraFreePanIdSetting, AZStd::string("mouse_button_middle")).c_str()); + } +} // namespace EMStudio::ViewportUtil diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.h index 4fca274866..d5002bbc27 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.h @@ -5,9 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once -#include + #include +#include namespace EMStudio::ViewportUtil { @@ -37,4 +39,6 @@ namespace EMStudio::ViewportUtil AzFramework::InputChannelId RotateCameraInputChannelId(); AzFramework::InputChannelId OrbitCameraInputChannelId(); AzFramework::InputChannelId OrbitLookCameraInputChannelId(); -} + AzFramework::InputChannelId OrbitDollyCameraInputChannelId(); + AzFramework::InputChannelId PanCameraInputChannelId(); +} // namespace EMStudio::ViewportUtil diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index c240ba09d8..b8c2b0f0e4 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -6,17 +6,17 @@ * */ -#include -#include -#include -#include #include +#include #include +#include +#include +#include #include -#include #include #include +#include #include namespace EMStudio @@ -64,31 +64,44 @@ namespace EMStudio void AnimViewportWidget::SetupCameras() { - m_rotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::RotateCameraInputChannelId()); - const auto translateCameraInputChannelIds = EMStudio::ViewportUtil::TranslateCameraInputChannelIds(); - m_translateCamera = AZStd::make_shared( + + m_lookRotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::RotateCameraInputChannelId()); + m_lookTranslateCamera = AZStd::make_shared( translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook); - m_translateCamera.get()->m_translateSpeedFn = [] + m_lookTranslateCamera->m_translateSpeedFn = [] { return 3.0f; }; - m_lookScrollCamera = AZStd::make_shared(); + m_lookScrollTranslationCamera = AZStd::make_shared(); + m_lookPanCamera = AZStd::make_shared( + EMStudio::ViewportUtil::PanCameraInputChannelId(), AzFramework::LookPan, AzFramework::TranslatePivotLook); m_orbitCamera = AZStd::make_shared(EMStudio::ViewportUtil::OrbitCameraInputChannelId()); m_orbitCamera->SetPivotFn( - [this](const AZ::Vector3& position, const AZ::Vector3& direction) + [this]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { - if (m_orbitCamera->Beginning()) - { - m_defaultOrbitPoint = position + direction * EMStudio::ViewportUtil::CameraDefaultOrbitDistance(); - } - return m_defaultOrbitPoint; + return m_renderer->GetCharacterCenter(); }); + + m_orbitTranslateCamera = AZStd::make_shared( + translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook); m_orbitRotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::OrbitLookCameraInputChannelId()); - m_orbitDollyScrollCamera = AZStd::make_shared(); + m_orbitScrollDollyCamera = AZStd::make_shared(); + m_orbitPanCamera = AZStd::make_shared( + EMStudio::ViewportUtil::PanCameraInputChannelId(), AzFramework::LookPan, AzFramework::TranslateOffsetOrbit); + m_orbitMotionDollyCamera = + AZStd::make_shared(EMStudio::ViewportUtil::OrbitDollyCameraInputChannelId()); m_orbitCamera->m_orbitCameras.AddCamera(m_orbitRotateCamera); - m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyScrollCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitScrollDollyCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitTranslateCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitMotionDollyCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitPanCamera); + + m_followRotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::OrbitLookCameraInputChannelId()); + m_followScrollDollyCamera = AZStd::make_shared(); + m_followScrollMotionCamera = + AZStd::make_shared(EMStudio::ViewportUtil::OrbitDollyCameraInputChannelId()); } void AnimViewportWidget::SetupCameraController() @@ -134,11 +147,13 @@ namespace EMStudio controller->SetCameraListBuilderCallback( [this](AzFramework::Cameras& cameras) { - cameras.AddCamera(m_rotateCamera); - cameras.AddCamera(m_translateCamera); - cameras.AddCamera(m_lookScrollCamera); + cameras.AddCamera(m_lookRotateCamera); + cameras.AddCamera(m_lookTranslateCamera); + cameras.AddCamera(m_lookScrollTranslationCamera); + cameras.AddCamera(m_lookPanCamera); cameras.AddCamera(m_orbitCamera); }); + GetControllerList()->Add(controller); } @@ -183,14 +198,34 @@ namespace EMStudio void AnimViewportWidget::UpdateCameraFollowUp(bool followUp) { + const auto lookAndOrbitCameras = + AZStd::vector>{ m_lookRotateCamera, m_lookTranslateCamera, + m_lookScrollTranslationCamera, m_lookPanCamera, m_orbitCamera }; + + const auto followCameras = + AZStd::vector>{ m_followRotateCamera, m_followScrollDollyCamera, + m_followScrollMotionCamera }; if (followUp) { + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::RemoveCameras, + lookAndOrbitCameras); + + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::AddCameras, followCameras); + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffset, AZ::Vector3::CreateAxisY(-CameraDistance)); } else { + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::RemoveCameras, followCameras); + + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::AddCameras, lookAndOrbitCameras); + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffset, AZ::Vector3::CreateZero()); @@ -219,8 +254,9 @@ namespace EMStudio const RenderOptions* renderOptions = m_plugin->GetRenderOptions(); AZ::Matrix4x4 viewToClipMatrix; - AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::DegToRad(renderOptions->GetFOV()), aspectRatio, - renderOptions->GetNearClipPlaneDistance(), renderOptions->GetFarClipPlaneDistance(), true); + AZ::MakePerspectiveFovMatrixRH( + viewToClipMatrix, AZ::DegToRad(renderOptions->GetFOV()), aspectRatio, renderOptions->GetNearClipPlaneDistance(), + renderOptions->GetFarClipPlaneDistance(), true); viewportContext->GetDefaultView()->SetViewToClipMatrix(viewToClipMatrix); } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index b66e002c68..e8e3c85545 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -55,12 +55,22 @@ namespace EMStudio AtomRenderPlugin* m_plugin; AZStd::unique_ptr m_renderer; - AZStd::shared_ptr m_rotateCamera; - AZStd::shared_ptr m_translateCamera; - AZStd::shared_ptr m_lookScrollCamera; - AZStd::shared_ptr m_orbitDollyScrollCamera; + AZStd::shared_ptr m_lookRotateCamera; + AZStd::shared_ptr m_lookTranslateCamera; + AZStd::shared_ptr m_lookScrollTranslationCamera; + AZStd::shared_ptr m_lookPanCamera; + AZStd::shared_ptr m_orbitCamera; + AZStd::shared_ptr m_orbitScrollDollyCamera; AZStd::shared_ptr m_orbitRotateCamera; + AZStd::shared_ptr m_orbitTranslateCamera; + AZStd::shared_ptr m_orbitMotionDollyCamera; + AZStd::shared_ptr m_orbitPanCamera; + + AZStd::shared_ptr m_followRotateCamera; + AZStd::shared_ptr m_followScrollDollyCamera; + AZStd::shared_ptr m_followScrollMotionCamera; + AZ::Vector3 m_defaultOrbitPoint = AZ::Vector3::CreateZero(); }; }