Atom Tools: Extracted the viewport input controller from ME to ATF
These viewport controls will be shared with material canvas and other tools that share a similar environment and viewport configurations. These classes are currently duplicated between the material editor and prototype projects. This change generalizes some things that are specific to the material editor and moves the system to a common location. Event buses were removed and replaced with a normal interface. Signed-off-by: Guthrie Adams <guthadam@amazon.com>
This commit is contained in:
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Viewport/ViewportInputBehaviorController/DollyCameraBehavior.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehaviorControllerInterface.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
DollyCameraBehavior::DollyCameraBehavior(ViewportInputBehaviorControllerInterface* controller)
|
||||
: ViewportInputBehavior(controller)
|
||||
{
|
||||
}
|
||||
|
||||
void DollyCameraBehavior::TickInternal([[maybe_unused]] float x, float y, [[maybe_unused]] float z)
|
||||
{
|
||||
m_distanceToTarget = m_distanceToTarget + y;
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
AZ::Vector3 position = m_targetPosition - transform.GetRotation().TransformVector(AZ::Vector3::CreateAxisY(m_distanceToTarget));
|
||||
AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalTranslation, position);
|
||||
}
|
||||
|
||||
float DollyCameraBehavior::GetSensitivityX()
|
||||
{
|
||||
return SensitivityX;
|
||||
}
|
||||
|
||||
float DollyCameraBehavior::GetSensitivityY()
|
||||
{
|
||||
return SensitivityY;
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Viewport/ViewportInputBehaviorController/MoveCameraBehavior.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehaviorControllerInterface.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
MoveCameraBehavior::MoveCameraBehavior(ViewportInputBehaviorControllerInterface* controller)
|
||||
: ViewportInputBehavior(controller)
|
||||
{
|
||||
}
|
||||
|
||||
void MoveCameraBehavior::End()
|
||||
{
|
||||
float distanceToTarget = m_controller->GetDistanceToTarget();
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
AZ::Vector3 targetPosition = transform.GetTranslation() + transform.GetBasisY() * distanceToTarget;
|
||||
m_controller->SetTargetPosition(targetPosition);
|
||||
}
|
||||
|
||||
void MoveCameraBehavior::TickInternal(float x, float y, float z)
|
||||
{
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
AZ::Vector3 up = transform.GetBasisZ();
|
||||
AZ::Vector3 right = transform.GetBasisX();
|
||||
AZ::Vector3 position = transform.GetTranslation();
|
||||
AZ::Vector3 deltaPosition = up * y + right * -x;
|
||||
position += deltaPosition;
|
||||
m_targetPosition += deltaPosition;
|
||||
AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalTranslation, position);
|
||||
|
||||
ViewportInputBehavior::TickInternal(x, y, z);
|
||||
}
|
||||
|
||||
float MoveCameraBehavior::GetSensitivityX()
|
||||
{
|
||||
return SensitivityX;
|
||||
}
|
||||
|
||||
float MoveCameraBehavior::GetSensitivityY()
|
||||
{
|
||||
return SensitivityY;
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Viewport/ViewportInputBehaviorController/OrbitCameraBehavior.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehaviorControllerInterface.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
OrbitCameraBehavior::OrbitCameraBehavior(ViewportInputBehaviorControllerInterface* controller)
|
||||
: ViewportInputBehavior(controller)
|
||||
{
|
||||
}
|
||||
|
||||
void OrbitCameraBehavior::TickInternal(float x, float y, float z)
|
||||
{
|
||||
ViewportInputBehavior::TickInternal(x, y, z);
|
||||
|
||||
// don't align camera until a movement has been made so that accidental right-click doesn't reset camera
|
||||
if (!m_aligned)
|
||||
{
|
||||
Align();
|
||||
}
|
||||
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
AZ::Quaternion rotation = transform.GetRotation();
|
||||
AZ::Vector3 right = transform.GetBasisX();
|
||||
rotation =
|
||||
AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), -x) * AZ::Quaternion::CreateFromAxisAngle(right, -y) * rotation;
|
||||
rotation.Normalize();
|
||||
AZ::Vector3 position = rotation.TransformVector(AZ::Vector3(0, -m_distanceToTarget, 0)) + m_targetPosition;
|
||||
transform = AZ::Transform::CreateFromQuaternionAndTranslation(rotation, position);
|
||||
AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalTM, transform);
|
||||
}
|
||||
|
||||
float OrbitCameraBehavior::GetSensitivityX()
|
||||
{
|
||||
return SensitivityX;
|
||||
}
|
||||
|
||||
float OrbitCameraBehavior::GetSensitivityY()
|
||||
{
|
||||
return SensitivityY;
|
||||
}
|
||||
|
||||
void OrbitCameraBehavior::Align()
|
||||
{
|
||||
AZ::Vector3 cameraPosition = AZ::Vector3::CreateZero();
|
||||
AZ::TransformBus::EventResult(cameraPosition, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTranslation);
|
||||
const AZ::Vector3 delta = m_targetPosition - cameraPosition;
|
||||
AZ::Quaternion targetRotation = LookRotation(delta);
|
||||
AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, targetRotation);
|
||||
m_aligned = true;
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Viewport/ViewportInputBehaviorController/PanCameraBehavior.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehaviorControllerInterface.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
PanCameraBehavior::PanCameraBehavior(ViewportInputBehaviorControllerInterface* controller)
|
||||
: ViewportInputBehavior(controller)
|
||||
{
|
||||
}
|
||||
|
||||
void PanCameraBehavior::End()
|
||||
{
|
||||
float distanceToTarget = m_controller->GetDistanceToTarget();
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
AZ::Vector3 targetPosition = transform.GetTranslation() + transform.GetBasisY() * distanceToTarget;
|
||||
m_controller->SetTargetPosition(targetPosition);
|
||||
}
|
||||
|
||||
void PanCameraBehavior::TickInternal(float x, float y, [[maybe_unused]] float z)
|
||||
{
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
AZ::Quaternion rotation = transform.GetRotation();
|
||||
const AZ::Vector3 right = transform.GetBasisX();
|
||||
rotation =
|
||||
AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), -x) * AZ::Quaternion::CreateFromAxisAngle(right, -y) * rotation;
|
||||
rotation.Normalize();
|
||||
AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, rotation);
|
||||
}
|
||||
|
||||
float PanCameraBehavior::GetSensitivityX()
|
||||
{
|
||||
return SensitivityX;
|
||||
}
|
||||
|
||||
float PanCameraBehavior::GetSensitivityY()
|
||||
{
|
||||
return SensitivityY;
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/RotateEnvironmentBehavior.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehaviorControllerInterface.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
RotateEnvironmentBehavior::RotateEnvironmentBehavior(ViewportInputBehaviorControllerInterface* controller)
|
||||
: ViewportInputBehavior(controller)
|
||||
{
|
||||
}
|
||||
|
||||
void RotateEnvironmentBehavior::Start()
|
||||
{
|
||||
ViewportInputBehavior::Start();
|
||||
|
||||
m_environmentEntityId = m_controller->GetEnvironmentEntityId();
|
||||
AZ_Assert(m_environmentEntityId.IsValid(), "Failed to find m_environmentEntityId");
|
||||
m_skyBoxFeatureProcessor =
|
||||
AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::Render::SkyBoxFeatureProcessorInterface>(m_environmentEntityId);
|
||||
}
|
||||
|
||||
void RotateEnvironmentBehavior::TickInternal(float x, float y, float z)
|
||||
{
|
||||
ViewportInputBehavior::TickInternal(x, y, z);
|
||||
|
||||
m_rotation += x;
|
||||
AZ::Quaternion rotation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), m_rotation);
|
||||
AZ::TransformBus::Event(m_environmentEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, rotation);
|
||||
const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateFromQuaternion(rotation);
|
||||
m_skyBoxFeatureProcessor->SetCubemapRotationMatrix(rotationMatrix);
|
||||
}
|
||||
|
||||
float RotateEnvironmentBehavior::GetSensitivityX()
|
||||
{
|
||||
return SensitivityX;
|
||||
}
|
||||
|
||||
float RotateEnvironmentBehavior::GetSensitivityY()
|
||||
{
|
||||
return SensitivityY;
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Viewport/ViewportInputBehaviorController/RotateModelBehavior.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehaviorControllerInterface.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
RotateModelBehavior::RotateModelBehavior(ViewportInputBehaviorControllerInterface* controller)
|
||||
: ViewportInputBehavior(controller)
|
||||
{
|
||||
}
|
||||
|
||||
void RotateModelBehavior::Start()
|
||||
{
|
||||
ViewportInputBehavior::Start();
|
||||
|
||||
m_targetEntityId = m_controller->GetTargetEntityId();
|
||||
AZ_Assert(m_targetEntityId.IsValid(), "Failed to find m_targetEntityId");
|
||||
|
||||
AZ::EntityId cameraEntityId = m_controller->GetCameraEntityId();
|
||||
AZ_Assert(cameraEntityId.IsValid(), "Failed to find cameraEntityId");
|
||||
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, cameraEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
m_cameraRight = transform.GetBasisX();
|
||||
}
|
||||
|
||||
void RotateModelBehavior::TickInternal(float x, float y, float z)
|
||||
{
|
||||
ViewportInputBehavior::TickInternal(x, y, z);
|
||||
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_targetEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
|
||||
AZ::Quaternion rotation = transform.GetRotation();
|
||||
rotation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), x) *
|
||||
AZ::Quaternion::CreateFromAxisAngle(m_cameraRight, y) * rotation;
|
||||
rotation.Normalize();
|
||||
|
||||
AZ::TransformBus::Event(m_targetEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, rotation);
|
||||
}
|
||||
|
||||
float RotateModelBehavior::GetSensitivityX()
|
||||
{
|
||||
return SensitivityX;
|
||||
}
|
||||
|
||||
float RotateModelBehavior::GetSensitivityY()
|
||||
{
|
||||
return SensitivityY;
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehavior.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehaviorControllerInterface.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
ViewportInputBehavior::ViewportInputBehavior(ViewportInputBehaviorControllerInterface* controller)
|
||||
: m_controller(controller)
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
ViewportInputBehavior::~ViewportInputBehavior()
|
||||
{
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void ViewportInputBehavior::Start()
|
||||
{
|
||||
m_x = {};
|
||||
m_y = {};
|
||||
m_z = {};
|
||||
|
||||
m_cameraEntityId = m_controller->GetCameraEntityId();
|
||||
AZ_Assert(m_cameraEntityId.IsValid(), "Failed to find m_cameraEntityId");
|
||||
m_distanceToTarget = m_controller->GetDistanceToTarget();
|
||||
m_targetPosition = m_controller->GetTargetPosition();
|
||||
m_radius = m_controller->GetRadius();
|
||||
}
|
||||
|
||||
void ViewportInputBehavior::End()
|
||||
{
|
||||
}
|
||||
|
||||
void ViewportInputBehavior::MoveX(float value)
|
||||
{
|
||||
m_x += value * GetSensitivityX();
|
||||
}
|
||||
|
||||
void ViewportInputBehavior::MoveY(float value)
|
||||
{
|
||||
m_y += value * GetSensitivityY();
|
||||
}
|
||||
|
||||
void ViewportInputBehavior::MoveZ(float value)
|
||||
{
|
||||
m_z += value * GetSensitivityZ();
|
||||
}
|
||||
|
||||
bool ViewportInputBehavior::HasDelta() const
|
||||
{
|
||||
return AZ::GetAbs(m_x) > std::numeric_limits<float>::min() || AZ::GetAbs(m_y) > std::numeric_limits<float>::min() ||
|
||||
AZ::GetAbs(m_z) > std::numeric_limits<float>::min();
|
||||
}
|
||||
|
||||
void ViewportInputBehavior::TickInternal([[maybe_unused]] float x, [[maybe_unused]] float y, float z)
|
||||
{
|
||||
m_distanceToTarget = m_distanceToTarget - z;
|
||||
|
||||
bool isCameraCentered = m_controller->IsCameraCentered();
|
||||
|
||||
// if camera is looking at the model (locked to the model) we don't want to zoom past the model's center
|
||||
if (isCameraCentered)
|
||||
{
|
||||
m_distanceToTarget = AZ::GetMax(m_distanceToTarget, 0.0f);
|
||||
}
|
||||
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM);
|
||||
AZ::Vector3 position = m_targetPosition - transform.GetRotation().TransformVector(AZ::Vector3::CreateAxisY(m_distanceToTarget));
|
||||
AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalTranslation, position);
|
||||
|
||||
// if camera is not locked to the model, move its focal point so we can free look
|
||||
if (!isCameraCentered)
|
||||
{
|
||||
m_targetPosition += transform.GetRotation().TransformVector(AZ::Vector3::CreateAxisY(z));
|
||||
m_controller->SetTargetPosition(m_targetPosition);
|
||||
m_distanceToTarget = m_controller->GetDistanceToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
float ViewportInputBehavior::GetSensitivityX()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ViewportInputBehavior::GetSensitivityY()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ViewportInputBehavior::GetSensitivityZ()
|
||||
{
|
||||
// adjust zooming sensitivity by model size, so that large models zoom at the same speed as smaller ones
|
||||
return 0.001f * AZ::GetMax(0.5f, m_radius);
|
||||
}
|
||||
|
||||
AZ::Quaternion ViewportInputBehavior::LookRotation(AZ::Vector3 forward)
|
||||
{
|
||||
forward.Normalize();
|
||||
AZ::Vector3 right = forward.CrossZAxis();
|
||||
right.Normalize();
|
||||
AZ::Vector3 up = right.Cross(forward);
|
||||
up.Normalize();
|
||||
AZ::Quaternion rotation = AZ::Quaternion::CreateFromBasis(right, forward, up);
|
||||
rotation.Normalize();
|
||||
return rotation;
|
||||
}
|
||||
|
||||
float ViewportInputBehavior::TakeStep(float& value, float t)
|
||||
{
|
||||
const float absValue = AZ::GetAbs(value);
|
||||
float step;
|
||||
if (absValue < SnapInterval)
|
||||
{
|
||||
step = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
step = AZ::Lerp(0, value, t);
|
||||
}
|
||||
value -= step;
|
||||
return step;
|
||||
}
|
||||
|
||||
void ViewportInputBehavior::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
// delta x and y values are accumulated in MoveX and MoveY functions (by dragging the mouse)
|
||||
// in the Tick function we then lerp them down to 0 over short time and apply delta transform to an entity
|
||||
if (HasDelta())
|
||||
{
|
||||
// t is a lerp amount based on time between frames (deltaTime)
|
||||
// GetMin restricts how much we can lerp in case of low fps (and very high deltaTime)
|
||||
const float t = AZ::GetMin(deltaTime / LerpTime, 0.5f);
|
||||
const float x = TakeStep(m_x, t);
|
||||
const float y = TakeStep(m_y, t);
|
||||
const float z = TakeStep(m_z, t);
|
||||
TickInternal(x, y, z);
|
||||
}
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* 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 <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInputBehaviorController/ViewportInputBehaviorController.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/Matrix4x4.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/Components/CameraBus.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QWidget>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
ViewportInputBehaviorController::ViewportInputBehaviorController(
|
||||
const AZ::EntityId& cameraEntityId, const AZ::EntityId& targetEntityId, const AZ::EntityId& environmentEntityId)
|
||||
: AzFramework::SingleViewportController()
|
||||
, m_cameraEntityId(cameraEntityId)
|
||||
, m_targetEntityId(targetEntityId)
|
||||
, m_environmentEntityId(environmentEntityId)
|
||||
, m_targetPosition(AZ::Vector3::CreateZero())
|
||||
{
|
||||
}
|
||||
|
||||
ViewportInputBehaviorController::~ViewportInputBehaviorController()
|
||||
{
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::AddBehavior(KeyMask mask, AZStd::shared_ptr<ViewportInputBehavior> behavior)
|
||||
{
|
||||
m_behaviorMap[mask] = behavior;
|
||||
}
|
||||
|
||||
const AZ::EntityId& ViewportInputBehaviorController::GetCameraEntityId() const
|
||||
{
|
||||
return m_cameraEntityId;
|
||||
}
|
||||
|
||||
const AZ::EntityId& ViewportInputBehaviorController::GetTargetEntityId() const
|
||||
{
|
||||
return m_targetEntityId;
|
||||
}
|
||||
|
||||
const AZ::EntityId& ViewportInputBehaviorController::GetEnvironmentEntityId() const
|
||||
{
|
||||
return m_environmentEntityId;
|
||||
}
|
||||
|
||||
const AZ::Vector3& ViewportInputBehaviorController::GetTargetPosition() const
|
||||
{
|
||||
return m_targetPosition;
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::SetTargetPosition(const AZ::Vector3& targetPosition)
|
||||
{
|
||||
m_targetPosition = targetPosition;
|
||||
m_isCameraCentered = false;
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::SetTargetBounds(const AZ::Aabb& targetBounds)
|
||||
{
|
||||
m_targetBounds = targetBounds;
|
||||
}
|
||||
|
||||
float ViewportInputBehaviorController::GetDistanceToTarget() const
|
||||
{
|
||||
AZ::Vector3 cameraPosition;
|
||||
AZ::TransformBus::EventResult(cameraPosition, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTranslation);
|
||||
return cameraPosition.GetDistance(m_targetPosition);
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::GetExtents(float& distanceMin, float& distanceMax) const
|
||||
{
|
||||
distanceMin = m_distanceMin;
|
||||
distanceMax = m_distanceMax;
|
||||
}
|
||||
|
||||
float ViewportInputBehaviorController::GetRadius() const
|
||||
{
|
||||
return m_radius;
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
|
||||
{
|
||||
if (m_keysChanged)
|
||||
{
|
||||
if (m_timeToBehaviorSwitchMs > 0)
|
||||
{
|
||||
m_timeToBehaviorSwitchMs -= event.m_deltaTime.count();
|
||||
}
|
||||
if (m_timeToBehaviorSwitchMs <= 0)
|
||||
{
|
||||
EvaluateControlBehavior();
|
||||
m_keysChanged = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewportInputBehaviorController::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
|
||||
{
|
||||
using namespace AzFramework;
|
||||
|
||||
const InputChannelId& inputChannelId = event.m_inputChannel.GetInputChannelId();
|
||||
const InputChannel::State state = event.m_inputChannel.GetState();
|
||||
const KeyMask keysOld = m_keys;
|
||||
|
||||
bool mouseOver = false;
|
||||
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::EventResult(
|
||||
mouseOver, GetViewportId(), &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::IsMouseOver);
|
||||
|
||||
if (!m_behavior)
|
||||
{
|
||||
EvaluateControlBehavior();
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case InputChannel::State::Began:
|
||||
if (inputChannelId == InputDeviceMouse::Button::Left)
|
||||
{
|
||||
m_keys |= Lmb;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceMouse::Button::Middle)
|
||||
{
|
||||
m_keys |= Mmb;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceMouse::Button::Right)
|
||||
{
|
||||
m_keys |= Rmb;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceKeyboard::Key::ModifierAltL)
|
||||
{
|
||||
m_keys |= Alt;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceKeyboard::Key::ModifierCtrlL)
|
||||
{
|
||||
m_keys |= Ctrl;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceKeyboard::Key::ModifierShiftL)
|
||||
{
|
||||
m_keys |= Shift;
|
||||
}
|
||||
if (m_behavior && inputChannelId == InputDeviceMouse::Movement::X)
|
||||
{
|
||||
m_behavior->MoveX(event.m_inputChannel.GetValue());
|
||||
}
|
||||
else if (m_behavior && inputChannelId == InputDeviceMouse::Movement::Y)
|
||||
{
|
||||
m_behavior->MoveY(event.m_inputChannel.GetValue());
|
||||
}
|
||||
else if (m_behavior && inputChannelId == InputDeviceMouse::Movement::Z && mouseOver)
|
||||
{
|
||||
m_behavior->MoveZ(event.m_inputChannel.GetValue());
|
||||
}
|
||||
break;
|
||||
case InputChannel::State::Ended:
|
||||
if (inputChannelId == InputDeviceMouse::Button::Left)
|
||||
{
|
||||
m_keys &= ~Lmb;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceMouse::Button::Middle)
|
||||
{
|
||||
m_keys &= ~Mmb;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceMouse::Button::Right)
|
||||
{
|
||||
m_keys &= ~Rmb;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceKeyboard::Key::ModifierAltL)
|
||||
{
|
||||
m_keys &= ~Alt;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceKeyboard::Key::ModifierCtrlL)
|
||||
{
|
||||
m_keys &= ~Ctrl;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceKeyboard::Key::ModifierShiftL)
|
||||
{
|
||||
m_keys &= ~Shift;
|
||||
}
|
||||
else if (inputChannelId == InputDeviceKeyboard::Key::AlphanumericZ && (m_keys & Ctrl) == None)
|
||||
{
|
||||
// only reset camera if no other widget besides viewport is in focus
|
||||
const auto focus = QApplication::focusWidget();
|
||||
if (!focus || focus->objectName() == "Viewport")
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputChannel::State::Updated:
|
||||
if (m_behavior && inputChannelId == InputDeviceMouse::Movement::X)
|
||||
{
|
||||
m_behavior->MoveX(event.m_inputChannel.GetValue());
|
||||
}
|
||||
else if (m_behavior && inputChannelId == InputDeviceMouse::Movement::Y)
|
||||
{
|
||||
m_behavior->MoveY(event.m_inputChannel.GetValue());
|
||||
}
|
||||
else if (m_behavior && inputChannelId == InputDeviceMouse::Movement::Z && mouseOver)
|
||||
{
|
||||
m_behavior->MoveZ(event.m_inputChannel.GetValue());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (keysOld != m_keys)
|
||||
{
|
||||
m_keysChanged = true;
|
||||
m_timeToBehaviorSwitchMs = BehaviorSwitchDelayMs;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::Reset()
|
||||
{
|
||||
CalculateExtents();
|
||||
|
||||
// reset camera
|
||||
m_targetPosition = m_modelCenter;
|
||||
const float distance = m_distanceMin * StartingDistanceMultiplier;
|
||||
const AZ::Quaternion cameraRotation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), StartingRotationAngle);
|
||||
AZ::Vector3 cameraPosition(m_targetPosition.GetX(), m_targetPosition.GetY() - distance, m_targetPosition.GetZ());
|
||||
cameraPosition = cameraRotation.TransformVector(cameraPosition);
|
||||
AZ::Transform cameraTransform = AZ::Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition);
|
||||
AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalTM, cameraTransform);
|
||||
m_isCameraCentered = true;
|
||||
|
||||
// reset model
|
||||
AZ::Transform modelTransform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::Event(m_targetEntityId, &AZ::TransformBus::Events::SetLocalTM, modelTransform);
|
||||
|
||||
// reset environment
|
||||
AZ::Transform environmentTransform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::Event(m_environmentEntityId, &AZ::TransformBus::Events::SetLocalTM, environmentTransform);
|
||||
|
||||
const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity();
|
||||
auto skyBoxFeatureProcessor =
|
||||
AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::Render::SkyBoxFeatureProcessorInterface>(m_environmentEntityId);
|
||||
skyBoxFeatureProcessor->SetCubemapRotationMatrix(rotationMatrix);
|
||||
|
||||
if (m_behavior)
|
||||
{
|
||||
m_behavior->End();
|
||||
m_behavior->Start();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::SetFieldOfView(float value)
|
||||
{
|
||||
Camera::CameraRequestBus::Event(m_cameraEntityId, &Camera::CameraRequestBus::Events::SetFovDegrees, value);
|
||||
}
|
||||
|
||||
bool ViewportInputBehaviorController::IsCameraCentered() const
|
||||
{
|
||||
return m_isCameraCentered;
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::CalculateExtents()
|
||||
{
|
||||
AZ::TransformBus::EventResult(m_modelCenter, m_targetEntityId, &AZ::TransformBus::Events::GetLocalTranslation);
|
||||
m_targetBounds.GetAsSphere(m_modelCenter, m_radius);
|
||||
m_distanceMin = DepthNear + 0.5f * AZ::GetMin(
|
||||
AZ::GetMin(
|
||||
m_targetBounds.GetExtents().GetX(),
|
||||
m_targetBounds.GetExtents().GetY()),
|
||||
m_targetBounds.GetExtents().GetZ());
|
||||
m_distanceMax = m_radius * MaxDistanceMultiplier;
|
||||
}
|
||||
|
||||
void ViewportInputBehaviorController::EvaluateControlBehavior()
|
||||
{
|
||||
auto it = m_behaviorMap.find(m_keys);
|
||||
AZStd::shared_ptr<ViewportInputBehavior> nextBehavior =
|
||||
it != m_behaviorMap.end() ? it->second : AZStd::shared_ptr<ViewportInputBehavior>();
|
||||
if (m_behavior != nextBehavior)
|
||||
{
|
||||
if (m_behavior)
|
||||
{
|
||||
m_behavior->End();
|
||||
}
|
||||
|
||||
m_behavior = nextBehavior;
|
||||
|
||||
if (m_behavior)
|
||||
{
|
||||
m_behavior->Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
Reference in New Issue
Block a user