Merge commit 'a6164ca2cd3f573fd7735c3825568b1e25b12c2b' into puvvadar/gitflow_211118_o3de
This commit is contained in:
@@ -337,12 +337,12 @@ namespace SandboxEditor
|
||||
AZ::TransformBus::EventResult(worldFromLocal, viewEntityId, &AZ::TransformBus::Events::GetWorldTM);
|
||||
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
|
||||
m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, worldFromLocal);
|
||||
m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::StartTrackingTransform, worldFromLocal);
|
||||
}
|
||||
else
|
||||
{
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
|
||||
m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::ClearReferenceFrame);
|
||||
m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::StopTrackingTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,8 +91,8 @@ namespace UnitTest
|
||||
&Camera::EditorCameraNotificationBus::Events::OnViewportViewEntityChanged, m_entity->GetId());
|
||||
|
||||
// ensure the viewport updates after the viewport view entity change
|
||||
const float deltaTime = 1.0f / 60.0f;
|
||||
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
|
||||
// note: do a large step to ensure smoothing finishes (e.g. not 1.0f/60.0f)
|
||||
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(2.0f), AZ::ScriptTimePoint() });
|
||||
|
||||
// retrieve updated camera transform
|
||||
const AZ::Transform cameraTransform = m_cameraViewportContextView->GetCameraTransform();
|
||||
@@ -102,61 +102,40 @@ namespace UnitTest
|
||||
EXPECT_THAT(cameraTransform, IsClose(entityTransform));
|
||||
}
|
||||
|
||||
TEST_F(EditorCameraFixture, ReferenceFrameRemainsIdentityAfterExternalCameraTransformChangeWhenNotSet)
|
||||
TEST_F(EditorCameraFixture, TrackingTransformIsTrueAfterTransformIsTracked)
|
||||
{
|
||||
// Given
|
||||
m_cameraViewportContextView->SetCameraTransform(AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 20.0f, 30.0f)));
|
||||
// Given/When
|
||||
const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
|
||||
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::StartTrackingTransform, referenceFrame);
|
||||
|
||||
// When
|
||||
AZ::Transform referenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
|
||||
bool trackingTransform = false;
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
|
||||
referenceFrame, TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
|
||||
trackingTransform, TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::IsTrackingTransform);
|
||||
|
||||
// Then
|
||||
// reference frame is still the identity
|
||||
EXPECT_THAT(referenceFrame, IsClose(AZ::Transform::CreateIdentity()));
|
||||
EXPECT_THAT(trackingTransform, ::testing::IsTrue());
|
||||
}
|
||||
|
||||
TEST_F(EditorCameraFixture, ExternalCameraTransformChangeWhenReferenceFrameIsSetUpdatesReferenceFrame)
|
||||
TEST_F(EditorCameraFixture, TrackingTransformIsFalseAfterTransformIsStoppedBeingTracked)
|
||||
{
|
||||
// Given
|
||||
const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
|
||||
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
|
||||
|
||||
const AZ::Transform nextTransform = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 20.0f, 30.0f));
|
||||
m_cameraViewportContextView->SetCameraTransform(nextTransform);
|
||||
|
||||
// When
|
||||
AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
|
||||
currentReferenceFrame, TestViewportId,
|
||||
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
|
||||
|
||||
// Then
|
||||
EXPECT_THAT(currentReferenceFrame, IsClose(nextTransform));
|
||||
}
|
||||
|
||||
TEST_F(EditorCameraFixture, ReferenceFrameReturnedToIdentityAfterClear)
|
||||
{
|
||||
// Given
|
||||
const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
|
||||
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
|
||||
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::StartTrackingTransform, referenceFrame);
|
||||
|
||||
// When
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
|
||||
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::ClearReferenceFrame);
|
||||
|
||||
AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
|
||||
currentReferenceFrame, TestViewportId,
|
||||
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
|
||||
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::StopTrackingTransform);
|
||||
|
||||
// Then
|
||||
EXPECT_THAT(currentReferenceFrame, IsClose(AZ::Transform::CreateIdentity()));
|
||||
bool trackingTransform = false;
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
|
||||
trackingTransform, TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::IsTrackingTransform);
|
||||
|
||||
EXPECT_THAT(trackingTransform, ::testing::IsFalse());
|
||||
}
|
||||
|
||||
TEST_F(EditorCameraFixture, InterpolateToTransform)
|
||||
@@ -184,7 +163,7 @@ namespace UnitTest
|
||||
const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
|
||||
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
|
||||
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::StartTrackingTransform, referenceFrame);
|
||||
|
||||
AZ::Transform transformToInterpolateTo = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f));
|
||||
@@ -198,15 +177,9 @@ namespace UnitTest
|
||||
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
|
||||
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
|
||||
|
||||
AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
|
||||
currentReferenceFrame, TestViewportId,
|
||||
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
|
||||
|
||||
const auto finalTransform = m_cameraViewportContextView->GetCameraTransform();
|
||||
|
||||
// Then
|
||||
EXPECT_THAT(finalTransform, IsClose(transformToInterpolateTo));
|
||||
EXPECT_THAT(currentReferenceFrame, IsClose(AZ::Transform::CreateIdentity()));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -146,6 +146,17 @@ namespace UnitTest
|
||||
controller->SetCameraPropsBuilderCallback(
|
||||
[](AzFramework::CameraProps& cameraProps)
|
||||
{
|
||||
// note: rotateSmoothness is also used for roll (not related to camera input directly)
|
||||
cameraProps.m_rotateSmoothnessFn = []
|
||||
{
|
||||
return 5.0f;
|
||||
};
|
||||
|
||||
cameraProps.m_translateSmoothnessFn = []
|
||||
{
|
||||
return 5.0f;
|
||||
};
|
||||
|
||||
cameraProps.m_rotateSmoothingEnabledFn = []
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -94,27 +94,27 @@ namespace AzFramework
|
||||
float y;
|
||||
float z;
|
||||
|
||||
// 2.4 Factor as RzRyRx
|
||||
if (orientation.GetElement(2, 0) < 1.0f)
|
||||
// 2.5 Factor as RzRxRy
|
||||
if (orientation.GetElement(2, 1) < 1.0f)
|
||||
{
|
||||
if (orientation.GetElement(2, 0) > -1.0f)
|
||||
if (orientation.GetElement(2, 1) > -1.0f)
|
||||
{
|
||||
x = AZStd::atan2(orientation.GetElement(2, 1), orientation.GetElement(2, 2));
|
||||
y = AZStd::asin(-orientation.GetElement(2, 0));
|
||||
z = AZStd::atan2(orientation.GetElement(1, 0), orientation.GetElement(0, 0));
|
||||
x = AZStd::asin(orientation.GetElement(2, 1));
|
||||
y = AZStd::atan2(-orientation.GetElement(2, 0), orientation.GetElement(2, 2));
|
||||
z = AZStd::atan2(-orientation.GetElement(0, 1), orientation.GetElement(1, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0.0f;
|
||||
y = AZ::Constants::Pi * 0.5f;
|
||||
z = -AZStd::atan2(-orientation.GetElement(2, 1), orientation.GetElement(1, 1));
|
||||
x = -AZ::Constants::Pi * 0.5f;
|
||||
y = 0.0f;
|
||||
z = -AZStd::atan2(orientation.GetElement(0, 2), orientation.GetElement(0, 0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0.0f;
|
||||
y = -AZ::Constants::Pi * 0.5f;
|
||||
z = AZStd::atan2(-orientation.GetElement(1, 2), orientation.GetElement(1, 1));
|
||||
x = AZ::Constants::Pi * 0.5f;
|
||||
y = 0.0f;
|
||||
z = AZStd::atan2(orientation.GetElement(0, 2), orientation.GetElement(0, 0));
|
||||
}
|
||||
|
||||
return { x, y, z };
|
||||
@@ -122,14 +122,36 @@ namespace AzFramework
|
||||
|
||||
void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform)
|
||||
{
|
||||
const auto eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(transform));
|
||||
UpdateCameraFromTranslationAndRotation(
|
||||
camera, transform.GetTranslation(), AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(transform)));
|
||||
}
|
||||
|
||||
void UpdateCameraFromTranslationAndRotation(Camera& camera, const AZ::Vector3& translation, const AZ::Vector3& eulerAngles)
|
||||
{
|
||||
camera.m_pitch = eulerAngles.GetX();
|
||||
camera.m_yaw = eulerAngles.GetZ();
|
||||
camera.m_pivot = transform.GetTranslation();
|
||||
camera.m_pivot = translation;
|
||||
camera.m_offset = AZ::Vector3::CreateZero();
|
||||
}
|
||||
|
||||
float SmoothValueTime(const float smoothness, float deltaTime)
|
||||
{
|
||||
// note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent
|
||||
// article by Scott Lembcke: https://www.gamasutra.com/blogs/ScottLembcke/20180404/316046/Improved_Lerp_Smoothing.php
|
||||
const float rate = AZStd::exp2(smoothness);
|
||||
return AZStd::exp2(-rate * deltaTime);
|
||||
}
|
||||
|
||||
float SmoothValue(const float target, const float current, const float time)
|
||||
{
|
||||
return AZ::Lerp(target, current, time);
|
||||
}
|
||||
|
||||
float SmoothValue(const float target, const float current, const float smoothness, const float deltaTime)
|
||||
{
|
||||
return SmoothValue(target, current, SmoothValueTime(smoothness, deltaTime));
|
||||
}
|
||||
|
||||
bool CameraSystem::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto& cursor = AZStd::get_if<CursorEvent>(&event))
|
||||
@@ -749,14 +771,11 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
Camera camera;
|
||||
// note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent
|
||||
// article by Scott Lembcke: https://www.gamasutra.com/blogs/ScottLembcke/20180404/316046/Improved_Lerp_Smoothing.php
|
||||
if (cameraProps.m_rotateSmoothingEnabledFn())
|
||||
{
|
||||
const float lookRate = AZStd::exp2(cameraProps.m_rotateSmoothnessFn());
|
||||
const float lookTime = AZStd::exp2(-lookRate * deltaTime);
|
||||
camera.m_pitch = AZ::Lerp(targetCamera.m_pitch, currentCamera.m_pitch, lookTime);
|
||||
camera.m_yaw = AZ::Lerp(targetYaw, currentYaw, lookTime);
|
||||
const float lookTime = SmoothValueTime(cameraProps.m_rotateSmoothnessFn(), deltaTime);
|
||||
camera.m_pitch = SmoothValue(targetCamera.m_pitch, currentCamera.m_pitch, lookTime);
|
||||
camera.m_yaw = SmoothValue(targetYaw, currentYaw, lookTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -766,8 +785,7 @@ namespace AzFramework
|
||||
|
||||
if (cameraProps.m_translateSmoothingEnabledFn())
|
||||
{
|
||||
const float moveRate = AZStd::exp2(cameraProps.m_translateSmoothnessFn());
|
||||
const float moveTime = AZStd::exp2(-moveRate * deltaTime);
|
||||
const float moveTime = SmoothValueTime(cameraProps.m_rotateSmoothnessFn(), deltaTime);
|
||||
camera.m_pivot = targetCamera.m_pivot.Lerp(currentCamera.m_pivot, moveTime);
|
||||
camera.m_offset = targetCamera.m_offset.Lerp(currentCamera.m_offset, moveTime);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,19 @@ namespace AzFramework
|
||||
//! Extracts Euler angles (orientation) and translation from the transform and writes the values to the camera.
|
||||
void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform);
|
||||
|
||||
//! Writes the translation value and Euler angles to the camera.
|
||||
void UpdateCameraFromTranslationAndRotation(Camera& camera, const AZ::Vector3& translation, const AZ::Vector3& eulerAngles);
|
||||
|
||||
//! Returns the time ('t') input value to use with SmoothValue.
|
||||
//! Useful if it is to be reused for multiple calls to SmoothValue.
|
||||
float SmoothValueTime(float smoothness, float deltaTime);
|
||||
|
||||
// Smoothly interpolate a value from current to target according to a smoothing parameter.
|
||||
float SmoothValue(float target, float current, float smoothness, float deltaTime);
|
||||
|
||||
// Overload of SmoothValue that takes time ('t') value directly.
|
||||
float SmoothValue(float target, float current, float time);
|
||||
|
||||
//! Generic motion type.
|
||||
template<typename MotionTag>
|
||||
struct MotionEvent
|
||||
|
||||
Reference in New Issue
Block a user