Prevent the camera from easily being set to an invalid orientation (#6203)

* add temporary debug logging

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* improvement for box select sometimes getting stuck on

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* add temporary debug logging

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* improvement for box select sometimes getting stuck on

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* remove temporary logging

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* fixes for camera pitch issues

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* missed file with camera pitch fixes

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* remove debug logs

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* add some tests for new pitch constraint updates

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>
This commit is contained in:
Tom Hulton-Harrop
2021-12-08 09:42:40 +00:00
committed by GitHub
parent a8ef23e4ae
commit b54215552c
8 changed files with 121 additions and 25 deletions
@@ -335,10 +335,13 @@ namespace AzFramework
Camera nextCamera = targetCamera;
const float rotateSpeed = m_rotateSpeedFn();
nextCamera.m_pitch -= float(cursorDelta.m_y) * rotateSpeed * Invert(m_invertPitchFn());
nextCamera.m_yaw -= float(cursorDelta.m_x) * rotateSpeed * Invert(m_invertYawFn());
const float deltaPitch = aznumeric_cast<float>(cursorDelta.m_y) * rotateSpeed * Invert(m_invertPitchFn());
const float deltaYaw = aznumeric_cast<float>(cursorDelta.m_x) * rotateSpeed * Invert(m_invertYawFn());
nextCamera.m_pitch -= deltaPitch;
nextCamera.m_yaw -= deltaYaw;
nextCamera.m_yaw = WrapYawRotation(nextCamera.m_yaw);
if (m_constrainPitch())
{
nextCamera.m_pitch = ClampPitchRotation(nextCamera.m_pitch);
@@ -25,6 +25,9 @@ namespace AzFramework
struct WindowSize;
//! Tolerance to use when limiting pitch to avoid reaching +/-Pi/2 exactly.
constexpr float CameraPitchTolerance = 1.0e-4f;
//! Returns Euler angles (pitch, roll, yaw) for the incoming orientation.
//! @note Order of rotation is Z, Y, X.
AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation);
@@ -318,11 +321,26 @@ namespace AzFramework
return m_handlingEvents;
}
//! Clamps pitch to be +/-90 degrees (-Pi/2, Pi/2).
//! Returns min/max values for camera pitch (in radians).
inline AZStd::tuple<float, float> CameraPitchMinMaxRadians()
{
return { -AZ::Constants::HalfPi, AZ::Constants::HalfPi };
}
//! Returns min/max values for camera pitch (in radians) including a small tolerance at each
//! extreme (looking directly up or down) to avoid floating point accuracy issues.
inline AZStd::tuple<float, float> CameraPitchMinMaxRadiansWithTolerance()
{
const auto [pitchMinRadians, pitchMaxRadians] = CameraPitchMinMaxRadians();
return { pitchMinRadians + CameraPitchTolerance, pitchMaxRadians - CameraPitchTolerance };
}
//! Clamps pitch to be +/-90 degrees (-Pi/2, Pi/2) with a minor tolerance at each extreme.
//! @param pitch Pitch angle in radians.
inline float ClampPitchRotation(const float pitch)
{
return AZ::GetClamp(pitch, -AZ::Constants::HalfPi, AZ::Constants::HalfPi);
const auto [pitchMin, pitchMax] = CameraPitchMinMaxRadiansWithTolerance();
return AZ::GetClamp(pitch, pitchMin, pitchMax);
}
//! Ensures yaw wraps between 0 and 360 degrees (0, 2Pi).
@@ -322,6 +322,17 @@ namespace UnitTest
EXPECT_THAT(m_camera.m_offset, IsClose(AZ::Vector3::CreateZero()));
}
TEST(CameraInput, CameraPitchIsClampedWithExpectedTolerance)
{
const auto [expectedMinPitch, expectedMaxPitch] = AzFramework::CameraPitchMinMaxRadiansWithTolerance();
const float minPitch = AzFramework::ClampPitchRotation(-AZ::Constants::HalfPi);
const float maxPitch = AzFramework::ClampPitchRotation(AZ::Constants::HalfPi);
using ::testing::FloatNear;
EXPECT_THAT(minPitch, FloatNear(expectedMinPitch, AzFramework::CameraPitchTolerance));
EXPECT_THAT(maxPitch, FloatNear(expectedMaxPitch, AzFramework::CameraPitchTolerance));
}
TEST_F(CameraInputFixture, OrbitRotateCameraInputRotatesPitchOffsetByNinetyDegreesWithRequiredPixelDelta)
{
const auto cameraStartingPosition = AZ::Vector3::CreateAxisY(-20.0f);
@@ -64,7 +64,8 @@ namespace AzToolsFramework
}
}
if (clickOutcome == AzFramework::ClickDetector::ClickOutcome::Release)
if (clickOutcome == AzFramework::ClickDetector::ClickOutcome::Release ||
clickOutcome == AzFramework::ClickDetector::ClickOutcome::Click)
{
if (m_leftMouseUp)
{