Fixes for viewport selection issues (#5494)
* improvements to editor selection in the viewport Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * fix issue with being able to select icons that are not showing for entities inside entity containers Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * update comment after review feedback Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * updates to viewport picking code to simplify the api Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add test to replicate near clip intersection issue Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * small tidy-up changes Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * updates to how we perform world to screen and screen to world calculations, added test coverage and some tidy-up Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add some more tests for ViewportInteractionImpl Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * minor tweaks before PR feedback Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * fix typo in fix Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * fix for manipulator test framework tests Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * updates to RPI::View and RenderPipeline after review feedback from VickyAtAZ Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add constexpr to ScreenPoint, ScreenVector and ScreenSize initializing constructors Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add PrintTo functions for Screen* types Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * downgrade error to warning temporarily Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * check incoming view is null Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * remove pragma optimize off Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
ef16207ac5
commit
e34ea3bcaa
@@ -8,18 +8,18 @@
|
||||
|
||||
#include "CameraState.h"
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Math/Matrix3x4.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void SetCameraClippingVolume(
|
||||
AzFramework::CameraState& cameraState, const float nearPlane, const float farPlane, const float fovRad)
|
||||
AzFramework::CameraState& cameraState, const float nearPlane, const float farPlane, const float verticalFovRad)
|
||||
{
|
||||
cameraState.m_nearClip = nearPlane;
|
||||
cameraState.m_farClip = farPlane;
|
||||
cameraState.m_fovOrZoom = fovRad;
|
||||
cameraState.m_fovOrZoom = verticalFovRad;
|
||||
}
|
||||
|
||||
void SetCameraTransform(CameraState& cameraState, const AZ::Transform& transform)
|
||||
@@ -35,20 +35,34 @@ namespace AzFramework
|
||||
SetCameraClippingVolume(cameraState, 0.1f, 1000.0f, AZ::DegToRad(60.0f));
|
||||
}
|
||||
|
||||
AzFramework::CameraState CreateDefaultCamera(
|
||||
const AZ::Transform& transform, const AZ::Vector2& viewportSize)
|
||||
CameraState CreateCamera(
|
||||
const AZ::Transform& transform,
|
||||
const float nearPlane,
|
||||
const float farPlane,
|
||||
const float verticalFovRad,
|
||||
const AZ::Vector2& viewportSize)
|
||||
{
|
||||
AzFramework::CameraState cameraState;
|
||||
|
||||
SetDefaultCameraClippingVolume(cameraState);
|
||||
SetCameraTransform(cameraState, transform);
|
||||
SetCameraClippingVolume(cameraState, nearPlane, farPlane, verticalFovRad);
|
||||
cameraState.m_viewportSize = viewportSize;
|
||||
|
||||
return cameraState;
|
||||
}
|
||||
|
||||
AzFramework::CameraState CreateIdentityDefaultCamera(
|
||||
const AZ::Vector3& position, const AZ::Vector2& viewportSize)
|
||||
AzFramework::CameraState CreateDefaultCamera(const AZ::Transform& transform, const AZ::Vector2& viewportSize)
|
||||
{
|
||||
AzFramework::CameraState cameraState;
|
||||
|
||||
SetCameraTransform(cameraState, transform);
|
||||
SetDefaultCameraClippingVolume(cameraState);
|
||||
cameraState.m_viewportSize = viewportSize;
|
||||
|
||||
return cameraState;
|
||||
}
|
||||
|
||||
AzFramework::CameraState CreateIdentityDefaultCamera(const AZ::Vector3& position, const AZ::Vector2& viewportSize)
|
||||
{
|
||||
return CreateDefaultCamera(AZ::Transform::CreateTranslation(position), viewportSize);
|
||||
}
|
||||
@@ -89,15 +103,15 @@ namespace AzFramework
|
||||
|
||||
void CameraState::Reflect(AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
serializeContext.Class<CameraState>()->
|
||||
Field("Position", &CameraState::m_position)->
|
||||
Field("Forward", &CameraState::m_forward)->
|
||||
Field("Side", &CameraState::m_side)->
|
||||
Field("Up", &CameraState::m_up)->
|
||||
Field("ViewportSize", &CameraState::m_viewportSize)->
|
||||
Field("NearClip", &CameraState::m_nearClip)->
|
||||
Field("FarClip", &CameraState::m_farClip)->
|
||||
Field("FovZoom", &CameraState::m_fovOrZoom)->
|
||||
Field("Ortho", &CameraState::m_orthographic);
|
||||
serializeContext.Class<CameraState>()
|
||||
->Field("Position", &CameraState::m_position)
|
||||
->Field("Forward", &CameraState::m_forward)
|
||||
->Field("Side", &CameraState::m_side)
|
||||
->Field("Up", &CameraState::m_up)
|
||||
->Field("ViewportSize", &CameraState::m_viewportSize)
|
||||
->Field("NearClip", &CameraState::m_nearClip)
|
||||
->Field("FarClip", &CameraState::m_farClip)
|
||||
->Field("FovZoom", &CameraState::m_fovOrZoom)
|
||||
->Field("Ortho", &CameraState::m_orthographic);
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -40,10 +40,14 @@ namespace AzFramework
|
||||
AZ::Vector2 m_viewportSize = AZ::Vector2::CreateZero(); //!< Dimensions of the viewport.
|
||||
float m_nearClip = 0.01f; //!< Near clip plane of the camera.
|
||||
float m_farClip = 100.0f; //!< Far clip plane of the camera.
|
||||
float m_fovOrZoom = 0.0f; //!< Fov or zoom of camera depending on if it is using orthographic projection or not.
|
||||
float m_fovOrZoom = 0.0f; //!< Vertical fov or zoom of camera depending on if it is using orthographic projection or not.
|
||||
bool m_orthographic = false; //!< Is the camera using orthographic projection or not.
|
||||
};
|
||||
|
||||
//! Create a camera at the given transform, specifying the near and far clip planes as well as the fov with a specific viewport size.
|
||||
CameraState CreateCamera(
|
||||
const AZ::Transform& transform, float nearPlane, float farPlane, float verticalFovRad, const AZ::Vector2& viewportSize);
|
||||
|
||||
//! Create a camera at the given transform with a specific viewport size.
|
||||
//! @note The near/far clip planes and fov are sensible default values - please
|
||||
//! use SetCameraClippingVolume to override them.
|
||||
@@ -60,7 +64,7 @@ namespace AzFramework
|
||||
CameraState CreateCameraFromWorldFromViewMatrix(const AZ::Matrix4x4& worldFromView, const AZ::Vector2& viewportSize);
|
||||
|
||||
//! Override the default near/far clipping planes and fov of the camera.
|
||||
void SetCameraClippingVolume(CameraState& cameraState, float nearPlane, float farPlane, float fovRad);
|
||||
void SetCameraClippingVolume(CameraState& cameraState, float nearPlane, float farPlane, float verticalFovRad);
|
||||
|
||||
//! Override the default near/far clipping planes and fov of the camera by inferring them the specified right handed transform into clip space.
|
||||
void SetCameraClippingVolumeFromPerspectiveFovMatrixRH(CameraState& cameraState, const AZ::Matrix4x4& clipFromView);
|
||||
|
||||
@@ -24,6 +24,10 @@ namespace AzFramework
|
||||
serializeContext->Class<ScreenVector>()->
|
||||
Field("X", &ScreenVector::m_x)->
|
||||
Field("Y", &ScreenVector::m_y);
|
||||
|
||||
serializeContext->Class<ScreenSize>()->
|
||||
Field("Width", &ScreenSize::m_width)->
|
||||
Field("Height", &ScreenSize::m_height);
|
||||
}
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace AzFramework
|
||||
AZ_TYPE_INFO(ScreenPoint, "{8472B6C2-527F-44FC-87F8-C226B1A57A97}");
|
||||
ScreenPoint() = default;
|
||||
|
||||
ScreenPoint(int x, int y)
|
||||
constexpr ScreenPoint(int x, int y)
|
||||
: m_x(x)
|
||||
, m_y(y)
|
||||
{
|
||||
@@ -45,7 +45,7 @@ namespace AzFramework
|
||||
AZ_TYPE_INFO(ScreenVector, "{1EAA2C62-8FDB-4A28-9FE3-1FA4F1418894}");
|
||||
ScreenVector() = default;
|
||||
|
||||
ScreenVector(int x, int y)
|
||||
constexpr ScreenVector(int x, int y)
|
||||
: m_x(x)
|
||||
, m_y(y)
|
||||
{
|
||||
@@ -55,6 +55,22 @@ namespace AzFramework
|
||||
int m_y; //!< Y screen delta.
|
||||
};
|
||||
|
||||
//! A wrapper around a screen width and height.
|
||||
struct ScreenSize
|
||||
{
|
||||
AZ_TYPE_INFO(ScreenSize, "{26D28916-6E8E-44B8-83F9-C44BCDA370E2}");
|
||||
ScreenSize() = default;
|
||||
|
||||
constexpr ScreenSize(int width, int height)
|
||||
: m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
int m_width; //!< Screen size width.
|
||||
int m_height; //!< Screen size height.
|
||||
};
|
||||
|
||||
void ScreenGeometryReflect(AZ::ReflectContext* context);
|
||||
|
||||
inline const ScreenVector operator-(const ScreenPoint& lhs, const ScreenPoint& rhs)
|
||||
@@ -138,6 +154,16 @@ namespace AzFramework
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
inline const bool operator==(const ScreenSize& lhs, const ScreenSize& rhs)
|
||||
{
|
||||
return lhs.m_width == rhs.m_width && lhs.m_height == rhs.m_height;
|
||||
}
|
||||
|
||||
inline const bool operator!=(const ScreenSize& lhs, const ScreenSize& rhs)
|
||||
{
|
||||
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));
|
||||
@@ -152,6 +178,20 @@ namespace AzFramework
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ScreenSize& operator*=(ScreenSize& lhs, const float rhs)
|
||||
{
|
||||
lhs.m_width = aznumeric_cast<int>(AZStd::lround(aznumeric_cast<float>(lhs.m_width) * rhs));
|
||||
lhs.m_height = aznumeric_cast<int>(AZStd::lround(aznumeric_cast<float>(lhs.m_height) * rhs));
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline const ScreenSize operator*(const ScreenSize& lhs, const float rhs)
|
||||
{
|
||||
ScreenSize 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));
|
||||
@@ -168,4 +208,28 @@ namespace AzFramework
|
||||
{
|
||||
return AZ::Vector2(aznumeric_cast<float>(screenVector.m_x), aznumeric_cast<float>(screenVector.m_y));
|
||||
}
|
||||
|
||||
//! Return an AZ::Vector2 from a ScreenSize.
|
||||
inline AZ::Vector2 Vector2FromScreenSize(const ScreenSize& screenSize)
|
||||
{
|
||||
return AZ::Vector2(aznumeric_cast<float>(screenSize.m_width), aznumeric_cast<float>(screenSize.m_height));
|
||||
}
|
||||
|
||||
//! Return a ScreenPoint from an AZ::Vector2.
|
||||
inline ScreenPoint ScreenPointFromVector2(const AZ::Vector2& vector2)
|
||||
{
|
||||
return ScreenPoint(aznumeric_cast<int>(AZStd::lround(vector2.GetX())), aznumeric_cast<int>(AZStd::lround(vector2.GetY())));
|
||||
}
|
||||
|
||||
//! Return a ScreenVector from an AZ::Vector2.
|
||||
inline ScreenVector ScreenVectorFromVector2(const AZ::Vector2& vector2)
|
||||
{
|
||||
return ScreenVector(aznumeric_cast<int>(AZStd::lround(vector2.GetX())), aznumeric_cast<int>(AZStd::lround(vector2.GetY())));
|
||||
}
|
||||
|
||||
//! Return a ScreenSize from an AZ::Vector2.
|
||||
inline ScreenSize ScreenSizeFromVector2(const AZ::Vector2& vector2)
|
||||
{
|
||||
return ScreenSize(aznumeric_cast<int>(AZStd::lround(vector2.GetX())), aznumeric_cast<int>(AZStd::lround(vector2.GetY())));
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Math/Frustum.h>
|
||||
#include <AzCore/Math/Matrix4x4.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/Math/Vector4.h>
|
||||
#include <AzCore/Math/VectorConversions.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
@@ -112,9 +113,8 @@ namespace AzFramework
|
||||
const AZ::Matrix4x4& cameraProjection,
|
||||
const AZ::Vector2& viewportSize)
|
||||
{
|
||||
const auto ndcNormalizedPosition = WorldToScreenNdc(worldPosition, cameraView, cameraProjection);
|
||||
// scale ndc position by screen dimensions to return screen position
|
||||
return ScreenPointFromNdc(AZ::Vector3ToVector2(ndcNormalizedPosition), viewportSize);
|
||||
return ScreenPointFromNdc(AZ::Vector3ToVector2(WorldToScreenNdc(worldPosition, cameraView, cameraProjection)), viewportSize);
|
||||
}
|
||||
|
||||
ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState)
|
||||
@@ -144,9 +144,7 @@ namespace AzFramework
|
||||
const AZ::Matrix4x4& inverseCameraProjection,
|
||||
const AZ::Vector2& viewportSize)
|
||||
{
|
||||
const auto normalizedScreenPosition = NdcFromScreenPoint(screenPosition, viewportSize);
|
||||
|
||||
return ScreenNdcToWorld(normalizedScreenPosition, inverseCameraView, inverseCameraProjection);
|
||||
return ScreenNdcToWorld(NdcFromScreenPoint(screenPosition, viewportSize), inverseCameraView, inverseCameraProjection);
|
||||
}
|
||||
|
||||
AZ::Vector3 ScreenToWorld(const ScreenPoint& screenPosition, const CameraState& cameraState)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||
#include <AzCore/Math/SimdMath.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/Math/Matrix4x4.h>
|
||||
|
||||
namespace UnitTest
|
||||
@@ -51,22 +52,6 @@ namespace UnitTest
|
||||
{
|
||||
};
|
||||
|
||||
// Taken from Atom::MatrixUtils for testing purposes, this can be removed if MakePerspectiveFovMatrixRH makes it into AZ
|
||||
static AZ::Matrix4x4 MakePerspectiveMatrixRH(float fovY, float aspectRatio, float nearClip, float farClip)
|
||||
{
|
||||
float sinFov, cosFov;
|
||||
AZ::SinCos(0.5f * fovY, sinFov, cosFov);
|
||||
float yScale = cosFov / sinFov; //cot(fovY/2)
|
||||
float xScale = yScale / aspectRatio;
|
||||
|
||||
AZ::Matrix4x4 out;
|
||||
out.SetRow(0, xScale, 0.f, 0.f, 0.f );
|
||||
out.SetRow(1, 0.f, yScale, 0.f, 0.f );
|
||||
out.SetRow(2, 0.f, 0.f, farClip / (nearClip - farClip), nearClip*farClip / (nearClip - farClip) );
|
||||
out.SetRow(3, 0.f, 0.f, -1.f, 0.f );
|
||||
return out;
|
||||
}
|
||||
|
||||
TEST_P(Translation, Permutation)
|
||||
{
|
||||
// Given a position
|
||||
@@ -176,7 +161,8 @@ namespace UnitTest
|
||||
{
|
||||
auto [fovY, aspectRatio, nearClip, farClip] = GetParam();
|
||||
|
||||
AZ::Matrix4x4 clipFromView = MakePerspectiveMatrixRH(fovY, aspectRatio, nearClip, farClip);
|
||||
AZ::Matrix4x4 clipFromView;
|
||||
MakePerspectiveFovMatrixRH(clipFromView, fovY, aspectRatio, nearClip, farClip);
|
||||
|
||||
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(m_cameraState, clipFromView);
|
||||
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Viewport/CursorState.h>
|
||||
#include <Tests/Utils/Printers.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using AzFramework::CursorState;
|
||||
using AzFramework::ScreenVector;
|
||||
using AzFramework::ScreenPoint;
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
class CursorStateFixture : public ::testing::Test
|
||||
{
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Printers.h"
|
||||
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void PrintTo(const ScreenPoint& screenPoint, std::ostream* os)
|
||||
{
|
||||
*os << "(x: " << screenPoint.m_x << ", y: " << screenPoint.m_y << ")";
|
||||
}
|
||||
|
||||
void PrintTo(const ScreenVector& screenVector, std::ostream* os)
|
||||
{
|
||||
*os << "(x: " << screenVector.m_x << ", y: " << screenVector.m_y << ")";
|
||||
}
|
||||
|
||||
void PrintTo(const ScreenSize& screenSize, std::ostream* os)
|
||||
{
|
||||
*os << "(width: " << screenSize.m_width << ", height: " << screenSize.m_height << ")";
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct ScreenPoint;
|
||||
struct ScreenVector;
|
||||
struct ScreenSize;
|
||||
|
||||
void PrintTo(const ScreenPoint& screenPoint, std::ostream* os);
|
||||
void PrintTo(const ScreenVector& screenVector, std::ostream* os);
|
||||
void PrintTo(const ScreenSize& screenSize, std::ostream* os);
|
||||
} // namespace AzFramework
|
||||
@@ -11,5 +11,7 @@ set(FILES
|
||||
Mocks/MockWindowRequests.h
|
||||
Utils/Utils.h
|
||||
Utils/Utils.cpp
|
||||
Utils/Printers.h
|
||||
Utils/Printers.cpp
|
||||
FrameworkApplicationFixture.h
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user