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
@@ -8,11 +8,10 @@
#pragma once
#include <AzCore/base.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/RTTI/TypeInfoSimple.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/RTTI/TypeInfoSimple.h>
#include <AzCore/base.h>
namespace AZ
{
@@ -27,7 +26,11 @@ namespace AzFramework
AZ_TYPE_INFO(ScreenPoint, "{8472B6C2-527F-44FC-87F8-C226B1A57A97}");
ScreenPoint() = default;
ScreenPoint(int x, int y) : m_x(x), m_y(y) {}
ScreenPoint(int x, int y)
: m_x(x)
, m_y(y)
{
}
int m_x; //!< X screen position.
int m_y; //!< Y screen position.
@@ -42,7 +45,11 @@ namespace AzFramework
AZ_TYPE_INFO(ScreenVector, "{1EAA2C62-8FDB-4A28-9FE3-1FA4F1418894}");
ScreenVector() = default;
ScreenVector(int x, int y) : m_x(x), m_y(y) {}
ScreenVector(int x, int y)
: m_x(x)
, m_y(y)
{
}
int m_x; //!< X screen delta.
int m_y; //!< Y screen delta.
@@ -71,14 +78,14 @@ namespace AzFramework
inline const ScreenPoint operator+(const ScreenPoint& lhs, const ScreenVector& rhs)
{
ScreenPoint result{lhs};
ScreenPoint result{ lhs };
result += rhs;
return result;
}
inline const ScreenPoint operator-(const ScreenPoint& lhs, const ScreenVector& rhs)
{
ScreenPoint result{lhs};
ScreenPoint result{ lhs };
result -= rhs;
return result;
}
@@ -99,14 +106,14 @@ namespace AzFramework
inline const ScreenVector operator+(const ScreenVector& lhs, const ScreenVector& rhs)
{
ScreenVector result{lhs};
ScreenVector result{ lhs };
result += rhs;
return result;
}
inline const ScreenVector operator-(const ScreenVector& lhs, const ScreenVector& rhs)
{
ScreenVector result{lhs};
ScreenVector result{ lhs };
result -= rhs;
return result;
}
@@ -131,23 +138,25 @@ namespace AzFramework
return !operator==(lhs, rhs);
}
inline ScreenVector& operator*=(ScreenVector& lhs, const float rhs)
{
lhs.m_x = aznumeric_cast<int>(AZStd::lround(aznumeric_cast<float>(lhs.m_x) * rhs));
lhs.m_y = aznumeric_cast<int>(AZStd::lround(aznumeric_cast<float>(lhs.m_y) * rhs));
return lhs;
}
inline const ScreenVector operator*(const ScreenVector& lhs, const float rhs)
{
ScreenVector result{ lhs };
result *= rhs;
return result;
}
inline float ScreenVectorLength(const ScreenVector& screenVector)
{
return aznumeric_cast<float>(AZStd::sqrt(screenVector.m_x * screenVector.m_x + screenVector.m_y * screenVector.m_y));
}
inline ScreenPoint ScreenPointFromNDC(const AZ::Vector3& screenNDC, const AZ::Vector2& viewportSize)
{
return ScreenPoint(
aznumeric_caster(AZStd::round(screenNDC.GetX() * viewportSize.GetX())),
aznumeric_caster(AZStd::round((1.0f - screenNDC.GetY()) * viewportSize.GetY())));
}
inline AZ::Vector2 NDCFromScreenPoint(const ScreenPoint& screenPoint, const AZ::Vector2& viewportSize)
{
return AZ::Vector2(aznumeric_cast<float>(screenPoint.m_x), viewportSize.GetY() - aznumeric_cast<float>(screenPoint.m_y)) / viewportSize;
}
//! Return an AZ::Vector2 from a ScreenPoint.
inline AZ::Vector2 Vector2FromScreenPoint(const ScreenPoint& screenPoint)
{
@@ -23,7 +23,7 @@ namespace AzFramework
// y-up, z into the screen, x-left
//
// x -> -x
// y -> z
// y -> z
// z -> y
//
// the same transform can be used to go to/from z-up - the only difference is the order of
@@ -37,15 +37,15 @@ namespace AzFramework
// yaw = AZ::Matrix4x4::CreateRotationZ(AZ::DegToRad(180.0f));
// conversion = pitch * yaw
return AZ::Matrix4x4::CreateFromColumns(
AZ::Vector4(-1.0f, 0.0f, 0.0f, 0.0f), AZ::Vector4(0.0f, 0.0f, 1.0f, .0f),
AZ::Vector4(0.0f, 1.0f, 0.0f, 0.0f), AZ::Vector4(0.0f, 0.0f, 0.0f, 1.0f));
AZ::Vector4(-1.0f, 0.0f, 0.0f, 0.0f), AZ::Vector4(0.0f, 0.0f, 1.0f, 0.0f), AZ::Vector4(0.0f, 1.0f, 0.0f, 0.0f),
AZ::Vector4(0.0f, 0.0f, 0.0f, 1.0f));
}
AZ::Matrix4x4 CameraTransform(const CameraState& cameraState)
{
return AZ::Matrix4x4::CreateFromColumns(
AZ::Vector3ToVector4(cameraState.m_side), AZ::Vector3ToVector4(cameraState.m_forward),
AZ::Vector3ToVector4(cameraState.m_up), AZ::Vector3ToVector4(cameraState.m_position, 1.0f));
AZ::Vector3ToVector4(cameraState.m_side), AZ::Vector3ToVector4(cameraState.m_forward), AZ::Vector3ToVector4(cameraState.m_up),
AZ::Vector3ToVector4(cameraState.m_position, 1.0f));
}
AZ::Matrix4x4 CameraView(const CameraState& cameraState)
@@ -63,8 +63,7 @@ namespace AzFramework
AZ::Matrix4x4 CameraProjection(const CameraState& cameraState)
{
return AZ::Matrix4x4::CreateProjection(
cameraState.VerticalFovRadian(), AspectRatio(cameraState.m_viewportSize), cameraState.m_nearClip,
cameraState.m_farClip);
cameraState.VerticalFovRadian(), AspectRatio(cameraState.m_viewportSize), cameraState.m_nearClip, cameraState.m_farClip);
}
AZ::Matrix4x4 InverseCameraProjection(const CameraState& cameraState)
@@ -93,12 +92,11 @@ namespace AzFramework
const auto cameraWorldTransform = AZ::Transform::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateFromMatrix4x4(worldFromView), worldFromView.GetTranslation());
return AZ::ViewFrustumAttributes(
cameraWorldTransform, AspectRatio(cameraState.m_viewportSize), cameraState.m_fovOrZoom,
cameraState.m_nearClip, cameraState.m_farClip);
cameraWorldTransform, AspectRatio(cameraState.m_viewportSize), cameraState.m_fovOrZoom, cameraState.m_nearClip,
cameraState.m_farClip);
}
AZ::Vector3 WorldToScreenNDC(
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection)
AZ::Vector3 WorldToScreenNdc(const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection)
{
// transform the world space position to clip space
const auto clipSpacePosition = cameraProjection * cameraView * AZ::Vector3ToVector4(worldPosition, 1.0f);
@@ -108,25 +106,24 @@ namespace AzFramework
return (AZ::Vector4ToVector3(ndcPosition) + AZ::Vector3::CreateOne()) * 0.5f;
}
ScreenPoint WorldToScreen(
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection,
const AZ::Vector3& worldPosition,
const AZ::Matrix4x4& cameraView,
const AZ::Matrix4x4& cameraProjection,
const AZ::Vector2& viewportSize)
{
const auto ndcNormalizedPosition = WorldToScreenNDC(worldPosition, cameraView, cameraProjection);
const auto ndcNormalizedPosition = WorldToScreenNdc(worldPosition, cameraView, cameraProjection);
// scale ndc position by screen dimensions to return screen position
return ScreenPointFromNDC(ndcNormalizedPosition, viewportSize);
return ScreenPointFromNdc(AZ::Vector3ToVector2(ndcNormalizedPosition), viewportSize);
}
ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState)
{
return WorldToScreen(
worldPosition, CameraView(cameraState), CameraProjection(cameraState), cameraState.m_viewportSize);
return WorldToScreen(worldPosition, CameraView(cameraState), CameraProjection(cameraState), cameraState.m_viewportSize);
}
AZ::Vector3 ScreenNDCToWorld(
const AZ::Vector2& normalizedScreenPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection)
AZ::Vector3 ScreenNdcToWorld(
const AZ::Vector2& normalizedScreenPosition, const AZ::Matrix4x4& inverseCameraView, const AZ::Matrix4x4& inverseCameraProjection)
{
// convert screen space coordinates from <0, 1> to <-1,1> range
const auto ndcPosition = normalizedScreenPosition * 2.0f - AZ::Vector2::CreateOne();
@@ -142,18 +139,19 @@ namespace AzFramework
}
AZ::Vector3 ScreenToWorld(
const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize)
const ScreenPoint& screenPosition,
const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection,
const AZ::Vector2& viewportSize)
{
const auto normalizedScreenPosition = NDCFromScreenPoint(screenPosition, viewportSize);
const auto normalizedScreenPosition = NdcFromScreenPoint(screenPosition, viewportSize);
return ScreenNDCToWorld(normalizedScreenPosition, inverseCameraView, inverseCameraProjection);
return ScreenNdcToWorld(normalizedScreenPosition, inverseCameraView, inverseCameraProjection);
}
AZ::Vector3 ScreenToWorld(const ScreenPoint& screenPosition, const CameraState& cameraState)
{
return ScreenToWorld(
screenPosition, InverseCameraView(cameraState), InverseCameraProjection(cameraState),
cameraState.m_viewportSize);
screenPosition, InverseCameraView(cameraState), InverseCameraProjection(cameraState), cameraState.m_viewportSize);
}
} // namespace AzFramework
@@ -8,26 +8,42 @@
#pragma once
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Math/Vector3.h>
#include <AzFramework/Viewport/ScreenGeometry.h>
namespace AZ
{
class Frustum;
class Matrix4x4;
class Vector3;
struct ViewFrustumAttributes;
} // namespace AZ
namespace AzFramework
{
struct CameraState;
struct ScreenPoint;
struct ViewportInfo;
//! Projects a position in world space to screen space normalized device coordinates for the given camera.
AZ::Vector3 WorldToScreenNDC(
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection);
//! Returns a position in screen space (in the range [0-viewportSize.x, 0-viewportSize.y]) from normalized device
//! coordinates (in the range 0.0-1.0).
inline ScreenPoint ScreenPointFromNdc(const AZ::Vector2& screenNdc, const AZ::Vector2& viewportSize)
{
return ScreenPoint(
aznumeric_cast<int>(AZStd::lround(screenNdc.GetX() * viewportSize.GetX())),
aznumeric_cast<int>(AZStd::lround((1.0f - screenNdc.GetY()) * viewportSize.GetY())));
}
//! Returns a position in normalized device coordinates (in the range [0.0-1.0, 0.0-1.0]) from a
//! screen space position (in the range [0-viewportSize.x, 0-viewportSize.y]).
inline AZ::Vector2 NdcFromScreenPoint(const ScreenPoint& screenPoint, const AZ::Vector2& viewportSize)
{
return AZ::Vector2(aznumeric_cast<float>(screenPoint.m_x), viewportSize.GetY() - aznumeric_cast<float>(screenPoint.m_y)) /
viewportSize;
}
//! Projects a position in world space to screen space normalized device coordinates for the given camera.
AZ::Vector3 WorldToScreenNdc(const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection);
//! Projects a position in world space to screen space for the given camera.
ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState);
@@ -35,7 +51,9 @@ namespace AzFramework
//! Overload of WorldToScreen that accepts camera values that can be precomputed if this function
//! is called many times in a loop.
ScreenPoint WorldToScreen(
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection,
const AZ::Vector3& worldPosition,
const AZ::Matrix4x4& cameraView,
const AZ::Matrix4x4& cameraProjection,
const AZ::Vector2& viewportSize);
//! Unprojects a position in screen space pixel coordinates to world space.
@@ -45,14 +63,15 @@ namespace AzFramework
//! Overload of ScreenToWorld that accepts camera values that can be precomputed if this function
//! is called many times in a loop.
AZ::Vector3 ScreenToWorld(
const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize);
const ScreenPoint& screenPosition,
const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection,
const AZ::Vector2& viewportSize);
//! Unprojects a position in screen space normalized device coordinates to world space.
//! Note: The position returned will be on the near clip plane of the camera in world space.
AZ::Vector3 ScreenNDCToWorld(
const AZ::Vector2& ndcPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection);
AZ::Vector3 ScreenNdcToWorld(
const AZ::Vector2& ndcPosition, const AZ::Matrix4x4& inverseCameraView, const AZ::Matrix4x4& inverseCameraProjection);
//! Returns the camera projection for the current camera state.
AZ::Matrix4x4 CameraProjection(const CameraState& cameraState);