Improve camera orbit behavior (#1060)

main
Tom Hulton-Harrop 5 years ago committed by GitHub
parent f2a7cd9a2d
commit cf08f4dab1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1233,7 +1233,7 @@ void EditorViewportWidget::SetViewportId(int id)
auto controller = AZStd::make_shared<AtomToolsFramework::ModularViewportCameraController>();
controller->SetCameraListBuilderCallback(
[](AzFramework::Cameras& cameras)
[id](AzFramework::Cameras& cameras)
{
auto firstPersonRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(AzFramework::CameraFreeLookButton);
auto firstPersonPanCamera =
@ -1243,17 +1243,17 @@ void EditorViewportWidget::SetViewportId(int id)
auto orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>();
orbitCamera->SetLookAtFn(
[](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional<AZ::Vector3>
[id](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional<AZ::Vector3>
{
AZStd::optional<AZ::Transform> manipulatorTransform;
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
manipulatorTransform, AzToolsFramework::GetEntityContextId(),
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
AZStd::optional<AZ::Vector3> lookAtAfterInterpolation;
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
lookAtAfterInterpolation, id,
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookAtAfterInterpolation);
// initially attempt to use manipulator transform if one exists (there is a selection)
if (manipulatorTransform)
// initially attempt to use the last set look at point after an interpolation has finished
if (lookAtAfterInterpolation.has_value())
{
return manipulatorTransform->GetTranslation();
return *lookAtAfterInterpolation;
}
const float RayDistance = 1000.0f;

@ -1732,13 +1732,14 @@ void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework::
// compute new camera transform
const float fov = AzFramework::RetrieveFov(viewportContext->GetCameraProjectionMatrix());
const float fovScale = (1.0f / AZStd::tan(fov * 0.5f));
const float distanceToTarget = selectionSize * fovScale * centerScale;
const float distanceToLookAt = selectionSize * fovScale * centerScale;
const AZ::Transform nextCameraTransform =
AZ::Transform::CreateLookAt(aabb.GetCenter() - (forward * distanceToTarget), aabb.GetCenter());
AZ::Transform::CreateLookAt(aabb.GetCenter() - (forward * distanceToLookAt), aabb.GetCenter());
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
viewportContext->GetId(),
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform);
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform,
distanceToLookAt);
}
}
}

@ -51,7 +51,8 @@ namespace AtomToolsFramework
void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
// ModularViewportCameraControllerRequestBus overrides ...
void InterpolateToTransform(const AZ::Transform& worldFromLocal) override;
void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) override;
AZStd::optional<AZ::Vector3> LookAtAfterInterpolation() const override;
private:
// AzFramework::ViewportDebugDisplayEventBus overrides ...
@ -71,6 +72,8 @@ namespace AtomToolsFramework
AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity();
float m_animationT = 0.0f;
CameraMode m_cameraMode = CameraMode::Control;
AZStd::optional<AZ::Vector3> m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished.
//!< Will be cleared when the view changes (camera looks away).
bool m_updatingTransform = false;
AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler;

@ -32,7 +32,12 @@ namespace AtomToolsFramework
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
//! Begin a smooth transition of the camera to the requested transform.
virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0;
//! @param worldFromLocal The transform of where the camera should end up.
//! @param lookAtDistance The distance between the camera transform and the imagined look at point.
virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) = 0;
//! Look at point after an interpolation has finished and no translation has occurred.
virtual AZStd::optional<AZ::Vector3> LookAtAfterInterpolation() const = 0;
protected:
~ModularViewportCameraControllerRequests() = default;

@ -140,6 +140,18 @@ namespace AtomToolsFramework
m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count());
m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, 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))
{
m_lookAtAfterInterpolation = {};
}
}
viewportContext->SetCameraTransform(m_camera.Transform());
}
else if (m_cameraMode == CameraMode::Animation)
@ -148,8 +160,8 @@ namespace AtomToolsFramework
{
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
};
const float transitionT = smootherStepFn(m_animationT);
const float transitionT = smootherStepFn(m_animationT);
const AZ::Transform current = AZ::Transform::CreateFromQuaternionAndTranslation(
m_transformStart.GetRotation().Slerp(m_transformEnd.GetRotation(), transitionT),
m_transformStart.GetTranslation().Lerp(m_transformEnd.GetTranslation(), transitionT));
@ -185,11 +197,17 @@ namespace AtomToolsFramework
}
}
void ModernViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal)
void ModernViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance)
{
m_animationT = 0.0f;
m_cameraMode = CameraMode::Animation;
m_transformStart = m_camera.Transform();
m_transformEnd = worldFromLocal;
m_lookAtAfterInterpolation = m_transformEnd.GetTranslation() + m_transformEnd.GetBasisY() * lookAtDistance;
}
AZStd::optional<AZ::Vector3> ModernViewportCameraControllerInstance::LookAtAfterInterpolation() const
{
return m_lookAtAfterInterpolation;
}
} // namespace AtomToolsFramework

Loading…
Cancel
Save