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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user