Fix issue with mouse input for viewport camera (#3210)
* fix for drift accumulating in the viewport camera Signed-off-by: hultonha <hultonha@amazon.co.uk> * fix typo and update how events are stored Signed-off-by: hultonha <hultonha@amazon.co.uk> * respond to PR feedback and fix linux and windows build issues Signed-off-by: hultonha <hultonha@amazon.co.uk> * fix failing unit tests in camera input Signed-off-by: hultonha <hultonha@amazon.co.uk>
This commit is contained in:
+103
-61
@@ -41,6 +41,7 @@ namespace AtomToolsFramework
|
||||
display.DrawLine(transform.GetTranslation(), transform.GetTranslation() + transform.GetBasisZ().GetNormalizedSafe() * axisLength);
|
||||
}
|
||||
|
||||
// convenience function to access the ViewportContext for the given ViewportId.
|
||||
static AZ::RPI::ViewportContextPtr RetrieveViewportContext(const AzFramework::ViewportId viewportId)
|
||||
{
|
||||
auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
|
||||
@@ -58,6 +59,35 @@ namespace AtomToolsFramework
|
||||
return viewportContext;
|
||||
}
|
||||
|
||||
ModularCameraViewportContextImpl::ModularCameraViewportContextImpl(const AzFramework::ViewportId viewportId)
|
||||
: m_viewportId(viewportId)
|
||||
{
|
||||
}
|
||||
|
||||
AZ::Transform ModularCameraViewportContextImpl::GetCameraTransform() const
|
||||
{
|
||||
if (auto viewportContext = RetrieveViewportContext(m_viewportId))
|
||||
{
|
||||
return viewportContext->GetCameraTransform();
|
||||
}
|
||||
|
||||
return AZ::Transform::CreateIdentity();
|
||||
}
|
||||
void ModularCameraViewportContextImpl::SetCameraTransform(const AZ::Transform& transform)
|
||||
{
|
||||
if (auto viewportContext = RetrieveViewportContext(m_viewportId))
|
||||
{
|
||||
viewportContext->SetCameraTransform(transform);
|
||||
}
|
||||
}
|
||||
void ModularCameraViewportContextImpl::ConnectViewMatrixChangedHandler(AZ::RPI::ViewportContext::MatrixChangedEvent::Handler& handler)
|
||||
{
|
||||
if (auto viewportContext = RetrieveViewportContext(m_viewportId))
|
||||
{
|
||||
viewportContext->ConnectViewMatrixChangedHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
void ModularViewportCameraController::SetCameraListBuilderCallback(const CameraListBuilder& builder)
|
||||
{
|
||||
m_cameraListBuilder = builder;
|
||||
@@ -73,6 +103,11 @@ namespace AtomToolsFramework
|
||||
m_cameraControllerPriorityBuilder = builder;
|
||||
}
|
||||
|
||||
void ModularViewportCameraController::SetCameraViewportContextBuilderCallback(const CameraViewportContextBuilder& builder)
|
||||
{
|
||||
m_cameraViewportContextBuilder = builder;
|
||||
}
|
||||
|
||||
void ModularViewportCameraController::SetupCameras(AzFramework::Cameras& cameras)
|
||||
{
|
||||
if (m_cameraListBuilder)
|
||||
@@ -97,6 +132,15 @@ namespace AtomToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void ModularViewportCameraController::SetupCameraControllerViewportContext(
|
||||
AZStd::unique_ptr<ModularCameraViewportContext>& cameraViewportContext)
|
||||
{
|
||||
if (m_cameraViewportContextBuilder)
|
||||
{
|
||||
m_cameraViewportContextBuilder(cameraViewportContext);
|
||||
}
|
||||
}
|
||||
|
||||
// what priority should the camera system respond to
|
||||
AzFramework::ViewportControllerPriority DefaultCameraControllerPriority(const AzFramework::CameraSystem& cameraSystem)
|
||||
{
|
||||
@@ -119,23 +163,20 @@ namespace AtomToolsFramework
|
||||
controller->SetupCameras(m_cameraSystem.m_cameras);
|
||||
controller->SetupCameraProperties(m_cameraProps);
|
||||
controller->SetupCameraControllerPriority(m_priorityFn);
|
||||
controller->SetupCameraControllerViewportContext(m_modularCameraViewportContext);
|
||||
|
||||
if (auto viewportContext = RetrieveViewportContext(GetViewportId()))
|
||||
auto handleCameraChange = [this](const AZ::Matrix4x4&)
|
||||
{
|
||||
auto handleCameraChange = [this, viewportContext](const AZ::Matrix4x4&)
|
||||
// ignore these updates if the camera is being updated internally
|
||||
if (!m_updatingTransformInternally)
|
||||
{
|
||||
// ignore these updates if the camera is being updated internally
|
||||
if (!m_updatingTransformInternally)
|
||||
{
|
||||
UpdateCameraFromTransform(m_targetCamera, viewportContext->GetCameraTransform());
|
||||
m_camera = m_targetCamera;
|
||||
}
|
||||
};
|
||||
UpdateCameraFromTransform(m_targetCamera, m_modularCameraViewportContext->GetCameraTransform());
|
||||
m_camera = m_targetCamera;
|
||||
}
|
||||
};
|
||||
|
||||
m_cameraViewMatrixChangeHandler = AZ::RPI::ViewportContext::MatrixChangedEvent::Handler(handleCameraChange);
|
||||
|
||||
viewportContext->ConnectViewMatrixChangedHandler(m_cameraViewMatrixChangeHandler);
|
||||
}
|
||||
m_cameraViewMatrixChangeHandler = AZ::RPI::ViewportContext::MatrixChangedEvent::Handler(handleCameraChange);
|
||||
m_modularCameraViewportContext->ConnectViewMatrixChangedHandler(m_cameraViewMatrixChangeHandler);
|
||||
|
||||
AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId());
|
||||
ModularViewportCameraControllerRequestBus::Handler::BusConnect(viewportId);
|
||||
@@ -151,7 +192,11 @@ namespace AtomToolsFramework
|
||||
{
|
||||
if (event.m_priority == m_priorityFn(m_cameraSystem))
|
||||
{
|
||||
return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel));
|
||||
AzFramework::WindowSize windowSize;
|
||||
AzFramework::WindowRequestBus::EventResult(
|
||||
windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
|
||||
|
||||
return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel, windowSize));
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -165,61 +210,58 @@ namespace AtomToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto viewportContext = RetrieveViewportContext(GetViewportId()))
|
||||
m_updatingTransformInternally = true;
|
||||
|
||||
if (m_cameraMode == CameraMode::Control)
|
||||
{
|
||||
m_updatingTransformInternally = true;
|
||||
m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count());
|
||||
m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, m_cameraProps, event.m_deltaTime.count());
|
||||
|
||||
if (m_cameraMode == CameraMode::Control)
|
||||
// if there has been an interpolation, only clear the look at point if it is no longer
|
||||
// centered in the view (the camera has looked away from it)
|
||||
if (m_lookAtAfterInterpolation.has_value())
|
||||
{
|
||||
m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count());
|
||||
m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, m_cameraProps, event.m_deltaTime.count());
|
||||
|
||||
// if there has been an interpolation, only clear the look at point if it is no longer
|
||||
// centered in the view (the camera has looked away from it)
|
||||
if (m_lookAtAfterInterpolation.has_value())
|
||||
if (const float lookDirection =
|
||||
(*m_lookAtAfterInterpolation - m_camera.Translation()).GetNormalized().Dot(m_camera.Transform().GetBasisY());
|
||||
!AZ::IsCloseMag(lookDirection, 1.0f, 0.001f))
|
||||
{
|
||||
if (const float lookDirection =
|
||||
(*m_lookAtAfterInterpolation - m_camera.Translation()).GetNormalized().Dot(m_camera.Transform().GetBasisY());
|
||||
!AZ::IsCloseMag(lookDirection, 1.0f, 0.001f))
|
||||
{
|
||||
m_lookAtAfterInterpolation = {};
|
||||
}
|
||||
m_lookAtAfterInterpolation = {};
|
||||
}
|
||||
|
||||
viewportContext->SetCameraTransform(m_camera.Transform());
|
||||
}
|
||||
else if (m_cameraMode == CameraMode::Animation)
|
||||
{
|
||||
const auto smootherStepFn = [](const float t)
|
||||
{
|
||||
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
|
||||
};
|
||||
|
||||
const auto& [transformStart, transformEnd, animationTime] = m_cameraAnimation;
|
||||
|
||||
const float transitionTime = smootherStepFn(animationTime);
|
||||
const AZ::Transform current = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
transformStart.GetRotation().Slerp(transformEnd.GetRotation(), transitionTime),
|
||||
transformStart.GetTranslation().Lerp(transformEnd.GetTranslation(), transitionTime));
|
||||
|
||||
const AZ::Vector3 eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(current));
|
||||
m_camera.m_pitch = eulerAngles.GetX();
|
||||
m_camera.m_yaw = eulerAngles.GetZ();
|
||||
m_camera.m_lookAt = current.GetTranslation();
|
||||
m_targetCamera = m_camera;
|
||||
|
||||
if (animationTime >= 1.0f)
|
||||
{
|
||||
m_cameraMode = CameraMode::Control;
|
||||
}
|
||||
|
||||
m_cameraAnimation.m_time = AZ::GetClamp(animationTime + event.m_deltaTime.count(), 0.0f, 1.0f);
|
||||
|
||||
viewportContext->SetCameraTransform(current);
|
||||
}
|
||||
|
||||
m_updatingTransformInternally = false;
|
||||
m_modularCameraViewportContext->SetCameraTransform(m_camera.Transform());
|
||||
}
|
||||
else if (m_cameraMode == CameraMode::Animation)
|
||||
{
|
||||
const auto smootherStepFn = [](const float t)
|
||||
{
|
||||
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
|
||||
};
|
||||
|
||||
const auto& [transformStart, transformEnd, animationTime] = m_cameraAnimation;
|
||||
|
||||
const float transitionTime = smootherStepFn(animationTime);
|
||||
const AZ::Transform current = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
transformStart.GetRotation().Slerp(transformEnd.GetRotation(), transitionTime),
|
||||
transformStart.GetTranslation().Lerp(transformEnd.GetTranslation(), transitionTime));
|
||||
|
||||
const AZ::Vector3 eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(current));
|
||||
m_camera.m_pitch = eulerAngles.GetX();
|
||||
m_camera.m_yaw = eulerAngles.GetZ();
|
||||
m_camera.m_lookAt = current.GetTranslation();
|
||||
m_targetCamera = m_camera;
|
||||
|
||||
if (animationTime >= 1.0f)
|
||||
{
|
||||
m_cameraMode = CameraMode::Control;
|
||||
}
|
||||
|
||||
m_cameraAnimation.m_time = AZ::GetClamp(animationTime + event.m_deltaTime.count(), 0.0f, 1.0f);
|
||||
|
||||
m_modularCameraViewportContext->SetCameraTransform(current);
|
||||
}
|
||||
|
||||
m_updatingTransformInternally = false;
|
||||
}
|
||||
|
||||
void ModularViewportCameraControllerInstance::DisplayViewport(
|
||||
|
||||
Reference in New Issue
Block a user