diff --git a/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraComponent.cpp b/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraComponent.cpp index 5f110ab85..bd38d5585 100644 --- a/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraComponent.cpp +++ b/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraComponent.cpp @@ -24,23 +24,23 @@ namespace ROS2 { AzFramework::InputDeviceKeyboard::Key::Alphanumeric9, 8 }, { AzFramework::InputDeviceKeyboard::Key::Alphanumeric0, 9 } }; + FollowingCameraComponent::FollowingCameraComponent(const FollowingCameraConfiguration& configuration) + : m_configuration(configuration) + { + } + void FollowingCameraComponent::Reflect(AZ::ReflectContext* reflection) { + FollowingCameraConfiguration::Reflect(reflection); AZ::SerializeContext* serializeContext = azrtti_cast(reflection); if (serializeContext) { - serializeContext->Class() - ->Version(1) - ->Field("PredefinedViews", &FollowingCameraComponent::m_predefinedViews) - ->Field("SmoothingLength", &FollowingCameraComponent::m_smoothingBuffer) - ->Field("ZoomSpeed", &FollowingCameraComponent::m_zoomSpeed) - ->Field("RotationSpeed", &FollowingCameraComponent::m_rotationSpeed) - ->Field("DefaultView", &FollowingCameraComponent::m_defaultView); - + serializeContext->Class()->Version(1)->Field( + "FollowingCameraConfiguration", &FollowingCameraComponent::m_configuration); AZ::EditContext* editContext = serializeContext->GetEditContext(); if (editContext) { - editContext->Class("Following Camera", "Camera following kraken") + editContext->Class("Following Camera", "Camera following entity with predefined views") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game")) ->Attribute(AZ::Edit::Attributes::Category, "ROS2 Utilities") @@ -48,31 +48,29 @@ namespace ROS2 ->UIElement(AZ::Edit::UIHandlers::Label, "", "") ->Attribute( AZ::Edit::Attributes::ValueText, - "This Component allows to switch camera among predefined transformation obtained from entities in Views. " + "This Component allows to switch camera view between predefined views. " "It also allows to zoom in/out and rotate around parent transformation. " - "It has smoothing capabilities. " - "Numerical keys allow to switch views. W,S,A,D keys allow to offset current view.") + "Use 0-9 keys to switch views and W, S, A, D keys to manipulate current view.") ->DataElement( AZ::Edit::UIHandlers::Default, - &FollowingCameraComponent::m_smoothingBuffer, - "Smoothing Length", - "Number of past transform used to smooth, larger value gives smoother result, but more lag") - ->Attribute(AZ::Edit::Attributes::Min, 1) - ->Attribute(AZ::Edit::Attributes::Max, 100) - ->DataElement(AZ::Edit::UIHandlers::Default, &FollowingCameraComponent::m_zoomSpeed, "Zoom Speed", "Speed of zooming") - ->DataElement( - AZ::Edit::UIHandlers::Default, - &FollowingCameraComponent::m_rotationSpeed, - "Rotation Speed", - "Rotation Speed around the target") - ->DataElement(AZ::Edit::UIHandlers::Default, &FollowingCameraComponent::m_predefinedViews, "Views", "Views to follow") - ->DataElement( - AZ::Edit::UIHandlers::Default, &FollowingCameraComponent::m_defaultView, "Default View", "Default View to follow") - ->Attribute(AZ::Edit::Attributes::Min, 0); + &FollowingCameraComponent::m_configuration, + "FollowingCameraConfiguration", + "FollowingCameraConfiguration") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); } } } + void FollowingCameraComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC("FollowingCameraService")); + } + + void FollowingCameraComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC("FollowingCameraService")); + } + void FollowingCameraComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC("TransformService")); @@ -81,14 +79,14 @@ namespace ROS2 void FollowingCameraComponent::Activate() { - if (m_predefinedViews.size() == 0) + if (m_configuration.m_predefinedViews.size() == 0) { - AZ_Warning("FollowingCameraComponent", false, "No predefined views"); - return; + AZ_Warning("FollowingCameraComponent", false, "No predefined views"); + return; } - if (m_defaultView < m_predefinedViews.size()) + if (m_configuration.m_defaultView < m_configuration.m_predefinedViews.size()) { - m_currentView = m_predefinedViews[m_defaultView]; + m_currentView = m_configuration.m_predefinedViews[m_configuration.m_defaultView]; } InputChannelEventListener::Connect(); AZ::TickBus::Handler::BusConnect(); @@ -106,11 +104,11 @@ namespace ROS2 m_lastTranslationsBuffer.push_back(AZStd::make_pair(transform.GetTranslation(), deltaTime)); m_lastRotationsBuffer.push_back(AZStd::make_pair(transform.GetRotation(), deltaTime)); - if (m_lastTranslationsBuffer.size() > m_smoothingBuffer) + if (m_lastTranslationsBuffer.size() > m_configuration.m_smoothingBuffer) { m_lastTranslationsBuffer.pop_front(); } - if (m_lastRotationsBuffer.size() > m_smoothingBuffer) + if (m_lastRotationsBuffer.size() > m_configuration.m_smoothingBuffer) { m_lastRotationsBuffer.pop_front(); } @@ -136,7 +134,6 @@ namespace ROS2 // get the averaged translation and quaternion AZ::Transform filtered_parent_transform = { SmoothTranslation(), SmoothRotation(), 1.f }; - // modifier for zooming auto modifiedTransformZoom = AZ::Transform::CreateIdentity(); modifiedTransformZoom.SetTranslation(AZ::Vector3::CreateAxisY(m_opticalAxisTranslation)); @@ -174,7 +171,6 @@ namespace ROS2 for (int i = 1; i < m_lastRotationsBuffer.size(); i++) { q = q.Slerp(m_lastRotationsBuffer[i].first, m_lastRotationsBuffer[i].second); - } return q; } @@ -196,32 +192,32 @@ namespace ROS2 const AzFramework::InputChannelId& channelId = inputChannel.GetInputChannelId(); if (channelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericW) { - m_opticalAxisTranslation += m_zoomSpeed; - m_opticalAxisTranslation = AZStd::min(m_opticalAxisTranslation, m_opticalAxisTranslationMin); + m_opticalAxisTranslation += m_configuration.m_zoomSpeed; + m_opticalAxisTranslation = AZStd::min(m_opticalAxisTranslation, m_configuration.m_opticalAxisTranslationMin); return; } if (channelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericS) { - m_opticalAxisTranslation -= m_zoomSpeed; + m_opticalAxisTranslation -= m_configuration.m_zoomSpeed; return; } if (channelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericA) { - m_rotationOffset -= m_rotationSpeed; + m_rotationOffset -= m_configuration.m_rotationSpeed; return; } if (channelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericD) { - m_rotationOffset += m_rotationSpeed; + m_rotationOffset += m_configuration.m_rotationSpeed; return; } - auto it = KeysToView.find(channelId); - if (it != KeysToView.end()) + + // channelId is a numeric key (Key::Alphanumeric0-Key::Alphanumeric9) + if (auto it = KeysToView.find(channelId); it != KeysToView.end()) { - int viewId = it->second; - if (viewId < m_predefinedViews.size()) + if (int viewId = it->second; viewId < m_configuration.m_predefinedViews.size()) { - m_currentView = m_predefinedViews[viewId]; + m_currentView = m_configuration.m_predefinedViews[viewId]; m_lastTranslationsBuffer.clear(); m_lastRotationsBuffer.clear(); } diff --git a/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraComponent.h b/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraComponent.h index 1776a2e58..19e18e01d 100644 --- a/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraComponent.h +++ b/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraComponent.h @@ -8,6 +8,7 @@ #pragma once +#include "FollowingCameraConfiguration.h" #include #include #include @@ -15,7 +16,7 @@ namespace ROS2 { - //! The component used for cameras that follow robots. + //! The component used for cameras that follow moving objects //! It allows to switch between different cameras attached to entities, and to control the active camera using keyboard. class FollowingCameraComponent : public AZ::Component @@ -23,8 +24,14 @@ namespace ROS2 , public AzFramework::InputChannelEventListener { public: + FollowingCameraComponent() = default; + FollowingCameraComponent(const FollowingCameraConfiguration& configuration); static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void Reflect(AZ::ReflectContext* reflection); AZ_COMPONENT(FollowingCameraComponent, "{6a21768a-f327-11ed-a05b-0242ac120003}", AZ::Component); @@ -34,12 +41,11 @@ namespace ROS2 void Deactivate() override; private: - // AZ::TickBus overrides + // AZ::TickBus overrides .. void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - // AzFramework::InputChannelEventListener overrides + // AzFramework::InputChannelEventListener overrides ... bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override; - void OnKeyboardEvent(const AzFramework::InputChannel& inputChannel); //! Compute weighted average of the vectors in the buffer. @@ -66,25 +72,10 @@ namespace ROS2 //! The smoothing buffer for rotation, the first element is the tangential vector, the second element is the weight. AZStd::deque> m_lastRotationsBuffer; - //! Predefined view points. - AZStd::vector m_predefinedViews; - - //! Default view point to active after activation. - int m_defaultView{ 0 }; - - //! Current used view point. - AZ::EntityId m_currentView; - - //! The rotation and zoom change from the input. - float m_rotationOffset = 0.0f; - //! The translation offset from the defined view. - float m_opticalAxisTranslation = 0.0f; - - //! The length of the smoothing buffer. - int m_smoothingBuffer = 30; - float m_zoomSpeed = 0.06f; - float m_rotationSpeed = 0.05f; + float m_rotationOffset = 0.0f; //!< The rotation change from the input. + float m_opticalAxisTranslation = 0.0f; //!< The zoom change from the input. + AZ::EntityId m_currentView; //!< Current used view point. - const float m_opticalAxisTranslationMin = 0.0f; + FollowingCameraConfiguration m_configuration; //!< The configuration of the following camera. }; } // namespace ROS2 diff --git a/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraConfiguration.cpp b/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraConfiguration.cpp new file mode 100644 index 000000000..7a603bfb6 --- /dev/null +++ b/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraConfiguration.cpp @@ -0,0 +1,56 @@ +/* + * 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 + * + */ + +#include "FollowingCameraConfiguration.h" +#include +#include + +namespace ROS2 +{ + void FollowingCameraConfiguration::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class() + ->Version(1) + ->Field("PredefinedViews", &FollowingCameraConfiguration::m_predefinedViews) + ->Field("SmoothingLength", &FollowingCameraConfiguration::m_smoothingBuffer) + ->Field("ZoomSpeed", &FollowingCameraConfiguration::m_zoomSpeed) + ->Field("RotationSpeed", &FollowingCameraConfiguration::m_rotationSpeed) + ->Field("DefaultView", &FollowingCameraConfiguration::m_defaultView); + + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ec->Class("Follow Camera Configuration", "Configuration for the Following Camera Component") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &FollowingCameraConfiguration::m_smoothingBuffer, + "Smoothing Length", + "Number of past transforms used to smooth, larger value gives smoother result, but more lag") + ->Attribute(AZ::Edit::Attributes::Min, 1) + ->Attribute(AZ::Edit::Attributes::Max, 100) + ->DataElement( + AZ::Edit::UIHandlers::Default, &FollowingCameraConfiguration::m_zoomSpeed, "Zoom Speed", "Speed of zooming") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &FollowingCameraConfiguration::m_rotationSpeed, + "Rotation Speed", + "Rotation Speed around the target") + ->DataElement( + AZ::Edit::UIHandlers::Default, &FollowingCameraConfiguration::m_predefinedViews, "Views", "Views to follow") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &FollowingCameraConfiguration::m_defaultView, + "Default View", + "Default View to follow") + ->Attribute(AZ::Edit::Attributes::Min, 0); + } + } + } + +} // namespace ROS2 diff --git a/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraConfiguration.h b/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraConfiguration.h new file mode 100644 index 000000000..f421f4d65 --- /dev/null +++ b/Gems/ROS2/Code/Source/SimulationUtils/FollowingCameraConfiguration.h @@ -0,0 +1,31 @@ +/* + * 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 +#include +#include +#include + +namespace ROS2 +{ + //! A structure capturing configuration of Following Camera. + struct FollowingCameraConfiguration + { + AZ_TYPE_INFO(FollowingCameraConfiguration, "{605fec3d-0152-44f3-b885-669cdcf201eb}"); + static void Reflect(AZ::ReflectContext* context); + + AZStd::vector m_predefinedViews; //!< List of predefined views. + int m_defaultView{ 0 }; //!< Index of the default view. + int m_smoothingBuffer = 30; //!< Number of past transforms used to smooth, larger value gives smoother result, but more lag + float m_zoomSpeed = 0.06f; //!< Speed of zooming + float m_rotationSpeed = 0.05f; //!< Rotation Speed around the target + const float m_opticalAxisTranslationMin = 0.0f; //!< Minimum zoom distance + }; +} // namespace ROS2 diff --git a/Gems/ROS2/Code/ros2_files.cmake b/Gems/ROS2/Code/ros2_files.cmake index 369a71751..d198e91bc 100644 --- a/Gems/ROS2/Code/ros2_files.cmake +++ b/Gems/ROS2/Code/ros2_files.cmake @@ -116,6 +116,8 @@ set(FILES Source/ROS2SystemComponent.h Source/Sensor/ROS2SensorComponent.cpp Source/Sensor/SensorConfiguration.cpp + Source/SimulationUtils/FollowingCameraConfiguration.cpp + Source/SimulationUtils/FollowingCameraConfiguration.h Source/SimulationUtils/FollowingCameraComponent.cpp Source/SimulationUtils/FollowingCameraComponent.h Source/Spawner/ROS2SpawnerComponent.cpp