Update to how entity space is treated in the viewport (#4263)

* first pass fixes for how entity space is handled in the viewport interaction model

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* small updates to simplify space handling

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* fix for influence group with one entity selected

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* some tidy-up and fix for scale manipulator snapping

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* couple of small fixes for scale manipulator

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* small comment update

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* fixes for integration test failures

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* add test for rotation manipulator

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* add test coverage for rotation manipulators

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* add tests for translation manipulators and some other tidy-up changes

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* add tests for translating a group of entities

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* add some tests for scale manipulators

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* some updates and formatting changes (clang-format) to ViewportScreen

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* simplify usage of lround code

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* update missed name updates

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* update usage of WorldToScreenNdc

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* updates following review feedback

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* some more small tidy-up changes

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* move static variables to be marked inline

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* small formatting fixes

Signed-off-by: hultonha <hultonha@amazon.co.uk>
This commit is contained in:
hultonha
2021-09-28 09:26:20 +01:00
committed by GitHub
parent 96d99c2814
commit 7da866e81a
10 changed files with 868 additions and 224 deletions
@@ -6,8 +6,8 @@
*
*/
#include <AzCore/Math/Matrix3x4.h>
#include <AzCore/Math/Matrix3x3.h>
#include <AzCore/Math/Matrix3x4.h>
#include <AzCore/Math/Matrix4x4.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/VectorConversions.h>
@@ -20,18 +20,17 @@
namespace UnitTest
{
// transform a point from normalized device coordinates to world space, and then from world space back to normalized device coordinates
AZ::Vector2 ScreenNDCToWorldToScreenNDC(
const AZ::Vector2& ndcPoint, const AzFramework::CameraState& cameraState)
// transform a point from normalized device coordinates to world space, and then from world space back to normalized device coordinates
AZ::Vector2 ScreenNdcToWorldToScreenNdc(const AZ::Vector2& ndcPoint, const AzFramework::CameraState& cameraState)
{
const auto worldResult = AzFramework::ScreenNDCToWorld(ndcPoint, InverseCameraView(cameraState), InverseCameraProjection(cameraState));
const auto ndcResult = AzFramework::WorldToScreenNDC(worldResult, CameraView(cameraState), CameraProjection(cameraState));
const auto worldResult =
AzFramework::ScreenNdcToWorld(ndcPoint, InverseCameraView(cameraState), InverseCameraProjection(cameraState));
const auto ndcResult = AzFramework::WorldToScreenNdc(worldResult, CameraView(cameraState), CameraProjection(cameraState));
return AZ::Vector3ToVector2(ndcResult);
}
// transform a point from screen space to world space, and then from world space back to screen space
AzFramework::ScreenPoint ScreenToWorldToScreen(
const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState)
AzFramework::ScreenPoint ScreenToWorldToScreen(const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState)
{
const auto worldResult = AzFramework::ScreenToWorld(screenPoint, cameraState);
return AzFramework::WorldToScreen(worldResult, cameraState);
@@ -47,25 +46,25 @@ namespace UnitTest
const auto cameraState = AzFramework::CreateIdentityDefaultCamera(cameraPosition, screenDimensions);
{
const auto expectedScreenPoint = ScreenPoint{600, 450};
const auto expectedScreenPoint = ScreenPoint{ 600, 450 };
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
{
const auto expectedScreenPoint = ScreenPoint{400, 300};
const auto expectedScreenPoint = ScreenPoint{ 400, 300 };
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
{
const auto expectedScreenPoint = ScreenPoint{0, 0};
const auto expectedScreenPoint = ScreenPoint{ 0, 0 };
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
{
const auto expectedScreenPoint = ScreenPoint{800, 600};
const auto expectedScreenPoint = ScreenPoint{ 800, 600 };
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
@@ -81,7 +80,7 @@ namespace UnitTest
const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions);
const auto expectedScreenPoint = ScreenPoint{200, 300};
const auto expectedScreenPoint = ScreenPoint{ 200, 300 };
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
@@ -93,46 +92,46 @@ namespace UnitTest
using AzFramework::ScreenPoint;
const auto screenDimensions = AZ::Vector2(800.0f, 600.0f);
const auto cameraTransform = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) *
AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f));
const auto cameraTransform =
AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) * AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f));
const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions);
const auto worldResult = AzFramework::ScreenToWorld(ScreenPoint{400, 300}, cameraState);
const auto worldResult = AzFramework::ScreenToWorld(ScreenPoint{ 400, 300 }, cameraState);
EXPECT_THAT(worldResult, IsClose(AZ::Vector3(10.1f, 0.0f, 0.0f)));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// NDC tests
TEST(ViewportScreen, WorldToScreenNDCAndScreenNDCToWorldReturnsTheSameValueIdentityCameraOffsetFromOrigin)
{
using NdcPoint = AZ::Vector2;
const auto screenDimensions = AZ::Vector2(800.0f, 600.0f);
const auto cameraPosition = AZ::Vector3::CreateAxisY(-10.0f);
const auto cameraState = AzFramework::CreateIdentityDefaultCamera(cameraPosition, screenDimensions);
{
const auto expectedNdcPoint = NdcPoint{0.75f, 0.75f};
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
const auto expectedNdcPoint = NdcPoint{ 0.75f, 0.75f };
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
}
{
const auto expectedNdcPoint = NdcPoint{0.5f, 0.5f};
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
const auto expectedNdcPoint = NdcPoint{ 0.5f, 0.5f };
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
}
{
const auto expectedNdcPoint = NdcPoint{0.0f, 0.0f};
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
const auto expectedNdcPoint = NdcPoint{ 0.0f, 0.0f };
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
}
{
const auto expectedNdcPoint = NdcPoint{1.0f, 1.0f};
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
const auto expectedNdcPoint = NdcPoint{ 1.0f, 1.0f };
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
}
}
@@ -147,8 +146,8 @@ namespace UnitTest
const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions);
const auto expectedNdcPoint = NdcPoint{0.25f, 0.5f};
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
const auto expectedNdcPoint = NdcPoint{ 0.25f, 0.5f };
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
}
@@ -159,12 +158,13 @@ namespace UnitTest
using NdcPoint = AZ::Vector2;
const auto screenDimensions = AZ::Vector2(800.0f, 600.0f);
const auto cameraTransform = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) *
AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f));
const auto cameraTransform =
AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) * AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f));
const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions);
const auto worldResult = AzFramework::ScreenNDCToWorld(NdcPoint{0.5f, 0.5f}, InverseCameraView(cameraState), InverseCameraProjection(cameraState));
const auto worldResult =
AzFramework::ScreenNdcToWorld(NdcPoint{ 0.5f, 0.5f }, InverseCameraView(cameraState), InverseCameraProjection(cameraState));
EXPECT_THAT(worldResult, IsClose(AZ::Vector3(10.1f, 0.0f, 0.0f)));
}
@@ -175,7 +175,7 @@ namespace UnitTest
using AzFramework::ScreenPoint;
using AzFramework::ScreenVector;
const ScreenVector screenVector = ScreenPoint{100, 200} - ScreenPoint{10, 20};
const ScreenVector screenVector = ScreenPoint{ 100, 200 } - ScreenPoint{ 10, 20 };
EXPECT_EQ(screenVector, ScreenVector(90, 180));
}
@@ -184,7 +184,7 @@ namespace UnitTest
using AzFramework::ScreenPoint;
using AzFramework::ScreenVector;
const ScreenPoint screenPoint = ScreenPoint{100, 200} + ScreenVector{50, 25};
const ScreenPoint screenPoint = ScreenPoint{ 100, 200 } + ScreenVector{ 50, 25 };
EXPECT_EQ(screenPoint, ScreenPoint(150, 225));
}
@@ -193,7 +193,7 @@ namespace UnitTest
using AzFramework::ScreenPoint;
using AzFramework::ScreenVector;
const ScreenPoint screenPoint = ScreenPoint{120, 200} - ScreenVector{50, 20};
const ScreenPoint screenPoint = ScreenPoint{ 120, 200 } - ScreenVector{ 50, 20 };
EXPECT_EQ(screenPoint, ScreenPoint(70, 180));
}
@@ -202,7 +202,7 @@ namespace UnitTest
using AzFramework::ScreenPoint;
using AzFramework::ScreenVector;
const ScreenVector screenVector = ScreenVector{100, 200} + ScreenVector{50, 25};
const ScreenVector screenVector = ScreenVector{ 100, 200 } + ScreenVector{ 50, 25 };
EXPECT_EQ(screenVector, ScreenVector(150, 225));
}
@@ -211,7 +211,7 @@ namespace UnitTest
using AzFramework::ScreenPoint;
using AzFramework::ScreenVector;
const ScreenVector screenVector = ScreenVector{100, 200} - ScreenVector{50, 25};
const ScreenVector screenVector = ScreenVector{ 100, 200 } - ScreenVector{ 50, 25 };
EXPECT_EQ(screenVector, ScreenVector(50, 175));
}
@@ -220,8 +220,8 @@ namespace UnitTest
using AzFramework::ScreenPoint;
using AzFramework::ScreenVector;
const ScreenPoint screenPoint = ScreenPoint{100, 200};
const ScreenVector screenVector = ScreenVector{50, 25};
const ScreenPoint screenPoint = ScreenPoint{ 100, 200 };
const ScreenVector screenVector = ScreenVector{ 50, 25 };
const AZ::Vector2 fromScreenPoint = AzFramework::Vector2FromScreenPoint(screenPoint);
const AZ::Vector2 fromScreenVector = AzFramework::Vector2FromScreenVector(screenVector);
@@ -295,6 +295,58 @@ namespace UnitTest
EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(12, 15)), 19.20937f, 0.001f);
}
TEST(ViewportScreen, ScreenVectorTransformedByScalarUpwards)
{
using AzFramework::ScreenVector;
auto screenVector = ScreenVector(5, 10);
auto scaledScreenVector = screenVector * 2.0f;
EXPECT_EQ(scaledScreenVector, ScreenVector(10, 20));
}
TEST(ViewportScreen, ScreenVectorTransformedByScalarWithRounding)
{
using AzFramework::ScreenVector;
auto screenVector = ScreenVector(1, 6);
auto scaledScreenVector = screenVector * 0.1f;
// value less than 0.5 rounds down, greater than or equal to 0.5 rounds up
EXPECT_EQ(scaledScreenVector, ScreenVector(0, 1));
}
TEST(ViewportScreen, ScreenVectorTransformedByScalarWithRoundingAtHalfwayBoundary)
{
using AzFramework::ScreenVector;
auto screenVector = ScreenVector(5, 10);
auto scaledScreenVector = screenVector * 0.1f;
// value less than 0.5 rounds down, greater than or equal to 0.5 rounds up
EXPECT_EQ(scaledScreenVector, ScreenVector(1, 1));
}
TEST(ViewportScreen, ScreenVectorTransformedByScalarDownwards)
{
using AzFramework::ScreenVector;
auto screenVector = ScreenVector(6, 12);
auto scaledScreenVector = screenVector * 0.5f;
EXPECT_EQ(scaledScreenVector, ScreenVector(3, 6));
}
TEST(ViewportScreen, ScreenVectorTransformedByScalarInplace)
{
using AzFramework::ScreenVector;
auto screenVector = ScreenVector(13, 37);
screenVector *= 10.0f;
EXPECT_EQ(screenVector, ScreenVector(130, 370));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Other tests
TEST(ViewportScreen, CanGetCameraTransformFromCameraViewAndBack)