Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,44 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_add_target(
NAME Atom_Component_DebugCamera.Static STATIC
NAMESPACE Gem
FILES_CMAKE
atom_component_debugcamera_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PUBLIC
AZ::AtomCore
AZ::AzCore
AZ::AzFramework
Gem::Atom_RPI.Public
)
ly_add_target(
NAME Atom_Component_DebugCamera ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
OUTPUT_NAME Gem.Atom_Component_DebugCamera.013d1b42ad314c929b292c143bcbf045.v0.1.0
FILES_CMAKE
atom_component_debugcamera_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PRIVATE
Gem::Atom_Component_DebugCamera.Static
)
@@ -0,0 +1,64 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Math/Vector3.h>
namespace AZ
{
class ReflectContext;
namespace Debug
{
enum ArcBallControllerChannel : uint32_t
{
ArcBallControllerChannel_None = 0x00,
ArcBallControllerChannel_Center = 0x01,
ArcBallControllerChannel_Pan = 0x02,
ArcBallControllerChannel_Distance = 0x04,
ArcBallControllerChannel_Heading = 0x08,
ArcBallControllerChannel_Pitch = 0x10,
ArcBallControllerChannel_Orientation = (ArcBallControllerChannel_Heading | ArcBallControllerChannel_Pitch)
};
class ArcBallControllerRequests
: public AZ::ComponentBus
{
public:
using MutexType = AZStd::recursive_mutex;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
virtual void SetCenter(AZ::Vector3 center) = 0;
virtual void SetPan(AZ::Vector3 pan) = 0;
virtual void SetDistance(float distance) = 0;
virtual void SetMinDistance(float minDistance) = 0;
virtual void SetMaxDistance(float maxDistance) = 0;
virtual void SetHeading(float heading) = 0;
virtual void SetPitch(float pitch) = 0;
virtual void SetPanningSensitivity(float panningSensitivity) = 0;
virtual void SetZoomingSensitivity(float zoomingSensitivity) = 0;
virtual AZ::Vector3 GetCenter() = 0;
virtual AZ::Vector3 GetPan() = 0;
virtual float GetDistance() = 0;
virtual float GetMinDistance() = 0;
virtual float GetMaxDistance() = 0;
virtual float GetHeading() = 0;
virtual float GetPitch() = 0;
virtual float GetPanningSensitivity() = 0;
virtual float GetZoomingSensitivity() = 0;
};
using ArcBallControllerRequestBus = AZ::EBus<ArcBallControllerRequests>;
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,94 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/std/containers/bitset.h>
#include <AzFramework/Input/Events/InputChannelEventListener.h>
#include <Atom/Component/DebugCamera/ArcBallControllerBus.h>
#include <Atom/Component/DebugCamera/CameraControllerComponent.h>
namespace AZ
{
namespace Debug
{
class ArcBallControllerComponent
: public CameraControllerComponent
, public TickBus::Handler
, public AzFramework::InputChannelEventListener
, ArcBallControllerRequestBus::Handler
{
public:
AZ_COMPONENT(ArcBallControllerComponent, "{3CCDE644-2798-4A58-992C-1C420599FCEE}", CameraControllerComponent);
ArcBallControllerComponent();
virtual ~ArcBallControllerComponent() = default;
static void Reflect(AZ::ReflectContext* reflection);
private:
/// CameraControllerComponent
void OnEnabled() override;
void OnDisabled() override;
// TickBus
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// AzFramework::InputChannelEventListener
bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override;
void SetCenter(AZ::Vector3 center) override;
void SetPan(AZ::Vector3 pan) override;
void SetDistance(float distance) override;
void SetMinDistance(float minDistance) override;
void SetMaxDistance(float maxDistance) override;
void SetHeading(float heading) override;
void SetPitch(float pitch) override;
void SetPanningSensitivity(float panningSensitivity) override;
void SetZoomingSensitivity(float zoomingSensitivity) override;
AZ::Vector3 GetCenter() override;
AZ::Vector3 GetPan() override;
float GetDistance() override;
float GetMinDistance() override;
float GetMaxDistance() override;
float GetHeading() override;
float GetPitch() override;
float GetPanningSensitivity() override;
float GetZoomingSensitivity() override;
bool m_arcballActive = false;
bool m_panningActive = false;
bool m_zoomingActive = false;
AZ::Vector3 m_center = AZ::Vector3::CreateZero();
AZ::Vector3 m_panningOffset = AZ::Vector3::CreateZero();
AZ::Vector3 m_panningOffsetDelta = AZ::Vector3::CreateZero();
float m_distance = 5.0f;
float m_minDistance = 0.1f;
float m_maxDistance = 10.0f;
float m_currentHeading = 0.0f;
float m_currentPitch = 0.0f;
float m_panningSensitivity = 1.0f;
float m_zoomingSensitivity = 1.0f;
AZ::Vector2 m_lastTouchPosition;
uint32_t m_windowWidth = 0;
uint32_t m_windowHeight = 0;
};
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,124 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/Matrix4x4.h>
#include <AzCore/Math/Vector3.h>
#include <AzFramework/Components/CameraBus.h>
#include <Atom/RPI.Public/ViewProviderBus.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/WindowContext.h>
#include <Atom/RPI.Public/WindowContextBus.h>
namespace AZ
{
namespace RPI
{
class AuxGeomFeatureProcessorInterface;
}
namespace Debug
{
class CameraComponentConfig
: public ComponentConfig
{
public:
AZ_RTTI(CameraComponentConfig, "{F4F7512E-D744-4DD9-9AA8-2F5AB15480F6}", AZ::ComponentConfig);
AZ_CLASS_ALLOCATOR(CameraComponentConfig, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
CameraComponentConfig() {}
explicit CameraComponentConfig(AZStd::shared_ptr<RPI::WindowContext> target)
: m_target(target)
{}
float m_fovY = AZ::Constants::QuarterPi;
float m_depthNear = 0.1f;
float m_depthFar = 100.0f;
float m_aspectRatioOverride = 0.0f;
AZStd::shared_ptr<RPI::WindowContext> m_target = nullptr;
};
class CameraComponent
: public Component
, public TransformNotificationBus::Handler
, public RPI::ViewProviderBus::Handler
, public Camera::CameraRequestBus::Handler
, public RPI::WindowContextNotificationBus::Handler
{
public:
AZ_COMPONENT(CameraComponent, "{2BAFDA24-B354-4C5C-95BE-D7254B4BD415}", AZ::Component);
static void Reflect(AZ::ReflectContext* context);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
CameraComponent() = default;
virtual ~CameraComponent() override = default;
// AZ::Component overrides...
void Activate() override;
void Deactivate() override;
// RPI::ViewProviderBus::Handler overrides...
RPI::ViewPtr GetView() const override;
private:
// AZ::Component overrides...
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
// TransformNotificationBus::Handler overrides...
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
// CameraRequestBus::Handler overrides...
float GetFovDegrees() override;
float GetFovRadians() override;
float GetNearClipDistance() override;
float GetFarClipDistance() override;
float GetFrustumWidth() override;
float GetFrustumHeight() override;
void SetFovDegrees(float fov) override;
void SetFovRadians(float fov) override;
void SetNearClipDistance(float nearClipDistance) override;
void SetFarClipDistance(float farClipDistance) override;
void SetFrustumWidth(float width) override;
void SetFrustumHeight(float height) override;
void MakeActiveView() override;
// RPI::WindowContextNotificationBus overrides...
void OnViewportResized(uint32_t width, uint32_t height) override;
void UpdateAspectRatio();
void UpdateViewToClipMatrix();
RPI::ViewPtr m_view = nullptr;
// Work around the EntityContext being detached before the camera component is deactivated.
// Without EntityContext class can't get AuxGeomFeatureProcessor to clean up per view draw interface.
RPI::AuxGeomFeatureProcessorInterface* m_auxGeomFeatureProcessor = nullptr;
CameraComponentConfig m_componentConfig;
float m_aspectRatio = 1.0f;
};
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,68 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
namespace AZ
{
class ReflectContext;
namespace Debug
{
//! Requests sent to any camera controllers in one entity
class CameraControllerRequests
: public ComponentBus
{
public:
using MutexType = AZStd::recursive_mutex;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
//! Enable the controller that has this typeId. Any other controllers which are different types will be disabled.
virtual void Enable(TypeId typeId) = 0;
//! Reset a controller to initial stats if it's enabled.
virtual void Reset() = 0;
//! Disable the controller which is enabled
virtual void Disable() = 0;
};
using CameraControllerRequestBus = AZ::EBus<CameraControllerRequests>;
//! Notifications sent by each camera controller
class CameraControllerNotifications
: public ComponentBus
{
public:
//! @param typeId the ID of the controller that was enabled
virtual void OnControllerEnabled([[maybe_unused]] TypeId typeId) {}
//! @param typeId the ID of the controller that was disabled
virtual void OnControllerDisabled([[maybe_unused]] TypeId typeId) {}
//! Called when user input begins a camera move
//! @param controllerTypeId the ID of this camera controller
//! @param channels the bitmask indicating the channels that began moving. The channel values are controller-specific.
virtual void OnCameraMoveBegan([[maybe_unused]] TypeId controllerTypeId, [[maybe_unused]] uint32_t channels) {}
//! Called when user input ends after a camera move
//! @param controllerTypeId the ID of this camera controller
//! @param channels the bitmask indicating the channels that ended moving. The channel values are controller-specific.
virtual void OnCameraMoveEnded([[maybe_unused]] TypeId controllerTypeId, [[maybe_unused]] uint32_t channels) {}
};
using CameraControllerNotificationBus = AZ::EBus<CameraControllerNotifications>;
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,63 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <Atom/Component/DebugCamera/CameraControllerBus.h>
namespace AZ
{
namespace Debug
{
/**
* CameraControllerComponent is the base class of any camera controller component
* which can modify camera's transformation or frustum.
* A camera controller usually processes input events and then utilizes the data to modify the entity's transformation.
* It's allowed to have more than one camera controller component on the same camera entity but there will
* be only one controller activated at same time.
* The derived class should disable its event handling and updating accordingly when the controller is disabled.
*/
class CameraControllerComponent
: public Component
, public CameraControllerRequestBus::Handler
{
public:
AZ_COMPONENT(CameraControllerComponent, "{A3503719-6DE2-46D0-A54B-922155F4537F}", AZ::Component);
CameraControllerComponent() = default;
virtual ~CameraControllerComponent() = default;
static void Reflect(AZ::ReflectContext* context);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
// CameraControllerRequestBus::Handler overrides
void Enable(TypeId typeId) override final;
void Reset() override final;
void Disable() override final;
// AZ::Component overrides
void Activate() override final;
void Deactivate() override final;
private:
// The derived components implements these functions for when the controller is enabled/disabled
virtual void OnEnabled() {}
virtual void OnDisabled() {}
bool m_enabled = false;
};
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,78 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Math/Vector3.h>
namespace AZ
{
class ReflectContext;
namespace Debug
{
enum NoClipControllerChannel : uint32_t
{
NoClipControllerChannel_None = 0x0,
NoClipControllerChannel_Position = 0x1,
NoClipControllerChannel_Orientation = 0x2,
NoClipControllerChannel_Fov = 0x4,
};
struct NoClipControllerProperties
{
AZ_TYPE_INFO(NoClipControllerProperties, "{65F7E522-7FDE-414E-AA0F-638B234699B8}");
static void Reflect(AZ::ReflectContext* context);
float m_mouseSensitivityX = 1.0f;
float m_mouseSensitivityY = 1.0f;
float m_moveSpeed = 1.0f;
float m_panningSpeed = 1.0f;
float m_touchSensitivity = 3.0f;
};
class NoClipControllerRequests
: public AZ::ComponentBus
{
public:
using MutexType = AZStd::recursive_mutex;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
virtual void SetMouseSensitivityX(float mouseSensitivityX) = 0;
virtual void SetMouseSensitivityY(float mouseSensitivityY) = 0;
virtual void SetMoveSpeed(float moveSpeed) = 0;
virtual void SetPanningSpeed(float panningSpeed) = 0;
virtual void SetTouchSensitivity(float touchSensitivity) = 0;
virtual void SetControllerProperties(const NoClipControllerProperties& properties) = 0;
virtual void SetPosition(AZ::Vector3 position) = 0;
virtual void SetHeading(float heading) = 0;
virtual void SetPitch(float pitch) = 0;
virtual void SetFov(float fov) = 0;
virtual float GetMouseSensitivityX() = 0;
virtual float GetMouseSensitivityY() = 0;
virtual float GetMoveSpeed() = 0;
virtual float GetPanningSpeed() = 0;
virtual float GetTouchSensitivity() = 0;
virtual NoClipControllerProperties GetControllerProperties() = 0;
virtual AZ::Vector3 GetPosition() = 0;
virtual float GetHeading() = 0;
virtual float GetPitch() = 0;
virtual float GetFov() = 0;
};
using NoClipControllerRequestBus = AZ::EBus<NoClipControllerRequests>;
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,118 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <Atom/Component/DebugCamera/CameraControllerComponent.h>
#include <Atom/Component/DebugCamera/NoClipControllerBus.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/std/containers/bitset.h>
#include <AzFramework/Input/Events/InputChannelEventListener.h>
namespace AZ
{
namespace Debug
{
class NoClipControllerComponent
: public CameraControllerComponent
, public TickBus::Handler
, public AzFramework::InputChannelEventListener
, public NoClipControllerRequestBus::Handler
{
public:
AZ_COMPONENT(NoClipControllerComponent, "{FDDF608A-7866-4886-87E5-6F02899C6C4D}", CameraControllerComponent);
NoClipControllerComponent();
virtual ~NoClipControllerComponent() = default;
static void Reflect(AZ::ReflectContext* reflection);
private:
// CameraControllerComponent overrides
void OnEnabled() override;
void OnDisabled() override;
// TickBus
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// AzFramework::InputChannelEventListener
bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override;
// ControllerRequestsBus::Handler
void SetMouseSensitivityX(float mouseSensitivityX) override;
void SetMouseSensitivityY(float mouseSensitivityY) override;
void SetMoveSpeed(float moveSpeed) override;
void SetPanningSpeed(float panningSpeed) override;
void SetControllerProperties(const NoClipControllerProperties& properties) override;
void SetTouchSensitivity(float touchSensitivity) override;
void SetPosition(AZ::Vector3 position) override;
void SetHeading(float heading) override;
void SetPitch(float pitch) override;
void SetFov(float fov) override;
float GetMouseSensitivityX() override;
float GetMouseSensitivityY() override;
float GetMoveSpeed() override;
float GetPanningSpeed() override;
float GetTouchSensitivity() override;
NoClipControllerProperties GetControllerProperties() override;
AZ::Vector3 GetPosition() override;
float GetHeading() override;
float GetPitch() override;
float GetFov() override;
enum CameraKeys
{
Forward = 0,
Back,
Left,
Right,
Up,
Down,
FastMode,
Count
};
bool m_mouseLookEnabled = false;
AZStd::bitset<static_cast<size_t>(CameraKeys::Count)> m_inputStates = 0;
NoClipControllerProperties m_properties;
float m_currentHeading = 0.0f;
float m_currentPitch = 0.0f;
float m_currentFov = 0.0f;
float m_lastForward = 0.0f;
float m_lastStrafe = 0.0f;
float m_lastAscent = 0.0f;
struct TouchEvent
{
static const AzFramework::InputChannelId InvalidTouchChannelId;
AZ::Vector2 m_initialPos = AZ::Vector2::CreateZero();
AzFramework::InputChannelId m_channelId = InvalidTouchChannelId;
};
TouchEvent m_mouseLookTouch;
TouchEvent m_movementTouch;
};
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,445 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Atom/Component/DebugCamera/ArcBallControllerComponent.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h>
#include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
#include <AzFramework/Windowing/WindowBus.h>
#include <DebugCameraUtils.h>
namespace AZ
{
namespace Debug
{
ArcBallControllerComponent::ArcBallControllerComponent()
: AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault())
{}
void ArcBallControllerComponent::Reflect(AZ::ReflectContext* reflection)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<ArcBallControllerComponent, CameraControllerComponent, AZ::Component>()
->Version(1);
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflection))
{
behaviorContext->EBus<ArcBallControllerRequestBus>("ArcBallControllerRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Camera")
->Attribute(AZ::Script::Attributes::Module, "render")
->Event("SetCenter", &ArcBallControllerRequestBus::Events::SetCenter)
->Event("SetPan", &ArcBallControllerRequestBus::Events::SetPan)
->Event("SetDistance", &ArcBallControllerRequestBus::Events::SetDistance)
->Event("SetMinDistance", &ArcBallControllerRequestBus::Events::SetMinDistance)
->Event("SetMaxDistance", &ArcBallControllerRequestBus::Events::SetMaxDistance)
->Event("SetHeading", &ArcBallControllerRequestBus::Events::SetHeading)
->Event("SetPitch", &ArcBallControllerRequestBus::Events::SetPitch)
->Event("SetPanningSensitivity", &ArcBallControllerRequestBus::Events::SetPanningSensitivity)
->Event("SetZoomingSensitivity", &ArcBallControllerRequestBus::Events::SetZoomingSensitivity)
->Event("GetCenter", &ArcBallControllerRequestBus::Events::GetCenter)
->Event("GetPan", &ArcBallControllerRequestBus::Events::GetPan)
->Event("GetDistance", &ArcBallControllerRequestBus::Events::GetDistance)
->Event("GetMinDistance", &ArcBallControllerRequestBus::Events::GetMinDistance)
->Event("GetMaxDistance", &ArcBallControllerRequestBus::Events::GetMaxDistance)
->Event("GetHeading", &ArcBallControllerRequestBus::Events::GetHeading)
->Event("GetPitch", &ArcBallControllerRequestBus::Events::GetPitch)
->Event("GetPanningSensitivity", &ArcBallControllerRequestBus::Events::GetPanningSensitivity)
->Event("GetZoomingSensitivity", &ArcBallControllerRequestBus::Events::GetZoomingSensitivity)
;
}
}
void ArcBallControllerComponent::OnEnabled()
{
// Reset parameters with initial values
m_arcballActive = false;
m_panningActive = false;
m_center = AZ::Vector3::CreateZero();
m_panningOffset = AZ::Vector3::CreateZero();
m_panningOffsetDelta = AZ::Vector3::CreateZero();
m_distance = 5.0f;
m_minDistance = 0.1f;
m_maxDistance = 10.0f;
m_currentHeading = 0.0f;
m_currentPitch = 0.0f;
m_panningSensitivity = 1.0f;
m_zoomingSensitivity = 1.0f;
AzFramework::NativeWindowHandle windowHandle = nullptr;
AzFramework::WindowSystemRequestBus::BroadcastResult(
windowHandle,
&AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle);
AzFramework::WindowSize windowSize;
AzFramework::WindowRequestBus::EventResult(
windowSize,
windowHandle,
&AzFramework::WindowRequestBus::Events::GetClientAreaSize);
m_windowWidth = windowSize.m_width;
m_windowHeight = windowSize.m_height;
ArcBallControllerRequestBus::Handler::BusConnect(GetEntityId());
AzFramework::InputChannelEventListener::Connect();
AZ::TickBus::Handler::BusConnect();
}
void ArcBallControllerComponent::OnDisabled()
{
TickBus::Handler::BusDisconnect();
AzFramework::InputChannelEventListener::Disconnect();
ArcBallControllerRequestBus::Handler::BusDisconnect();
}
void ArcBallControllerComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time)
{
AZ_UNUSED(time);
if (m_distance < m_minDistance)
{
m_distance = m_minDistance;
}
else if (m_distance > m_maxDistance)
{
m_distance = m_maxDistance;
}
// The coordinate system is right-handed and Z-up. So heading is a rotation around the Z axis.
// After that rotation we rotate around the (rotated by heading) X axis for pitch.
AZ::Quaternion orientation = AZ::Quaternion::CreateRotationZ(m_currentHeading)
* AZ::Quaternion::CreateRotationX(m_currentPitch);
m_panningOffsetDelta *= deltaTime;
m_panningOffset += (orientation.TransformVector(m_panningOffsetDelta));
AZ::Vector3 position = (m_center + m_panningOffset) + (orientation.TransformVector(AZ::Vector3(0, -m_distance, 0)));
AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(orientation, position);
AZ::TransformBus::Event(
GetEntityId(), &AZ::TransformBus::Events::SetLocalTM, transform);
}
bool ArcBallControllerComponent::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
{
static const float PixelToDegree = 1.0 / 360.0f;
uint32_t handledChannels = ArcBallControllerChannel_None;
const AzFramework::InputChannelId& inputChannelId = inputChannel.GetInputChannelId();
switch (inputChannel.GetState())
{
case AzFramework::InputChannel::State::Began:
case AzFramework::InputChannel::State::Updated: // update the camera rotation
{
//Keyboard & Mouse
if (inputChannelId == AzFramework::InputDeviceMouse::Button::Right)
{
m_arcballActive = true;
handledChannels |= ArcBallControllerChannel_Orientation;
}
else if (inputChannelId == AzFramework::InputDeviceMouse::Button::Middle)
{
m_panningActive = true;
handledChannels |= ArcBallControllerChannel_Pan;
}
if (m_arcballActive)
{
if (inputChannelId == AzFramework::InputDeviceMouse::Movement::X)
{
// modify yaw angle
m_currentHeading -= inputChannel.GetValue() * PixelToDegree;
m_currentHeading = NormalizeAngle(m_currentHeading);
}
else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Y)
{
// modify pitch angle
m_currentPitch -= inputChannel.GetValue() * PixelToDegree;
m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
}
}
else if (m_panningActive)
{
if (inputChannelId == AzFramework::InputDeviceMouse::Movement::X)
{
m_panningOffsetDelta.SetX(-inputChannel.GetValue() * m_panningSensitivity);
}
else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Y)
{
m_panningOffsetDelta.SetZ(inputChannel.GetValue() * m_panningSensitivity);
}
}
if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Z)
{
const float MouseWheelDeltaScale = 1.0f / 120.0f; // based on WHEEL_DELTA in WinUser.h
m_distance -= inputChannel.GetValue() * MouseWheelDeltaScale * m_zoomingSensitivity;
m_zoomingActive = true;
handledChannels |= ArcBallControllerChannel_Distance;
}
// Gamepad
if (inputChannelId == AzFramework::InputDeviceGamepad::Trigger::L2)
{
m_arcballActive = true;
handledChannels |= ArcBallControllerChannel_Orientation;
}
else if (inputChannelId == AzFramework::InputDeviceGamepad::Button::L1)
{
m_panningActive = true;
handledChannels |= ArcBallControllerChannel_Pan;
}
if (m_arcballActive)
{
if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RX)
{
// modify yaw angle
m_currentHeading -= inputChannel.GetValue() * PixelToDegree;
m_currentHeading = NormalizeAngle(m_currentHeading);
}
else if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RY)
{
// modify pitch angle
m_currentPitch += inputChannel.GetValue() * PixelToDegree;
m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
}
}
else if (m_panningActive)
{
if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RX)
{
m_panningOffsetDelta.SetX(-inputChannel.GetValue() * 10.0f * m_panningSensitivity);
}
else if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RY)
{
m_panningOffsetDelta.SetZ(inputChannel.GetValue() * 10.0f * m_panningSensitivity);
}
}
if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::LY)
{
m_distance -= inputChannel.GetValue() * m_zoomingSensitivity;
m_zoomingActive = true;
handledChannels |= ArcBallControllerChannel_Distance;
}
// Touch controls works depending which side of the screen you start the touch event.
// Left side controls the heading and pitch. Right side controls the panning.
// Only one touch control can be active at the same time.
if (inputChannelId == AzFramework::InputDeviceTouch::Touch::Index0)
{
auto* positionData = inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
AZ::Vector2 screenPos = positionData->m_normalizedPosition;
auto deltaInPixels = screenPos - m_lastTouchPosition;
deltaInPixels *= AZ::Vector2(static_cast<float>(m_windowWidth), static_cast<float>(m_windowHeight));
if (inputChannel.GetState() == AzFramework::InputChannel::State::Began)
{
m_panningActive = screenPos.GetX() > 0.5f ? true : false;
m_arcballActive = !m_panningActive;
}
else if(m_panningActive)
{
m_panningOffsetDelta.SetX(-deltaInPixels.GetX() * m_panningSensitivity);
m_panningOffsetDelta.SetZ(deltaInPixels.GetY() * m_panningSensitivity);
}
else if(m_arcballActive)
{
// modify yaw angle
m_currentHeading -= deltaInPixels.GetX() * PixelToDegree;
m_currentHeading = NormalizeAngle(m_currentHeading);
// modify pitch angle
m_currentPitch -= deltaInPixels.GetY() * PixelToDegree;
m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
}
m_lastTouchPosition = screenPos;
if (m_panningActive)
{
handledChannels |= ArcBallControllerChannel_Pan;
}
else if (m_arcballActive)
{
handledChannels |= ArcBallControllerChannel_Orientation;
}
}
if (handledChannels && AzFramework::InputChannel::State::Began == inputChannel.GetState())
{
CameraControllerNotificationBus::Broadcast(&CameraControllerNotifications::OnCameraMoveBegan, RTTI_GetType(), handledChannels);
}
break;
}
case AzFramework::InputChannel::State::Ended: // update the released input state
{
uint32_t handledChannels2 = ArcBallControllerChannel_None;
if (inputChannelId == AzFramework::InputDeviceMouse::Button::Right)
{
m_arcballActive = false;
handledChannels2 |= ArcBallControllerChannel_Orientation;
}
else if (inputChannelId == AzFramework::InputDeviceMouse::Button::Middle)
{
m_panningActive = false;
handledChannels2 |= ArcBallControllerChannel_Pan;
}
else if (inputChannelId == AzFramework::InputDeviceGamepad::Trigger::L2)
{
m_arcballActive = false;
handledChannels2 |= ArcBallControllerChannel_Orientation;
}
else if (inputChannelId == AzFramework::InputDeviceGamepad::Button::L1)
{
m_panningActive = false;
handledChannels2 |= ArcBallControllerChannel_Pan;
}
else if (inputChannelId == AzFramework::InputDeviceTouch::Touch::Index0)
{
if (m_panningActive)
{
handledChannels2 |= ArcBallControllerChannel_Pan;
}
else if (m_arcballActive)
{
handledChannels2 |= ArcBallControllerChannel_Orientation;
}
m_panningActive = false;
m_arcballActive = false;
}
else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Z ||
inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::LY)
{
m_zoomingActive = false;
handledChannels2 |= ArcBallControllerChannel_Distance;
}
if (handledChannels2)
{
CameraControllerNotificationBus::Broadcast(&CameraControllerNotifications::OnCameraMoveEnded, RTTI_GetType(), handledChannels2);
}
}
default:
{
break;
}
}
return false;
}
void ArcBallControllerComponent::SetCenter(AZ::Vector3 center)
{
m_center = center;
}
void ArcBallControllerComponent::SetPan(AZ::Vector3 pan)
{
m_panningOffset = pan;
}
void ArcBallControllerComponent::SetDistance(float distance)
{
m_distance = distance;
}
void ArcBallControllerComponent::SetMinDistance(float minDistance)
{
m_minDistance = minDistance;
m_distance = AZ::GetMax(m_distance, m_minDistance);
}
void ArcBallControllerComponent::SetMaxDistance(float maxDistance)
{
m_maxDistance = maxDistance;
m_distance = AZ::GetMin(m_distance, m_maxDistance);
}
void ArcBallControllerComponent::SetHeading(float heading)
{
m_currentHeading = heading;
}
void ArcBallControllerComponent::SetPitch(float pitch)
{
m_currentPitch = pitch;
}
void ArcBallControllerComponent::SetPanningSensitivity(float panningSensitivity)
{
m_panningSensitivity = AZ::GetMax(panningSensitivity, 0.0f);
}
void ArcBallControllerComponent::SetZoomingSensitivity(float zoomingSensitivity)
{
m_zoomingSensitivity = AZ::GetMax(zoomingSensitivity, 0.0f);
}
AZ::Vector3 ArcBallControllerComponent::GetCenter()
{
return m_center;
}
AZ::Vector3 ArcBallControllerComponent::GetPan()
{
return m_panningOffset;
}
float ArcBallControllerComponent::GetDistance()
{
return m_distance;
}
float ArcBallControllerComponent::GetMinDistance()
{
return m_minDistance;
}
float ArcBallControllerComponent::GetMaxDistance()
{
return m_maxDistance;
}
float ArcBallControllerComponent::GetHeading()
{
return m_currentHeading;
}
float ArcBallControllerComponent::GetPitch()
{
return m_currentPitch;
}
float ArcBallControllerComponent::GetPanningSensitivity()
{
return m_panningSensitivity;
}
float ArcBallControllerComponent::GetZoomingSensitivity()
{
return m_zoomingSensitivity;
}
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,272 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Atom/Component/DebugCamera/CameraComponent.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/IO/IOUtils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Math/MatrixUtils.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/WindowContext.h>
namespace AZ
{
namespace Debug
{
void CameraComponentConfig::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<CameraComponentConfig, AZ::ComponentConfig>()
->Version(1)
->Field("FovY", &CameraComponentConfig::m_fovY)
->Field("DepthNear", &CameraComponentConfig::m_depthNear)
->Field("DepthFar", &CameraComponentConfig::m_depthFar)
->Field("AspectRatioOverride", &CameraComponentConfig::m_aspectRatioOverride)
;
}
}
void CameraComponent::Reflect(AZ::ReflectContext* context)
{
CameraComponentConfig::Reflect(context);
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<CameraComponent, AZ::Component>()
->Version(1)
->Field("Config", &CameraComponent::m_componentConfig)
;
}
}
void CameraComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
void CameraComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("CameraService", 0x1dd1caa4));
}
void CameraComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("CameraService", 0x1dd1caa4));
}
void CameraComponent::Activate()
{
AZ::Name viewName = GetEntity() ?
AZ::Name(AZStd::string::format("Camera View (entity: \"%s\")", GetEntity()->GetName().c_str())) :
AZ::Name("Camera view (unknown entity)");
m_view = RPI::View::CreateView(viewName, RPI::View::UsageCamera);
m_auxGeomFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity<RPI::AuxGeomFeatureProcessorInterface>(GetEntityId());
if (m_auxGeomFeatureProcessor)
{
m_auxGeomFeatureProcessor->GetOrCreateDrawQueueForView(m_view.get());
}
//Get transform at start
Transform transform;
TransformBus::BroadcastResult(transform, &TransformBus::Events::GetWorldTM);
OnTransformChanged(transform, transform);
TransformNotificationBus::Handler::BusConnect(GetEntityId());
RPI::ViewProviderBus::Handler::BusConnect(GetEntityId());
Camera::CameraRequestBus::Handler::BusConnect(GetEntityId());
Camera::CameraNotificationBus::Broadcast(&Camera::CameraNotificationBus::Events::OnCameraAdded, GetEntityId());
}
void CameraComponent::Deactivate()
{
Camera::CameraNotificationBus::Broadcast(&Camera::CameraNotificationBus::Events::OnCameraRemoved, GetEntityId());
Camera::CameraRequestBus::Handler::BusDisconnect();
RPI::ViewProviderBus::Handler::BusDisconnect();
TransformNotificationBus::Handler::BusDisconnect();
RPI::WindowContextNotificationBus::Handler::BusDisconnect();
if (m_auxGeomFeatureProcessor)
{
m_auxGeomFeatureProcessor->ReleaseDrawQueueForView(m_view.get());
}
m_view = nullptr;
m_auxGeomFeatureProcessor = nullptr;
}
RPI::ViewPtr CameraComponent::GetView() const
{
return m_view;
}
bool CameraComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
auto config = azrtti_cast<const CameraComponentConfig*>(baseConfig);
if (config != nullptr)
{
m_componentConfig = *config;
if (config->m_target != nullptr)
{
RPI::WindowContextNotificationBus::Handler::BusConnect(m_componentConfig.m_target->GetWindowHandle());
}
UpdateAspectRatio();
return true;
}
return false;
}
bool CameraComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
auto config = azrtti_cast<CameraComponentConfig*>(outBaseConfig);
if (config != nullptr)
{
*config = m_componentConfig;
return true;
}
return false;
}
void CameraComponent::OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world)
{
AZ_UNUSED(local);
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromTransform(world));
UpdateViewToClipMatrix();
}
float CameraComponent::GetFovDegrees()
{
return RadToDeg(m_componentConfig.m_fovY);
}
float CameraComponent::GetFovRadians()
{
return m_componentConfig.m_fovY;
}
float CameraComponent::GetNearClipDistance()
{
return m_componentConfig.m_depthNear;
}
float CameraComponent::GetFarClipDistance()
{
return m_componentConfig.m_depthFar;
}
float CameraComponent::GetFrustumWidth()
{
return m_componentConfig.m_depthFar * tanf(m_componentConfig.m_fovY / 2) * m_aspectRatio * 2;
}
float CameraComponent::GetFrustumHeight()
{
return m_componentConfig.m_depthFar * tanf(m_componentConfig.m_fovY / 2) * 2;
}
void CameraComponent::SetFovDegrees(float fov)
{
m_componentConfig.m_fovY = DegToRad(fov);
UpdateViewToClipMatrix();
}
void CameraComponent::SetFovRadians(float fov)
{
m_componentConfig.m_fovY = fov;
UpdateViewToClipMatrix();
}
void CameraComponent::SetNearClipDistance(float nearClipDistance)
{
m_componentConfig.m_depthNear = nearClipDistance;
UpdateViewToClipMatrix();
}
void CameraComponent::SetFarClipDistance(float farClipDistance)
{
m_componentConfig.m_depthFar = farClipDistance;
UpdateViewToClipMatrix();
}
void CameraComponent::SetFrustumWidth(float width)
{
AZ_Assert(m_componentConfig.m_depthFar > 0.f, "Depth Far has to be positive.");
AZ_Assert(m_aspectRatio > 0.f, "Aspect ratio must be positive.");
const float height = width / m_aspectRatio;
m_componentConfig.m_fovY = atanf(height / 2 / m_componentConfig.m_depthFar) * 2;
UpdateViewToClipMatrix();
}
void CameraComponent::SetFrustumHeight(float height)
{
AZ_Assert(m_componentConfig.m_depthFar > 0.f, "Depth Far has to be positive.");
m_componentConfig.m_fovY = atanf(height / 2 / m_componentConfig.m_depthFar) * 2;
UpdateViewToClipMatrix();
}
void CameraComponent::MakeActiveView()
{
// do nothing
}
void CameraComponent::OnViewportResized(uint32_t width, uint32_t height)
{
AZ_UNUSED(width)
AZ_UNUSED(height)
UpdateAspectRatio();
UpdateViewToClipMatrix();
}
void CameraComponent::UpdateAspectRatio()
{
if (m_componentConfig.m_aspectRatioOverride > 0.0f)
{
m_aspectRatio = m_componentConfig.m_aspectRatioOverride;
}
else if (m_componentConfig.m_target)
{
const auto& viewport = m_componentConfig.m_target->GetViewport();
m_aspectRatio = viewport.m_maxX / viewport.m_maxY;
}
}
void CameraComponent::UpdateViewToClipMatrix()
{
// Note: This is projection assumes a setup for reversed depth
AZ::Matrix4x4 viewToClipMatrix;
MakePerspectiveFovMatrixRH(viewToClipMatrix,
m_componentConfig.m_fovY,
m_aspectRatio,
m_componentConfig.m_depthNear,
m_componentConfig.m_depthFar, true);
m_view->SetViewToClipMatrix(viewToClipMatrix);
}
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,96 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Atom/Component/DebugCamera/CameraControllerComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
namespace Debug
{
void CameraControllerComponent::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<CameraControllerComponent, AZ::Component>()
->Version(1);
}
}
void CameraControllerComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
required.push_back(AZ_CRC("CameraService", 0x1dd1caa4));
}
void CameraControllerComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("CameraControllerService", 0xc35788f9));
}
void CameraControllerComponent::Enable(TypeId typeId)
{
// Enable this controller if type id matches, otherwise disable this controller
if (typeId == RTTI_GetType())
{
if (!m_enabled)
{
m_enabled = true;
OnEnabled();
}
}
else
{
if (m_enabled)
{
m_enabled = false;
OnDisabled();
}
}
}
void CameraControllerComponent::Disable()
{
if (m_enabled)
{
m_enabled = false;
OnDisabled();
}
}
void CameraControllerComponent::Reset()
{
if (m_enabled)
{
OnDisabled();
OnEnabled();
}
}
void CameraControllerComponent::Activate()
{
CameraControllerRequestBus::Handler::BusConnect(GetEntityId());
}
void CameraControllerComponent::Deactivate()
{
if (m_enabled)
{
m_enabled = false;
OnDisabled();
}
CameraControllerRequestBus::Handler::BusDisconnect();
}
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,43 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <DebugCameraUtils.h>
#include <AzCore/Math/MathUtils.h>
namespace AZ
{
namespace Debug
{
void ApplyMomentum(float& oldValue, float& newValue, float deltaTime)
{
float blendedValue;
blendedValue = AZ::Lerp(newValue, oldValue, deltaTime);
oldValue = blendedValue;
newValue = blendedValue;
}
float NormalizeAngle(float angle)
{
if (angle > AZ::Constants::Pi)
{
angle -= AZ::Constants::TwoPi;
}
else if (angle < -AZ::Constants::Pi)
{
angle += AZ::Constants::TwoPi;
}
return angle;
}
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,22 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
namespace AZ
{
namespace Debug
{
void ApplyMomentum(float& oldValue, float& newValue, float deltaTime);
float NormalizeAngle(float angle);
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,54 @@
/*
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution(the "License").All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file.Do not
* remove or modify any license notices.This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Module/Module.h>
#include <Atom/Component/DebugCamera/ArcBallControllerComponent.h>
#include <Atom/Component/DebugCamera/CameraComponent.h>
#include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
namespace AZ
{
namespace Debug
{
class CameraModule
: public AZ::Module
{
public:
AZ_RTTI(DebugCameraModule, "{C4F5D301-5C7F-42C2-8326-08F685B2D7A3}", AZ::Module);
CameraModule()
{
m_descriptors.insert(m_descriptors.end(), {
ArcBallControllerComponent::CreateDescriptor(),
CameraComponent::CreateDescriptor(),
NoClipControllerComponent::CreateDescriptor(),
});
}
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList GetRequiredSystemComponents() const override
{
AZ::ComponentTypeList required;
return required;
}
};
} // namespace Debug
} // namespace AZ
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
AZ_DECLARE_MODULE_CLASS(Gem_Atom_Component_DebugCamera, AZ::Debug::CameraModule)
@@ -0,0 +1,474 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h>
#include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
#include <AzFramework/Components/CameraBus.h>
#include <DebugCameraUtils.h>
namespace AZ
{
namespace Debug
{
const AzFramework::InputChannelId NoClipControllerComponent::TouchEvent::InvalidTouchChannelId = AzFramework::InputChannelId("InvalidChannel");
static constexpr float MaxFov = 160.0f * Constants::Pi / 180.0f;
static constexpr float MinFov = 1.0f * Constants::Pi / 180.0f;
static constexpr float DefaultFov = Constants::QuarterPi;
void NoClipControllerProperties::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<NoClipControllerProperties>()
->Version(2)
->Field("Mouse Sensitivity X", &NoClipControllerProperties::m_mouseSensitivityX)
->Field("Mouse Sensitivity Y", &NoClipControllerProperties::m_mouseSensitivityY)
->Field("Move Speed", &NoClipControllerProperties::m_moveSpeed)
->Field("Panning Speed", &NoClipControllerProperties::m_panningSpeed)
->Field("Touch Sensitivity", &NoClipControllerProperties::m_touchSensitivity);
}
}
NoClipControllerComponent::NoClipControllerComponent()
: AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault())
{}
void NoClipControllerComponent::Reflect(AZ::ReflectContext* reflection)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<NoClipControllerComponent, CameraControllerComponent, AZ::Component>()
->Version(1)
->Field("Properties", &NoClipControllerComponent::m_properties);
}
}
void NoClipControllerComponent::OnEnabled()
{
// Reset parameters
m_mouseLookEnabled = false;
m_inputStates = 0;
m_currentHeading = 0.0f;
m_currentPitch = 0.0f;
m_currentFov = DefaultFov;
m_lastForward = 0.0f;
m_lastStrafe = 0.0f;
m_lastAscent = 0.0f;
NoClipControllerRequestBus::Handler::BusConnect(GetEntityId());
AzFramework::InputChannelEventListener::Connect();
AZ::TickBus::Handler::BusConnect();
}
void NoClipControllerComponent::OnDisabled()
{
TickBus::Handler::BusDisconnect();
AzFramework::InputChannelEventListener::Disconnect();
NoClipControllerRequestBus::Handler::BusDisconnect();
// Reset the Fov to default.
Camera::CameraRequestBus::Event(GetEntityId(), &Camera::CameraRequestBus::Events::SetFovRadians, DefaultFov);
}
void NoClipControllerComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time)
{
AZ_UNUSED(time);
static const float normalSpeed = 3.0f;
static const float sprintSpeed = 10.0f;
float speedFactor = m_inputStates[CameraKeys::FastMode] ? sprintSpeed : normalSpeed;
float forward = m_properties.m_moveSpeed * speedFactor * (
(m_inputStates[CameraKeys::Forward] ? deltaTime : 0.0f) +
(m_inputStates[CameraKeys::Back] ? -deltaTime : 0.0f));
float strafe = m_properties.m_panningSpeed * speedFactor * (
(m_inputStates[CameraKeys::Right] ? deltaTime : 0.0f) +
(m_inputStates[CameraKeys::Left] ? -deltaTime : 0.0f));
float ascent = m_properties.m_panningSpeed * speedFactor * (
(m_inputStates[CameraKeys::Up] ? deltaTime : 0.0f) +
(m_inputStates[CameraKeys::Down] ? -deltaTime : 0.0f));
ApplyMomentum(m_lastForward, forward, deltaTime);
ApplyMomentum(m_lastStrafe, strafe, deltaTime);
ApplyMomentum(m_lastAscent, ascent, deltaTime);
AZ::Vector3 worldPosition;
AZ::TransformBus::EventResult(
worldPosition, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation);
// The coordinate system is right-handed and Z-up. So heading is a rotation around the Z axis.
// After that rotation we rotate around the (rotated by heading) X axis for pitch.
AZ::Quaternion orientation = AZ::Quaternion::CreateRotationZ(m_currentHeading)
* AZ::Quaternion::CreateRotationX(m_currentPitch);
AZ::Vector3 position = orientation.TransformVector(AZ::Vector3(strafe, forward, ascent)) + worldPosition;
AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(orientation, position);
AZ::TransformBus::Event(
GetEntityId(), &AZ::TransformBus::Events::SetWorldTM, transform);
Camera::CameraRequestBus::Event(GetEntityId(), &Camera::CameraRequestBus::Events::SetFovRadians, m_currentFov);
}
bool NoClipControllerComponent::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
{
static const auto KeyCount = static_cast<uint32_t>(CameraKeys::Count);
static const float PixelToDegree = 1.0 / 360.0f;
static const AzFramework::InputChannelId CameraInputMap[KeyCount] =
{
AzFramework::InputDeviceKeyboard::Key::AlphanumericW, // Forward
AzFramework::InputDeviceKeyboard::Key::AlphanumericS, // Back
AzFramework::InputDeviceKeyboard::Key::AlphanumericA, // Left
AzFramework::InputDeviceKeyboard::Key::AlphanumericD, // Right
AzFramework::InputDeviceKeyboard::Key::AlphanumericQ, // Up
AzFramework::InputDeviceKeyboard::Key::AlphanumericE, // Down
AzFramework::InputDeviceKeyboard::Key::ModifierShiftL, // FastMode
};
static const AzFramework::InputChannelId CameraGamepadInputMap[KeyCount] =
{
AzFramework::InputDeviceGamepad::Button::DU, // Forward
AzFramework::InputDeviceGamepad::Button::DD, // Back
AzFramework::InputDeviceGamepad::Button::DL, // Left
AzFramework::InputDeviceGamepad::Button::DR, // Right
AzFramework::InputDeviceGamepad::Button::R1, // Up
AzFramework::InputDeviceGamepad::Button::L1, // Down
AzFramework::InputDeviceGamepad::Trigger::R2, // FastMode
};
uint32_t handledChannels = NoClipControllerChannel_None;
const AzFramework::InputChannelId& inputChannelId = inputChannel.GetInputChannelId();
switch (inputChannel.GetState())
{
case AzFramework::InputChannel::State::Began:
case AzFramework::InputChannel::State::Updated: // update the camera rotation
{
//Keyboard & Mouse
if (m_mouseLookEnabled && inputChannelId == AzFramework::InputDeviceMouse::Movement::X)
{
// modify yaw angle
m_currentHeading -= inputChannel.GetValue() * m_properties.m_mouseSensitivityX * PixelToDegree;
m_currentHeading = NormalizeAngle(m_currentHeading);
}
else if (m_mouseLookEnabled && inputChannelId == AzFramework::InputDeviceMouse::Movement::Y)
{
// modify pitch angle
m_currentPitch -= inputChannel.GetValue() * m_properties.m_mouseSensitivityY * PixelToDegree;
m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
}
else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Z)
{
// modify field of view
m_currentFov = GetClamp(m_currentFov - inputChannel.GetValue() * 0.0005f * m_currentFov, MinFov, MaxFov);
handledChannels |= NoClipControllerChannel_Fov;
}
else if (inputChannelId == AzFramework::InputDeviceMouse::Button::Right)
{
m_mouseLookEnabled = true;
handledChannels |= NoClipControllerChannel_Orientation;
}
else
{
for (uint32_t i = 0; i < KeyCount; ++i)
{
if (inputChannelId == CameraInputMap[i])
{
m_inputStates[i] = true;
if (i != CameraKeys::FastMode)
{
handledChannels |= NoClipControllerChannel_Position;
}
break;
}
}
}
// Gamepad
if (inputChannelId == AzFramework::InputDeviceGamepad::Trigger::L2)
{
m_mouseLookEnabled = true;
handledChannels |= NoClipControllerChannel_Orientation;
}
else if (m_mouseLookEnabled)
{
if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RX)
{
// modify yaw angle
m_currentHeading -= inputChannel.GetValue() * m_properties.m_mouseSensitivityX * PixelToDegree;
m_currentHeading = NormalizeAngle(m_currentHeading);
}
else if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RY)
{
// modify pitch angle
m_currentPitch += inputChannel.GetValue() * m_properties.m_mouseSensitivityY * PixelToDegree;
m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
}
for (uint32_t i = 0; i < KeyCount; ++i)
{
if (inputChannelId == CameraGamepadInputMap[i])
{
m_inputStates[i] = true;
if (i != CameraKeys::FastMode)
{
handledChannels |= NoClipControllerChannel_Position;
}
break;
}
}
}
// Touch controls works like two virtual joysticks.
// The left "joystick" controls forward/backward/left and right movements.
// The right "joystick" controls the camera heading and pitch.
// There's no control to move up and down.
if (inputChannelId == AzFramework::InputDeviceTouch::Touch::Index0 || inputChannelId == AzFramework::InputDeviceTouch::Touch::Index1)
{
auto* positionData = inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
AZ::Vector2 screenPos = positionData->m_normalizedPosition;
const float deadZone = 0.07f;
if (inputChannelId == m_mouseLookTouch.m_channelId)
{
// modify yaw angle
AZ::Vector2 deltaPos = screenPos - m_mouseLookTouch.m_initialPos;
AZ::Vector2 inputValue = AZ::Vector2(fabsf(deltaPos.GetX()) > deadZone ? 1.0f : 0, fabsf(deltaPos.GetY()) > deadZone ? 1.0f : 0);
m_currentHeading -= inputValue.GetX() * AZ::GetSign(deltaPos.GetX()) * m_properties.m_touchSensitivity * m_properties.m_mouseSensitivityX * PixelToDegree;
m_currentHeading = NormalizeAngle(m_currentHeading);
// modify pitch angle
m_currentPitch -= inputValue.GetY() * AZ::GetSign(deltaPos.GetY()) * m_properties.m_touchSensitivity * m_properties.m_mouseSensitivityY * PixelToDegree;
m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
handledChannels |= NoClipControllerChannel_Orientation;
}
else if (inputChannelId == m_movementTouch.m_channelId)
{
AZ::Vector2 deltaPos = screenPos - m_movementTouch.m_initialPos;
m_inputStates[Forward] = deltaPos.GetY() < -deadZone ? true : false;
m_inputStates[Back] = deltaPos.GetY() > deadZone ? true : false;
m_inputStates[Left] = deltaPos.GetX() < -deadZone ? true : false;
m_inputStates[Right] = deltaPos.GetX() > deadZone ? true : false;
handledChannels |= NoClipControllerChannel_Position;
}
else
{
bool isMouseLook = (screenPos.GetX() > 0.5);
auto& touchEvent = isMouseLook ? m_mouseLookTouch : m_movementTouch;
if (touchEvent.m_channelId == TouchEvent::InvalidTouchChannelId)
{
touchEvent.m_channelId = inputChannelId;
touchEvent.m_initialPos = screenPos;
}
if (isMouseLook)
{
handledChannels |= NoClipControllerChannel_Orientation;
}
else
{
handledChannels |= NoClipControllerChannel_Position;
}
}
}
if (handledChannels && AzFramework::InputChannel::State::Began == inputChannel.GetState())
{
CameraControllerNotificationBus::Broadcast(&CameraControllerNotifications::OnCameraMoveBegan, RTTI_GetType(), handledChannels);
}
break;
}
case AzFramework::InputChannel::State::Ended: // update the released input state
{
if (inputChannelId == AzFramework::InputDeviceMouse::Button::Right)
{
m_mouseLookEnabled = false;
handledChannels |= NoClipControllerChannel_Orientation;
}
else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Z)
{
handledChannels |= NoClipControllerChannel_Fov;
}
else if (inputChannelId == AzFramework::InputDeviceGamepad::Trigger::L2)
{
m_mouseLookEnabled = false;
handledChannels |= NoClipControllerChannel_Orientation;
// On gamepads, Trigger::L2 also indicates positional movement, see above.
handledChannels |= NoClipControllerChannel_Position;
}
else if (inputChannelId == m_movementTouch.m_channelId)
{
m_movementTouch.m_channelId = TouchEvent::InvalidTouchChannelId;
for (uint32_t i = 0; i < KeyCount; ++i)
{
m_inputStates[i] = false;
if (i != CameraKeys::FastMode)
{
handledChannels |= NoClipControllerChannel_Position;
}
}
}
else if (inputChannelId == m_mouseLookTouch.m_channelId)
{
m_mouseLookTouch.m_channelId = TouchEvent::InvalidTouchChannelId;
handledChannels |= NoClipControllerChannel_Orientation;
}
else
{
for (uint32_t i = 0; i < KeyCount; ++i)
{
if (inputChannelId == CameraInputMap[i] || inputChannelId == CameraGamepadInputMap[i])
{
m_inputStates[i] = false;
if (i != CameraKeys::FastMode)
{
handledChannels |= NoClipControllerChannel_Position;
}
break;
}
}
}
if (handledChannels)
{
CameraControllerNotificationBus::Broadcast(&CameraControllerNotifications::OnCameraMoveEnded, RTTI_GetType(), handledChannels);
}
break;
}
default:
{
break;
}
}
return false;
}
void NoClipControllerComponent::SetMouseSensitivityX(float mouseSensitivityX)
{
m_properties.m_mouseSensitivityX = mouseSensitivityX;
}
void NoClipControllerComponent::SetMouseSensitivityY(float mouseSensitivityY)
{
m_properties.m_mouseSensitivityY = mouseSensitivityY;
}
void NoClipControllerComponent::SetMoveSpeed(float moveSpeed)
{
m_properties.m_moveSpeed = moveSpeed;
}
void NoClipControllerComponent::SetPanningSpeed(float panningSpeed)
{
m_properties.m_panningSpeed = panningSpeed;
}
void NoClipControllerComponent::SetControllerProperties(const NoClipControllerProperties& properties)
{
m_properties = properties;
}
void NoClipControllerComponent::SetTouchSensitivity([[maybe_unused]] float touchSensitivity)
{
m_properties.m_touchSensitivity;
}
void NoClipControllerComponent::SetPosition(AZ::Vector3 position)
{
AZ::TransformBus::Event(GetEntityId(), &AZ::TransformBus::Events::SetWorldTranslation, position);
}
void NoClipControllerComponent::SetHeading(float heading)
{
m_currentHeading = heading;
m_currentHeading = NormalizeAngle(m_currentHeading);
}
void NoClipControllerComponent::SetPitch(float pitch)
{
m_currentPitch = pitch;
m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
}
void NoClipControllerComponent::SetFov(float fov)
{
m_currentFov = GetClamp(fov, MinFov, MaxFov);
}
float NoClipControllerComponent::GetMouseSensitivityX()
{
return m_properties.m_mouseSensitivityX;
}
float NoClipControllerComponent::GetMouseSensitivityY()
{
return m_properties.m_mouseSensitivityY;
}
float NoClipControllerComponent::GetMoveSpeed()
{
return m_properties.m_moveSpeed;
}
float NoClipControllerComponent::GetPanningSpeed()
{
return m_properties.m_panningSpeed;
}
float NoClipControllerComponent::GetTouchSensitivity()
{
return m_properties.m_touchSensitivity;
}
NoClipControllerProperties NoClipControllerComponent::GetControllerProperties()
{
return m_properties;
}
AZ::Vector3 NoClipControllerComponent::GetPosition()
{
AZ::Vector3 position;
AZ::TransformBus::EventResult(position, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation);
return position;
}
float NoClipControllerComponent::GetHeading()
{
return m_currentHeading;
}
float NoClipControllerComponent::GetPitch()
{
return m_currentPitch;
}
float NoClipControllerComponent::GetFov()
{
return m_currentFov;
}
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,26 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Include/Atom/Component/DebugCamera/ArcBallControllerBus.h
Include/Atom/Component/DebugCamera/ArcBallControllerComponent.h
Include/Atom/Component/DebugCamera/CameraComponent.h
Include/Atom/Component/DebugCamera/CameraControllerBus.h
Include/Atom/Component/DebugCamera/CameraControllerComponent.h
Include/Atom/Component/DebugCamera/NoClipControllerBus.h
Include/Atom/Component/DebugCamera/NoClipControllerComponent.h
Source/ArcBallControllerComponent.cpp
Source/CameraComponent.cpp
Source/CameraControllerComponent.cpp
Source/DebugCameraUtils.cpp
Source/DebugCameraUtils.h
Source/NoClipControllerComponent.cpp
)
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Source/Module.cpp
)