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
@@ -547,13 +547,6 @@ QPoint Q2DViewport::WorldToView(const Vec3& wp) const
|
||||
QPoint p = QPoint(static_cast<int>(sp.x), static_cast<int>(sp.y));
|
||||
return p;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
QPoint Q2DViewport::WorldToViewParticleEditor(const Vec3& wp, [[maybe_unused]] int width, [[maybe_unused]] int height) const //Eric@conffx implement for the children class of IDisplayViewport
|
||||
{
|
||||
Vec3 sp = m_screenTM.TransformPoint(wp);
|
||||
QPoint p = QPoint(static_cast<int>(sp.x), static_cast<int>(sp.y));
|
||||
return p;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
Vec3 Q2DViewport::ViewToWorld(const QPoint& vp, [[maybe_unused]] bool* collideWithTerrain, [[maybe_unused]] bool onlyTerrain, [[maybe_unused]] bool bSkipVegetation, [[maybe_unused]] bool bTestRenderMesh, [[maybe_unused]] bool* collideWithObject) const
|
||||
|
||||
@@ -50,8 +50,6 @@ public:
|
||||
//! Map world space position to viewport position.
|
||||
QPoint WorldToView(const Vec3& wp) const override;
|
||||
|
||||
QPoint WorldToViewParticleEditor(const Vec3& wp, int width, int height) const override; //Eric@conffx
|
||||
|
||||
//! Map viewport position to world space position.
|
||||
Vec3 ViewToWorld(const QPoint& vp, bool* collideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const override;
|
||||
//! Map viewport position to world space ray from camera.
|
||||
|
||||
@@ -299,13 +299,9 @@ AzToolsFramework::ViewportInteraction::MousePick EditorViewportWidget::BuildMous
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::MousePick mousePick;
|
||||
mousePick.m_screenCoordinates = AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(point);
|
||||
if (const auto& ray = m_renderViewport->ViewportScreenToWorldRay(mousePick.m_screenCoordinates);
|
||||
ray.has_value())
|
||||
{
|
||||
mousePick.m_rayOrigin = ray.value().origin;
|
||||
mousePick.m_rayDirection = ray.value().direction;
|
||||
}
|
||||
|
||||
const auto[origin, direction] = m_renderViewport->ViewportScreenToWorldRay(mousePick.m_screenCoordinates);
|
||||
mousePick.m_rayOrigin = origin;
|
||||
mousePick.m_rayDirection = direction;
|
||||
return mousePick;
|
||||
}
|
||||
|
||||
@@ -912,23 +908,6 @@ AZ::Vector3 EditorViewportWidget::PickTerrain(const AzFramework::ScreenPoint& po
|
||||
return LYVec3ToAZVec3(ViewToWorld(AzToolsFramework::ViewportInteraction::QPointFromScreenPoint(point), nullptr, true));
|
||||
}
|
||||
|
||||
AZ::EntityId EditorViewportWidget::PickEntity(const AzFramework::ScreenPoint& point)
|
||||
{
|
||||
AZ::EntityId entityId;
|
||||
HitContext hitInfo;
|
||||
hitInfo.view = this;
|
||||
if (HitTest(AzToolsFramework::ViewportInteraction::QPointFromScreenPoint(point), hitInfo))
|
||||
{
|
||||
if (hitInfo.object && (hitInfo.object->GetType() == OBJTYPE_AZENTITY))
|
||||
{
|
||||
auto entityObject = static_cast<CComponentEntityObject*>(hitInfo.object);
|
||||
entityId = entityObject->GetAssociatedEntityId();
|
||||
}
|
||||
}
|
||||
|
||||
return entityId;
|
||||
}
|
||||
|
||||
float EditorViewportWidget::TerrainHeight(const AZ::Vector2& position)
|
||||
{
|
||||
return GetIEditor()->GetTerrainElevation(position.GetX(), position.GetY());
|
||||
@@ -1653,16 +1632,15 @@ void EditorViewportWidget::RenderSelectedRegion()
|
||||
Vec3 EditorViewportWidget::WorldToView3D(const Vec3& wp, [[maybe_unused]] int nFlags) const
|
||||
{
|
||||
Vec3 out(0, 0, 0);
|
||||
float x, y, z;
|
||||
float x, y;
|
||||
|
||||
ProjectToScreen(wp.x, wp.y, wp.z, &x, &y, &z);
|
||||
if (_finite(x) && _finite(y) && _finite(z))
|
||||
ProjectToScreen(wp.x, wp.y, wp.z, &x, &y);
|
||||
if (_finite(x) && _finite(y))
|
||||
{
|
||||
out.x = (x / 100) * m_rcClient.width();
|
||||
out.y = (y / 100) * m_rcClient.height();
|
||||
out.x /= static_cast<float>(QHighDpiScaling::factor(windowHandle()->screen()));
|
||||
out.y /= static_cast<float>(QHighDpiScaling::factor(windowHandle()->screen()));
|
||||
out.z = z;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -1672,24 +1650,6 @@ QPoint EditorViewportWidget::WorldToView(const Vec3& wp) const
|
||||
{
|
||||
return AzToolsFramework::ViewportInteraction::QPointFromScreenPoint(m_renderViewport->ViewportWorldToScreen(LYVec3ToAZVec3(wp)));
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
QPoint EditorViewportWidget::WorldToViewParticleEditor(const Vec3& wp, int width, int height) const
|
||||
{
|
||||
QPoint p;
|
||||
float x, y, z;
|
||||
|
||||
ProjectToScreen(wp.x, wp.y, wp.z, &x, &y, &z);
|
||||
if (_finite(x) || _finite(y))
|
||||
{
|
||||
p.rx() = static_cast<int>((x / 100) * width);
|
||||
p.ry() = static_cast<int>((y / 100) * height);
|
||||
}
|
||||
else
|
||||
{
|
||||
QPoint(0, 0);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
Vec3 EditorViewportWidget::ViewToWorld(
|
||||
@@ -1705,20 +1665,16 @@ Vec3 EditorViewportWidget::ViewToWorld(
|
||||
AZ_UNUSED(collideWithObject);
|
||||
|
||||
auto ray = m_renderViewport->ViewportScreenToWorldRay(AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(vp));
|
||||
if (!ray.has_value())
|
||||
{
|
||||
return Vec3(0, 0, 0);
|
||||
}
|
||||
|
||||
const float maxDistance = 10000.f;
|
||||
Vec3 v = AZVec3ToLYVec3(ray.value().direction) * maxDistance;
|
||||
Vec3 v = AZVec3ToLYVec3(ray.direction) * maxDistance;
|
||||
|
||||
if (!_finite(v.x) || !_finite(v.y) || !_finite(v.z))
|
||||
{
|
||||
return Vec3(0, 0, 0);
|
||||
}
|
||||
|
||||
Vec3 colp = AZVec3ToLYVec3(ray.value().origin) + 0.002f * v;
|
||||
Vec3 colp = AZVec3ToLYVec3(ray.origin) + 0.002f * v;
|
||||
|
||||
return colp;
|
||||
}
|
||||
@@ -1757,21 +1713,19 @@ bool EditorViewportWidget::RayRenderMeshIntersection(IRenderMesh* pRenderMesh, c
|
||||
return bRes;*/
|
||||
}
|
||||
|
||||
void EditorViewportWidget::UnProjectFromScreen(float sx, float sy, float sz, float* px, float* py, float* pz) const
|
||||
void EditorViewportWidget::UnProjectFromScreen(float sx, float sy, float* px, float* py, float* pz) const
|
||||
{
|
||||
AZ::Vector3 wp;
|
||||
wp = m_renderViewport->ViewportScreenToWorld(AzFramework::ScreenPoint{(int)sx, m_rcClient.bottom() - ((int)sy)}, sz).value_or(wp);
|
||||
const AZ::Vector3 wp = m_renderViewport->ViewportScreenToWorld(AzFramework::ScreenPoint{(int)sx, m_rcClient.bottom() - ((int)sy)});
|
||||
*px = wp.GetX();
|
||||
*py = wp.GetY();
|
||||
*pz = wp.GetZ();
|
||||
}
|
||||
|
||||
void EditorViewportWidget::ProjectToScreen(float ptx, float pty, float ptz, float* sx, float* sy, float* sz) const
|
||||
void EditorViewportWidget::ProjectToScreen(float ptx, float pty, float ptz, float* sx, float* sy) const
|
||||
{
|
||||
AzFramework::ScreenPoint screenPosition = m_renderViewport->ViewportWorldToScreen(AZ::Vector3{ptx, pty, ptz});
|
||||
*sx = static_cast<float>(screenPosition.m_x);
|
||||
*sy = static_cast<float>(screenPosition.m_y);
|
||||
*sz = 0.f;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -1781,32 +1735,22 @@ void EditorViewportWidget::ViewToWorldRay(const QPoint& vp, Vec3& raySrc, Vec3&
|
||||
|
||||
Vec3 pos0, pos1;
|
||||
float wx, wy, wz;
|
||||
UnProjectFromScreen(static_cast<float>(vp.x()), static_cast<float>(rc.bottom() - vp.y()), 0.0f, &wx, &wy, &wz);
|
||||
if (!_finite(wx) || !_finite(wy) || !_finite(wz))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fabs(wx) > 1000000 || fabs(wy) > 1000000 || fabs(wz) > 1000000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
pos0(wx, wy, wz);
|
||||
UnProjectFromScreen(static_cast<float>(vp.x()), static_cast<float>(rc.bottom() - vp.y()), 1.0f, &wx, &wy, &wz);
|
||||
if (!_finite(wx) || !_finite(wy) || !_finite(wz))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fabs(wx) > 1000000 || fabs(wy) > 1000000 || fabs(wz) > 1000000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
pos1(wx, wy, wz);
|
||||
UnProjectFromScreen(static_cast<float>(vp.x()), static_cast<float>(rc.bottom() - vp.y()), &wx, &wy, &wz);
|
||||
|
||||
Vec3 v = (pos1 - pos0);
|
||||
v = v.GetNormalized();
|
||||
if (!_finite(wx) || !_finite(wy) || !_finite(wz))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (fabs(wx) > 1000000 || fabs(wy) > 1000000 || fabs(wz) > 1000000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pos0(wx, wy, wz);
|
||||
|
||||
raySrc = pos0;
|
||||
rayDir = v;
|
||||
rayDir = (pos0 - AZVec3ToLYVec3(m_renderViewport->GetCameraState().m_position)).GetNormalized();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -166,7 +166,6 @@ private:
|
||||
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, const QPoint& point) override;
|
||||
void SetViewportId(int id) override;
|
||||
QPoint WorldToView(const Vec3& wp) const override;
|
||||
QPoint WorldToViewParticleEditor(const Vec3& wp, int width, int height) const override;
|
||||
Vec3 WorldToView3D(const Vec3& wp, int nFlags = 0) const override;
|
||||
Vec3 ViewToWorld(const QPoint& vp, bool* collideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const override;
|
||||
void ViewToWorldRay(const QPoint& vp, Vec3& raySrc, Vec3& rayDir) const override;
|
||||
@@ -208,7 +207,6 @@ private:
|
||||
void* GetSystemCursorConstraintWindow() const override;
|
||||
|
||||
// AzToolsFramework::MainEditorViewportInteractionRequestBus overrides ...
|
||||
AZ::EntityId PickEntity(const AzFramework::ScreenPoint& point) override;
|
||||
AZ::Vector3 PickTerrain(const AzFramework::ScreenPoint& point) override;
|
||||
float TerrainHeight(const AZ::Vector2& position) override;
|
||||
bool ShowingWorldSpace() override;
|
||||
@@ -306,8 +304,8 @@ private:
|
||||
const DisplayContext& GetDisplayContext() const { return m_displayContext; }
|
||||
CBaseObject* GetCameraObject() const;
|
||||
|
||||
void UnProjectFromScreen(float sx, float sy, float sz, float* px, float* py, float* pz) const;
|
||||
void ProjectToScreen(float ptx, float pty, float ptz, float* sx, float* sy, float* sz) const;
|
||||
void UnProjectFromScreen(float sx, float sy, float* px, float* py, float* pz) const;
|
||||
void ProjectToScreen(float ptx, float pty, float ptz, float* sx, float* sy) const;
|
||||
|
||||
AZ::RPI::ViewPtr GetCurrentAtomView() const;
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ struct IDisplayViewport
|
||||
virtual const Matrix34& GetViewTM() const = 0;
|
||||
virtual const Matrix34& GetScreenTM() const = 0;
|
||||
virtual QPoint WorldToView(const Vec3& worldPoint) const = 0;
|
||||
virtual QPoint WorldToViewParticleEditor(const Vec3& worldPoint, int width, int height) const = 0;
|
||||
virtual Vec3 WorldToView3D(const Vec3& worldPoint, int flags = 0) const = 0;
|
||||
virtual Vec3 ViewToWorld(const QPoint& vp, bool* collideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const = 0;
|
||||
virtual void ViewToWorldRay(const QPoint& vp, Vec3& raySrc, Vec3& rayDir) const = 0;
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
#include "ViewportManipulatorController.h"
|
||||
|
||||
#include <AzCore/Script/ScriptTimePoint.h>
|
||||
#include <AzFramework/Input/Buses/Requests/InputSystemCursorRequestBus.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Buses/Requests/InputSystemCursorRequestBus.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzCore/Script/ScriptTimePoint.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
@@ -87,8 +89,14 @@ namespace SandboxEditor
|
||||
}
|
||||
|
||||
using InteractionBus = AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
|
||||
using namespace AzToolsFramework::ViewportInteraction;
|
||||
using AzFramework::InputChannel;
|
||||
using AzToolsFramework::ViewportInteraction::KeyboardModifier;
|
||||
using AzToolsFramework::ViewportInteraction::MouseButton;
|
||||
using AzToolsFramework::ViewportInteraction::MouseEvent;
|
||||
using AzToolsFramework::ViewportInteraction::MouseInteraction;
|
||||
using AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
|
||||
using AzToolsFramework::ViewportInteraction::ProjectedViewportRay;
|
||||
using AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus;
|
||||
|
||||
bool interactionHandled = false;
|
||||
float wheelDelta = 0.0f;
|
||||
@@ -117,16 +125,13 @@ namespace SandboxEditor
|
||||
aznumeric_cast<int>(position->m_normalizedPosition.GetX() * windowSize.m_width),
|
||||
aznumeric_cast<int>(position->m_normalizedPosition.GetY() * windowSize.m_height));
|
||||
|
||||
m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPoint;
|
||||
AZStd::optional<ProjectedViewportRay> ray;
|
||||
ProjectedViewportRay ray{};
|
||||
ViewportInteractionRequestBus::EventResult(
|
||||
ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPoint);
|
||||
|
||||
if (ray.has_value())
|
||||
{
|
||||
m_mouseInteraction.m_mousePick.m_rayOrigin = ray.value().origin;
|
||||
m_mouseInteraction.m_mousePick.m_rayDirection = ray.value().direction;
|
||||
}
|
||||
m_mouseInteraction.m_mousePick.m_rayOrigin = ray.origin;
|
||||
m_mouseInteraction.m_mousePick.m_rayDirection = ray.direction;
|
||||
m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPoint;
|
||||
}
|
||||
|
||||
eventType = MouseEvent::Move;
|
||||
@@ -160,8 +165,8 @@ namespace SandboxEditor
|
||||
else if (state == InputChannel::State::Ended)
|
||||
{
|
||||
// If we've actually logged a mouse down event, forward a mouse up event.
|
||||
// This prevents corner cases like the context menu thinking it should be opened even though no one clicked in this viewport,
|
||||
// due to RenderViewportWidget ensuring all controllers get InputChannel::State::Ended events.
|
||||
// This prevents corner cases like the context menu thinking it should be opened even though no one clicked in this
|
||||
// viewport, due to RenderViewportWidget ensuring all controllers get InputChannel::State::Ended events.
|
||||
if (m_mouseInteraction.m_mouseButtons.m_mouseButtons & mouseButtonValue)
|
||||
{
|
||||
// Erase the button from our state if we're done processing events.
|
||||
@@ -259,4 +264,4 @@ namespace SandboxEditor
|
||||
const double doubleClickThresholdMilliseconds = qApp->doubleClickInterval();
|
||||
return (m_curTime.GetMilliseconds() - clickIt->second.GetMilliseconds()) < doubleClickThresholdMilliseconds;
|
||||
}
|
||||
} //namespace SandboxEditor
|
||||
} // namespace SandboxEditor
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
+2
-2
@@ -41,8 +41,8 @@ namespace AzManipulatorTestFramework
|
||||
// ViewportInteractionRequestBus overrides ...
|
||||
AzFramework::CameraState GetCameraState() override;
|
||||
AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) override;
|
||||
AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override;
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportScreenToWorldRay(
|
||||
AZ::Vector3 ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition) override;
|
||||
AzToolsFramework::ViewportInteraction::ProjectedViewportRay ViewportScreenToWorldRay(
|
||||
const AzFramework::ScreenPoint& screenPosition) override;
|
||||
float DeviceScalingFactor() override;
|
||||
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ namespace AzManipulatorTestFramework
|
||||
|
||||
AzToolsFramework::ViewportInteraction::MousePick mousePick;
|
||||
mousePick.m_screenCoordinates = screenPoint;
|
||||
mousePick.m_rayOrigin = cameraState.m_position;
|
||||
mousePick.m_rayOrigin = nearPlaneWorldPosition;
|
||||
mousePick.m_rayDirection = (nearPlaneWorldPosition - cameraState.m_position).GetNormalized();
|
||||
|
||||
return mousePick;
|
||||
|
||||
@@ -69,8 +69,6 @@ namespace AzManipulatorTestFramework
|
||||
void ImmediateModeActionDispatcher::CameraStateImpl(const AzFramework::CameraState& cameraState)
|
||||
{
|
||||
m_viewportManipulatorInteraction.GetViewportInteraction().SetCameraState(cameraState);
|
||||
GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick.m_rayOrigin = cameraState.m_position;
|
||||
GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick.m_rayDirection = cameraState.m_forward;
|
||||
}
|
||||
|
||||
void ImmediateModeActionDispatcher::MouseLButtonDownImpl()
|
||||
|
||||
+2
-1
@@ -20,7 +20,8 @@ namespace AzManipulatorTestFramework
|
||||
{
|
||||
public:
|
||||
IndirectCallManipulatorManager(ViewportInteractionInterface& viewportInteraction);
|
||||
// ManipulatorManagerInterface ...
|
||||
|
||||
// ManipulatorManagerInterface overrides ...
|
||||
void ConsumeMouseInteractionEvent(const MouseInteractionEvent& event) override;
|
||||
AzToolsFramework::ManipulatorManagerId GetId() const override;
|
||||
bool ManipulatorBeingInteracted() const override;
|
||||
|
||||
@@ -140,13 +140,12 @@ namespace AzManipulatorTestFramework
|
||||
return m_viewportId;
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::Vector3> ViewportInteraction::ViewportScreenToWorld(
|
||||
[[maybe_unused]] const AzFramework::ScreenPoint& screenPosition, [[maybe_unused]] float depth)
|
||||
AZ::Vector3 ViewportInteraction::ViewportScreenToWorld([[maybe_unused]] const AzFramework::ScreenPoint& screenPosition)
|
||||
{
|
||||
return {};
|
||||
return AZ::Vector3::CreateZero();
|
||||
}
|
||||
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportInteraction::ViewportScreenToWorldRay(
|
||||
AzToolsFramework::ViewportInteraction::ProjectedViewportRay ViewportInteraction::ViewportScreenToWorldRay(
|
||||
[[maybe_unused]] const AzFramework::ScreenPoint& screenPosition)
|
||||
{
|
||||
return {};
|
||||
|
||||
@@ -140,8 +140,8 @@ namespace UnitTest
|
||||
// given a left mouse down ray in world space
|
||||
// consume the mouse move event
|
||||
state.m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState))
|
||||
->MouseLButtonDown()
|
||||
->ExpectTrue(state.m_linearManipulator->PerformingAction())
|
||||
->ExpectManipulatorBeingInteracted()
|
||||
->MouseLButtonUp()
|
||||
|
||||
+4
-1
@@ -158,7 +158,10 @@ namespace UnitTest
|
||||
{
|
||||
// Create & Start a new ToolsApplication if there's no existing one
|
||||
m_app = CreateTestApplication();
|
||||
m_app->Start(AzFramework::Application::Descriptor());
|
||||
AZ::ComponentApplication::StartupParameters startupParameters;
|
||||
startupParameters.m_loadAssetCatalog = false;
|
||||
|
||||
m_app->Start(AzFramework::Application::Descriptor(), startupParameters);
|
||||
}
|
||||
|
||||
// without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
|
||||
@@ -162,12 +162,11 @@ namespace AzToolsFramework
|
||||
//! Multiply by DeviceScalingFactor to get the position in viewport pixel space.
|
||||
virtual AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) = 0;
|
||||
//! Transforms a point from Qt widget screen space to world space based on the given clip space depth.
|
||||
//! Depth specifies a relative camera depth to project in the range of [0.f, 1.f].
|
||||
//! Returns the world space position if successful.
|
||||
virtual AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) = 0;
|
||||
virtual AZ::Vector3 ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition) = 0;
|
||||
//! Casts a point in screen space to a ray in world space originating from the viewport camera frustum's near plane.
|
||||
//! Returns a ray containing the ray's origin and a direction normal, if successful.
|
||||
virtual AZStd::optional<ProjectedViewportRay> ViewportScreenToWorldRay(const AzFramework::ScreenPoint& screenPosition) = 0;
|
||||
virtual ProjectedViewportRay ViewportScreenToWorldRay(const AzFramework::ScreenPoint& screenPosition) = 0;
|
||||
//! Gets the DPI scaling factor that translates Qt widget space into viewport pixel space.
|
||||
virtual float DeviceScalingFactor() = 0;
|
||||
|
||||
@@ -229,9 +228,6 @@ namespace AzToolsFramework
|
||||
class MainEditorViewportInteractionRequests
|
||||
{
|
||||
public:
|
||||
//! Given a point in screen space, return the picked entity (if any).
|
||||
//! Picked EntityId will be returned, InvalidEntityId will be returned on failure.
|
||||
virtual AZ::EntityId PickEntity(const AzFramework::ScreenPoint& point) = 0;
|
||||
//! Given a point in screen space, return the terrain position in world space.
|
||||
virtual AZ::Vector3 PickTerrain(const AzFramework::ScreenPoint& point) = 0;
|
||||
//! Return the terrain height given a world position in 2d (xy plane).
|
||||
@@ -266,7 +262,6 @@ namespace AzToolsFramework
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
//! Returns the current state of the keyboard modifier keys.
|
||||
virtual KeyboardModifiers QueryKeyboardModifiers() = 0;
|
||||
@@ -290,7 +285,6 @@ namespace AzToolsFramework
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
//! Returns the current time in seconds.
|
||||
//! This interface can be overridden for the purposes of testing to simplify viewport input requests.
|
||||
|
||||
+5
-3
@@ -148,7 +148,6 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
EditorHelpers::EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
|
||||
: m_entityDataCache(entityDataCache)
|
||||
{
|
||||
@@ -190,7 +189,10 @@ namespace AzToolsFramework
|
||||
if (helpersVisible)
|
||||
{
|
||||
// some components choose to hide their icons (e.g. meshes)
|
||||
if (!m_entityDataCache->IsVisibleEntityIconHidden(entityCacheIndex))
|
||||
// we also do not want to test against icons that may not be showing as they're inside a 'closed' entity container
|
||||
// (these icons only become visible when it is opened for editing)
|
||||
if (!m_entityDataCache->IsVisibleEntityIconHidden(entityCacheIndex) &&
|
||||
m_entityDataCache->IsVisibleEntityIndividuallySelectableInViewport(entityCacheIndex))
|
||||
{
|
||||
const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex);
|
||||
|
||||
@@ -235,7 +237,7 @@ namespace AzToolsFramework
|
||||
viewportId, &ViewportInteraction::ViewportMouseCursorRequestBus::Events::SetOverrideCursor,
|
||||
ViewportInteraction::CursorStyleOverride::Forbidden);
|
||||
}
|
||||
|
||||
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
|
||||
mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down ||
|
||||
mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::DoubleClick)
|
||||
|
||||
+2
-2
@@ -409,7 +409,7 @@ namespace AzToolsFramework
|
||||
const AzFramework::CameraState cameraState = GetCameraState(viewportId);
|
||||
for (size_t entityCacheIndex = 0; entityCacheIndex < entityDataCache.VisibleEntityDataCount(); ++entityCacheIndex)
|
||||
{
|
||||
if (!entityDataCache.IsVisibleEntitySelectableInViewport(entityCacheIndex))
|
||||
if (!entityDataCache.IsVisibleEntityIndividuallySelectableInViewport(entityCacheIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -983,7 +983,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (auto entityIndex = entityDataCache.GetVisibleEntityIndexFromId(entityId))
|
||||
{
|
||||
if (entityDataCache.IsVisibleEntitySelectableInViewport(*entityIndex))
|
||||
if (entityDataCache.IsVisibleEntityIndividuallySelectableInViewport(*entityIndex))
|
||||
{
|
||||
return *entityIndex;
|
||||
}
|
||||
|
||||
+3
-5
@@ -293,12 +293,10 @@ namespace AzToolsFramework
|
||||
return m_impl->m_visibleEntityDatas[index].m_iconHidden;
|
||||
}
|
||||
|
||||
bool EditorVisibleEntityDataCache::IsVisibleEntitySelectableInViewport(size_t index) const
|
||||
bool EditorVisibleEntityDataCache::IsVisibleEntityIndividuallySelectableInViewport(const size_t index) const
|
||||
{
|
||||
return m_impl->m_visibleEntityDatas[index].m_visible
|
||||
&& !m_impl->m_visibleEntityDatas[index].m_locked
|
||||
&& m_impl->m_visibleEntityDatas[index].m_inFocus
|
||||
&& !m_impl->m_visibleEntityDatas[index].m_descendantOfClosedContainer;
|
||||
return m_impl->m_visibleEntityDatas[index].m_visible && !m_impl->m_visibleEntityDatas[index].m_locked &&
|
||||
m_impl->m_visibleEntityDatas[index].m_inFocus && !m_impl->m_visibleEntityDatas[index].m_descendantOfClosedContainer;
|
||||
}
|
||||
|
||||
AZStd::optional<size_t> EditorVisibleEntityDataCache::GetVisibleEntityIndexFromId(const AZ::EntityId entityId) const
|
||||
|
||||
+4
-1
@@ -55,7 +55,10 @@ namespace AzToolsFramework
|
||||
bool IsVisibleEntityVisible(size_t index) const;
|
||||
bool IsVisibleEntitySelected(size_t index) const;
|
||||
bool IsVisibleEntityIconHidden(size_t index) const;
|
||||
bool IsVisibleEntitySelectableInViewport(size_t index) const;
|
||||
//! Returns true if the entity is individually selectable (none of its ancestors are a closed container entity).
|
||||
//! @note It may still be desirable to be able to 'click' an entity that is a descendant of a closed container
|
||||
//! to select the container itself, not the individual entity.
|
||||
bool IsVisibleEntityIndividuallySelectableInViewport(size_t index) const;
|
||||
|
||||
AZStd::optional<size_t> GetVisibleEntityIndexFromId(AZ::EntityId entityId) const;
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@ namespace UnitTest
|
||||
{
|
||||
AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId());
|
||||
AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
// default local bounds to unit cube
|
||||
m_localBounds = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-0.5f), AZ::Vector3(0.5f));
|
||||
}
|
||||
|
||||
void BoundsTestComponent::Deactivate()
|
||||
@@ -57,7 +60,6 @@ namespace UnitTest
|
||||
|
||||
AZ::Aabb BoundsTestComponent::GetLocalBounds()
|
||||
{
|
||||
return AZ::Aabb::CreateFromMinMax(AZ::Vector3(-0.5f), AZ::Vector3(0.5f));
|
||||
return m_localBounds;
|
||||
}
|
||||
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -41,5 +41,7 @@ namespace UnitTest
|
||||
// BoundsRequestBus overrides ...
|
||||
AZ::Aabb GetWorldBounds() override;
|
||||
AZ::Aabb GetLocalBounds() override;
|
||||
|
||||
AZ::Aabb m_localBounds; //!< Local bounds that can be modified for certain tests (defaults to unit cube).
|
||||
};
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
|
||||
#include <AzToolsFramework/ViewportUi/ViewportUiManager.h>
|
||||
|
||||
#include<Tests/BoundsTestComponent.h>
|
||||
#include <Tests/BoundsTestComponent.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -493,12 +493,8 @@ namespace UnitTest
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Then
|
||||
AzToolsFramework::EntityIdList selectedEntities;
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
selectedEntities, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetSelectedEntities);
|
||||
|
||||
AzToolsFramework::EntityIdList expectedSelectedEntities = { entity4, entity5, entity6 };
|
||||
|
||||
const AzToolsFramework::EntityIdList selectedEntities = SelectedEntities();
|
||||
const AzToolsFramework::EntityIdList expectedSelectedEntities = { entity4, entity5, entity6 };
|
||||
EXPECT_THAT(selectedEntities, UnorderedElementsAreArray(expectedSelectedEntities));
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
@@ -527,12 +523,8 @@ namespace UnitTest
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Then
|
||||
AzToolsFramework::EntityIdList selectedEntities;
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
selectedEntities, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetSelectedEntities);
|
||||
|
||||
AzToolsFramework::EntityIdList expectedSelectedEntities = { m_entityId1, entity2, entity3, entity4 };
|
||||
|
||||
const AzToolsFramework::EntityIdList selectedEntities = SelectedEntities();
|
||||
const AzToolsFramework::EntityIdList expectedSelectedEntities = { m_entityId1, entity2, entity3, entity4 };
|
||||
EXPECT_THAT(selectedEntities, UnorderedElementsAreArray(expectedSelectedEntities));
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
@@ -946,6 +938,42 @@ namespace UnitTest
|
||||
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, BoundsBetweenCameraAndNearClipPlaneDoesNotIntersectMouseRay)
|
||||
{
|
||||
// move camera to 10 units along the y-axis
|
||||
AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f)));
|
||||
|
||||
// send a very narrow bounds for entity1
|
||||
AZ::Entity* entity1 = AzToolsFramework::GetEntityById(m_entityId1);
|
||||
auto* boundTestComponent = entity1->FindComponent<BoundsTestComponent>();
|
||||
boundTestComponent->m_localBounds =
|
||||
AZ::Aabb::CreateFromMinMax(AZ::Vector3(-0.5f, -0.0025f, -0.5f), AZ::Vector3(0.5f, 0.0025f, 0.5f));
|
||||
|
||||
// move entity1 in front of the camera between it and the near clip plane
|
||||
AZ::TransformBus::Event(
|
||||
m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.05f)));
|
||||
// move entity2 behind entity1
|
||||
AZ::TransformBus::Event(
|
||||
m_entityId2, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(15.0f)));
|
||||
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(m_entityId2), m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(true)
|
||||
->CameraState(m_cameraState)
|
||||
->MousePosition(entity2ScreenPosition)
|
||||
->CameraState(m_cameraState)
|
||||
->MouseLButtonDown()
|
||||
->MouseLButtonUp();
|
||||
|
||||
// ensure entity1 is not selected as it is before the near clip plane
|
||||
using ::testing::UnorderedElementsAreArray;
|
||||
const AzToolsFramework::EntityIdList selectedEntities = SelectedEntities();
|
||||
const AzToolsFramework::EntityIdList expectedSelectedEntities = { m_entityId2 };
|
||||
EXPECT_THAT(selectedEntities, UnorderedElementsAreArray(expectedSelectedEntities));
|
||||
}
|
||||
|
||||
class EditorTransformComponentSelectionViewportPickingManipulatorTestFixtureParam
|
||||
: public EditorTransformComponentSelectionViewportPickingManipulatorTestFixture
|
||||
, public ::testing::WithParamInterface<bool>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h>
|
||||
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
|
||||
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
|
||||
#include <Tests/Utils/Printers.h>
|
||||
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
#include <Tests/Utils/Printers.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
@@ -35,6 +36,7 @@ namespace UnitTest
|
||||
const auto worldResult = AzFramework::ScreenToWorld(screenPoint, cameraState);
|
||||
return AzFramework::WorldToScreen(worldResult, cameraState);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ScreenPoint tests
|
||||
TEST(ViewportScreen, WorldToScreenAndScreenToWorldReturnsTheSameValueIdentityCameraOffsetFromOrigin)
|
||||
@@ -102,8 +104,8 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NDC tests
|
||||
TEST(ViewportScreen, WorldToScreenNDCAndScreenNDCToWorldReturnsTheSameValueIdentityCameraOffsetFromOrigin)
|
||||
// Ndc tests
|
||||
TEST(ViewportScreen, WorldToScreenNdcAndScreenNdcToWorldReturnsTheSameValueIdentityCameraOffsetFromOrigin)
|
||||
{
|
||||
using NdcPoint = AZ::Vector2;
|
||||
|
||||
@@ -136,7 +138,7 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, WorldToScreenNDCAndScreenNDCToWorldReturnsTheSameValueOrientatedCamera)
|
||||
TEST(ViewportScreen, WorldToScreenNdcAndScreenNdcToWorldReturnsTheSameValueOrientatedCamera)
|
||||
{
|
||||
using NdcPoint = AZ::Vector2;
|
||||
|
||||
@@ -153,7 +155,7 @@ namespace UnitTest
|
||||
|
||||
// note: nearClip is 0.1 - the world space value returned will be aligned to the near clip
|
||||
// plane of the camera so use that to confirm the mapping to/from is correct
|
||||
TEST(ViewportScreen, ScreenNDCToWorldReturnsPositionOnNearClipPlaneInWorldSpace)
|
||||
TEST(ViewportScreen, ScreenNdcToWorldReturnsPositionOnNearClipPlaneInWorldSpace)
|
||||
{
|
||||
using NdcPoint = AZ::Vector2;
|
||||
|
||||
|
||||
@@ -132,17 +132,22 @@ namespace AZ
|
||||
//! Returns the masked occlusion culling interface
|
||||
MaskedOcclusionCulling* GetMaskedOcclusionCulling();
|
||||
|
||||
//! This is called by RenderPipeline when this view is added to the pipeline.
|
||||
void OnAddToRenderPipeline();
|
||||
|
||||
private:
|
||||
View() = delete;
|
||||
View(const AZ::Name& name, UsageFlags usage);
|
||||
|
||||
|
||||
//! Sorts the finalized draw lists in this view
|
||||
void SortFinalizedDrawLists();
|
||||
|
||||
//! Sorts a drawList using the sort function from a pass with the corresponding drawListTag
|
||||
void SortDrawList(RHI::DrawList& drawList, RHI::DrawListTag tag);
|
||||
|
||||
//! Attempt to create a shader resource group.
|
||||
void TryCreateShaderResourceGroup();
|
||||
|
||||
AZ::Name m_name;
|
||||
UsageFlags m_usageFlags;
|
||||
|
||||
|
||||
@@ -178,6 +178,10 @@ namespace AZ
|
||||
pipelineViews.m_views.resize(1);
|
||||
}
|
||||
ViewPtr previousView = pipelineViews.m_views[0];
|
||||
if (view)
|
||||
{
|
||||
view->OnAddToRenderPipeline();
|
||||
}
|
||||
pipelineViews.m_views[0] = view;
|
||||
|
||||
if (previousView)
|
||||
@@ -238,6 +242,7 @@ namespace AZ
|
||||
pipelineViews.m_type = PipelineViewType::Transient;
|
||||
}
|
||||
view->SetPassesByDrawList(&pipelineViews.m_passesByDrawList);
|
||||
view->OnAddToRenderPipeline();
|
||||
pipelineViews.m_views.push_back(view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,18 +47,14 @@ namespace AZ
|
||||
{
|
||||
AZ_Assert(!name.IsEmpty(), "invalid name");
|
||||
|
||||
// Set default matrixes.
|
||||
// Set default matrices
|
||||
SetWorldToViewMatrix(AZ::Matrix4x4::CreateIdentity());
|
||||
AZ::Matrix4x4 viewToClipMatrix;
|
||||
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, 1, 0.1f, 1000.f, true);
|
||||
SetViewToClipMatrix(viewToClipMatrix);
|
||||
|
||||
Data::Asset<ShaderAsset> viewSrgShaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs();
|
||||
TryCreateShaderResourceGroup();
|
||||
|
||||
if (viewSrgShaderAsset.IsReady())
|
||||
{
|
||||
m_shaderResourceGroup = ShaderResourceGroup::Create(viewSrgShaderAsset, RPISystemInterface::Get()->GetViewSrgLayout()->GetName());
|
||||
}
|
||||
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
|
||||
m_maskedOcclusionCulling = MaskedOcclusionCulling::Create();
|
||||
m_maskedOcclusionCulling->SetResolution(MaskedSoftwareOcclusionCullingWidth, MaskedSoftwareOcclusionCullingHeight);
|
||||
@@ -369,16 +365,19 @@ namespace AZ
|
||||
{
|
||||
if (m_clipSpaceOffset.IsZero())
|
||||
{
|
||||
Matrix4x4 worldToClipPrevMatrix = m_viewToClipPrevMatrix * m_worldToViewPrevMatrix;
|
||||
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, worldToClipPrevMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_viewToClipMatrix.GetInverseFull());
|
||||
if (m_shaderResourceGroup)
|
||||
{
|
||||
Matrix4x4 worldToClipPrevMatrix = m_viewToClipPrevMatrix * m_worldToViewPrevMatrix;
|
||||
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, worldToClipPrevMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_viewToClipMatrix.GetInverseFull());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Offset the current and previous frame clip matricies
|
||||
// Offset the current and previous frame clip matrices
|
||||
Matrix4x4 offsetViewToClipMatrix = m_viewToClipMatrix;
|
||||
offsetViewToClipMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX());
|
||||
offsetViewToClipMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY());
|
||||
@@ -387,27 +386,33 @@ namespace AZ
|
||||
offsetViewToClipPrevMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX());
|
||||
offsetViewToClipPrevMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY());
|
||||
|
||||
// Build other matricies dependent on the view to clip matricies
|
||||
// Build other matrices dependent on the view to clip matrices
|
||||
Matrix4x4 offsetWorldToClipMatrix = offsetViewToClipMatrix * m_worldToViewMatrix;
|
||||
Matrix4x4 offsetWorldToClipPrevMatrix = offsetViewToClipPrevMatrix * m_worldToViewPrevMatrix;
|
||||
|
||||
Matrix4x4 offsetClipToViewMatrix = offsetViewToClipMatrix.GetInverseFull();
|
||||
Matrix4x4 offsetClipToWorldMatrix = m_viewToWorldMatrix * offsetClipToViewMatrix;
|
||||
|
||||
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, offsetWorldToClipPrevMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, offsetWorldToClipMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, offsetViewToClipMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, offsetClipToWorldMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, offsetViewToClipMatrix.GetInverseFull());
|
||||
|
||||
if (m_shaderResourceGroup)
|
||||
{
|
||||
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, offsetWorldToClipPrevMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, offsetWorldToClipMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, offsetViewToClipMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, offsetClipToWorldMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, offsetViewToClipMatrix.GetInverseFull());
|
||||
}
|
||||
}
|
||||
|
||||
m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position);
|
||||
m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_worldToViewMatrix.GetInverseFull());
|
||||
m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_nearZ_farZ_farZTimesNearZ_farZMinusNearZ);
|
||||
m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants);
|
||||
if (m_shaderResourceGroup)
|
||||
{
|
||||
m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position);
|
||||
m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix);
|
||||
m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_worldToViewMatrix.GetInverseFull());
|
||||
m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_nearZ_farZ_farZTimesNearZ_farZMinusNearZ);
|
||||
m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants);
|
||||
|
||||
m_shaderResourceGroup->Compile();
|
||||
m_shaderResourceGroup->Compile();
|
||||
}
|
||||
|
||||
m_viewToClipPrevMatrix = m_viewToClipMatrix;
|
||||
m_worldToViewPrevMatrix = m_worldToViewMatrix;
|
||||
@@ -426,5 +431,30 @@ namespace AZ
|
||||
{
|
||||
return m_maskedOcclusionCulling;
|
||||
}
|
||||
|
||||
void View::TryCreateShaderResourceGroup()
|
||||
{
|
||||
if (!m_shaderResourceGroup)
|
||||
{
|
||||
if (auto rpiSystemInterface = RPISystemInterface::Get())
|
||||
{
|
||||
if (Data::Asset<ShaderAsset> viewSrgShaderAsset = rpiSystemInterface->GetCommonShaderAssetForSrgs();
|
||||
viewSrgShaderAsset.IsReady())
|
||||
{
|
||||
m_shaderResourceGroup =
|
||||
ShaderResourceGroup::Create(viewSrgShaderAsset, rpiSystemInterface->GetViewSrgLayout()->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void View::OnAddToRenderPipeline()
|
||||
{
|
||||
TryCreateShaderResourceGroup();
|
||||
if (!m_shaderResourceGroup)
|
||||
{
|
||||
AZ_Warning("RPI::View", false, "Shader Resource Group failed to initialize");
|
||||
}
|
||||
}
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -80,6 +80,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AzTestShared
|
||||
AZ::AzFrameworkTestShared
|
||||
Gem::AtomToolsFramework.Static
|
||||
Gem::Atom_Utils.TestUtils.Static
|
||||
)
|
||||
|
||||
+7
-4
@@ -21,6 +21,7 @@
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
|
||||
#include <AtomToolsFramework/Viewport/ViewportInteractionImpl.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
@@ -30,8 +31,8 @@ namespace AtomToolsFramework
|
||||
//! @see AZ::RPI::ViewportContext for Atom's API for setting up
|
||||
class RenderViewportWidget
|
||||
: public QWidget
|
||||
, public AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler
|
||||
, public AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler
|
||||
, public AzToolsFramework::ViewportInteraction::ViewportInteractionRequests
|
||||
, public AzFramework::WindowRequestBus::Handler
|
||||
, protected AzFramework::InputChannelEventListener
|
||||
, protected AZ::TickBus::Handler
|
||||
@@ -90,11 +91,11 @@ namespace AtomToolsFramework
|
||||
//! Input processing is enabled by default.
|
||||
void SetInputProcessingEnabled(bool enabled);
|
||||
|
||||
// AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler overrides ...
|
||||
// ViewportInteractionRequests overrides ...
|
||||
AzFramework::CameraState GetCameraState() override;
|
||||
AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) override;
|
||||
AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override;
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportScreenToWorldRay(
|
||||
AZ::Vector3 ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition) override;
|
||||
AzToolsFramework::ViewportInteraction::ProjectedViewportRay ViewportScreenToWorldRay(
|
||||
const AzFramework::ScreenPoint& screenPosition) override;
|
||||
float DeviceScalingFactor() override;
|
||||
|
||||
@@ -149,5 +150,7 @@ namespace AtomToolsFramework
|
||||
AZ::ScriptTimePoint m_time;
|
||||
// Maps our internal Qt events into AzFramework InputChannels for our ViewportControllerList.
|
||||
AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr;
|
||||
// Implementation of ViewportInteractionRequests (handles viewport picking operations).
|
||||
AZStd::unique_ptr<ViewportInteractionImpl> m_viewportInteractionImpl;
|
||||
};
|
||||
} //namespace AtomToolsFramework
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! A concrete implementation of the ViewportInteractionRequestBus.
|
||||
//! Primarily concerned with picking (screen to world and world to screen transformations).
|
||||
class ViewportInteractionImpl : public AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
explicit ViewportInteractionImpl(AZ::RPI::ViewPtr viewPtr);
|
||||
|
||||
void Connect(AzFramework::ViewportId viewportId);
|
||||
void Disconnect();
|
||||
|
||||
// ViewportInteractionRequestBus overrides ...
|
||||
AzFramework::CameraState GetCameraState() override;
|
||||
AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) override;
|
||||
AZ::Vector3 ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition) override;
|
||||
AzToolsFramework::ViewportInteraction::ProjectedViewportRay ViewportScreenToWorldRay(
|
||||
const AzFramework::ScreenPoint& screenPosition) override;
|
||||
float DeviceScalingFactor() override;
|
||||
|
||||
AZStd::function<AzFramework::ScreenSize()> m_screenSizeFn; //! Callback to determine the screen size.
|
||||
AZStd::function<float()> m_deviceScalingFactorFn; //! Callback to determine the device scaling factor.
|
||||
|
||||
private:
|
||||
AZ::RPI::ViewPtr m_viewPtr;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
@@ -75,7 +75,11 @@ namespace AtomToolsFramework
|
||||
m_defaultCamera = AZ::RPI::View::CreateView(cameraName, AZ::RPI::View::UsageFlags::UsageCamera);
|
||||
AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get()->PushView(m_viewportContext->GetName(), m_defaultCamera);
|
||||
|
||||
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(GetId());
|
||||
m_viewportInteractionImpl = AZStd::make_unique<ViewportInteractionImpl>(m_defaultCamera);
|
||||
m_viewportInteractionImpl->m_deviceScalingFactorFn = [this] { return aznumeric_cast<float>(devicePixelRatioF()); };
|
||||
m_viewportInteractionImpl->m_screenSizeFn = [this] { return AzFramework::ScreenSize(width(), height()); };
|
||||
m_viewportInteractionImpl->Connect(id);
|
||||
|
||||
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusConnect(GetId());
|
||||
AzFramework::InputChannelEventListener::Connect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
@@ -107,7 +111,7 @@ namespace AtomToolsFramework
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AzFramework::InputChannelEventListener::Disconnect();
|
||||
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusDisconnect();
|
||||
m_viewportInteractionImpl->Disconnect();
|
||||
}
|
||||
|
||||
void RenderViewportWidget::LockRenderTargetSize(uint32_t width, uint32_t height)
|
||||
@@ -278,77 +282,23 @@ namespace AtomToolsFramework
|
||||
|
||||
AzFramework::CameraState RenderViewportWidget::GetCameraState()
|
||||
{
|
||||
AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView();
|
||||
if (currentView == nullptr)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// Build camera state from Atom camera transforms
|
||||
AzFramework::CameraState cameraState = AzFramework::CreateCameraFromWorldFromViewMatrix(
|
||||
currentView->GetViewToWorldMatrix(),
|
||||
AZ::Vector2{aznumeric_cast<float>(width()), aznumeric_cast<float>(height())}
|
||||
);
|
||||
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix());
|
||||
|
||||
// Convert from Z-up
|
||||
AZStd::swap(cameraState.m_forward, cameraState.m_up);
|
||||
cameraState.m_forward = -cameraState.m_forward;
|
||||
|
||||
return cameraState;
|
||||
return m_viewportInteractionImpl->GetCameraState();
|
||||
}
|
||||
|
||||
AzFramework::ScreenPoint RenderViewportWidget::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
|
||||
{
|
||||
if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView();
|
||||
currentView == nullptr)
|
||||
{
|
||||
return AzFramework::ScreenPoint(0, 0);
|
||||
}
|
||||
|
||||
return AzFramework::WorldToScreen(worldPosition, GetCameraState());
|
||||
return m_viewportInteractionImpl->ViewportWorldToScreen(worldPosition);
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::Vector3> RenderViewportWidget::ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth)
|
||||
AZ::Vector3 RenderViewportWidget::ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition)
|
||||
{
|
||||
const auto& cameraProjection = m_viewportContext->GetCameraProjectionMatrix();
|
||||
const auto& cameraView = m_viewportContext->GetCameraViewMatrix();
|
||||
|
||||
const AZ::Vector4 normalizedScreenPosition {
|
||||
screenPosition.m_x * 2.f / width() - 1.0f,
|
||||
(height() - screenPosition.m_y) * 2.f / height() - 1.0f,
|
||||
1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
|
||||
1.f
|
||||
};
|
||||
|
||||
AZ::Matrix4x4 worldFromScreen = cameraProjection * cameraView;
|
||||
worldFromScreen.InvertFull();
|
||||
|
||||
const AZ::Vector4 projectedPosition = worldFromScreen * normalizedScreenPosition;
|
||||
if (projectedPosition.GetW() == 0.0f)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return projectedPosition.GetAsVector3() / projectedPosition.GetW();
|
||||
return m_viewportInteractionImpl->ViewportScreenToWorld(screenPosition);
|
||||
}
|
||||
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> RenderViewportWidget::ViewportScreenToWorldRay(
|
||||
AzToolsFramework::ViewportInteraction::ProjectedViewportRay RenderViewportWidget::ViewportScreenToWorldRay(
|
||||
const AzFramework::ScreenPoint& screenPosition)
|
||||
{
|
||||
auto pos0 = ViewportScreenToWorld(screenPosition, 0.f);
|
||||
auto pos1 = ViewportScreenToWorld(screenPosition, 1.f);
|
||||
if (!pos0.has_value() || !pos1.has_value())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
pos0 = m_viewportContext->GetDefaultView()->GetViewToWorldMatrix().GetTranslation();
|
||||
AZ::Vector3 rayOrigin = pos0.value();
|
||||
AZ::Vector3 rayDirection = pos1.value() - pos0.value();
|
||||
rayDirection.Normalize();
|
||||
|
||||
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection};
|
||||
return m_viewportInteractionImpl->ViewportScreenToWorldRay(screenPosition);
|
||||
}
|
||||
|
||||
float RenderViewportWidget::DeviceScalingFactor()
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 <AtomToolsFramework/Viewport/ViewportInteractionImpl.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
ViewportInteractionImpl::ViewportInteractionImpl(AZ::RPI::ViewPtr viewPtr)
|
||||
: m_viewPtr(AZStd::move(viewPtr))
|
||||
{
|
||||
}
|
||||
|
||||
void ViewportInteractionImpl::Connect(const AzFramework::ViewportId viewportId)
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(viewportId);
|
||||
}
|
||||
|
||||
void ViewportInteractionImpl::Disconnect()
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AzFramework::CameraState ViewportInteractionImpl::GetCameraState()
|
||||
{
|
||||
// build camera state from atom camera transforms
|
||||
AzFramework::CameraState cameraState =
|
||||
AzFramework::CreateDefaultCamera(m_viewPtr->GetCameraTransform(), AzFramework::Vector2FromScreenSize(m_screenSizeFn()));
|
||||
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, m_viewPtr->GetViewToClipMatrix());
|
||||
return cameraState;
|
||||
}
|
||||
|
||||
AzFramework::ScreenPoint ViewportInteractionImpl::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
|
||||
{
|
||||
return AzFramework::WorldToScreen(worldPosition, GetCameraState());
|
||||
}
|
||||
|
||||
AZ::Vector3 ViewportInteractionImpl::ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition)
|
||||
{
|
||||
return AzFramework::ScreenToWorld(screenPosition, GetCameraState());
|
||||
}
|
||||
|
||||
AzToolsFramework::ViewportInteraction::ProjectedViewportRay ViewportInteractionImpl::ViewportScreenToWorldRay(
|
||||
const AzFramework::ScreenPoint& screenPosition)
|
||||
{
|
||||
const AzFramework::CameraState cameraState = GetCameraState();
|
||||
const AZ::Vector3 rayOrigin = AzFramework::ScreenToWorld(screenPosition, cameraState);
|
||||
const AZ::Vector3 rayDirection = (rayOrigin - cameraState.m_position).GetNormalized();
|
||||
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection };
|
||||
}
|
||||
|
||||
float ViewportInteractionImpl::DeviceScalingFactor()
|
||||
{
|
||||
return m_deviceScalingFactorFn();
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
@@ -12,16 +12,25 @@
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class AtomToolsFrameworkTestEnvironment : public AZ::Test::ITestEnvironment
|
||||
{
|
||||
protected:
|
||||
void SetupEnvironment() override
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
|
||||
}
|
||||
|
||||
void TeardownEnvironment() override
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
};
|
||||
|
||||
class AtomToolsFrameworkTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
if (!AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Create(AZ::SystemAllocator::Descriptor());
|
||||
}
|
||||
|
||||
m_assetSystemStub.Activate();
|
||||
|
||||
RegisterSourceAsset("objects/upgrades/materials/supercondor.material");
|
||||
@@ -38,11 +47,6 @@ namespace UnitTest
|
||||
void TearDown() override
|
||||
{
|
||||
m_assetSystemStub.Deactivate();
|
||||
|
||||
if (AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterSourceAsset(const AZStd::string& path)
|
||||
@@ -73,5 +77,5 @@ namespace UnitTest
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 0), "materials/condor.material");
|
||||
}
|
||||
|
||||
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
|
||||
AZ_UNIT_TEST_HOOK(new AtomToolsFrameworkTestEnvironment);
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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 <Atom/RPI.Public/View.h>
|
||||
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
|
||||
#include <AzCore/Math/IntersectSegment.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/Name/NameDictionary.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <Tests/Utils/Printers.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class ViewportInteractionImplFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static inline constexpr AzFramework::ViewportId TestViewportId = 1234;
|
||||
static inline constexpr AzFramework::ScreenSize ScreenDimensions = AzFramework::ScreenSize(1280, 720);
|
||||
|
||||
static AzFramework::ScreenPoint ScreenCenter()
|
||||
{
|
||||
const auto halfScreenDimensions = ScreenDimensions * 0.5f;
|
||||
return AzFramework::ScreenPoint(halfScreenDimensions.m_width, halfScreenDimensions.m_height);
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AZ::NameDictionary::Create();
|
||||
|
||||
m_view = AZ::RPI::View::CreateView(AZ::Name("TestView"), AZ::RPI::View::UsageCamera);
|
||||
|
||||
const auto aspectRatio = aznumeric_cast<float>(ScreenDimensions.m_width) / aznumeric_cast<float>(ScreenDimensions.m_height);
|
||||
|
||||
AZ::Matrix4x4 viewToClipMatrix;
|
||||
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::DegToRad(60.0f), aspectRatio, 0.1f, 1000.f, true);
|
||||
m_view->SetViewToClipMatrix(viewToClipMatrix);
|
||||
|
||||
m_viewportInteractionImpl = AZStd::make_unique<AtomToolsFramework::ViewportInteractionImpl>(m_view);
|
||||
|
||||
m_viewportInteractionImpl->m_deviceScalingFactorFn = []
|
||||
{
|
||||
return 1.0f;
|
||||
};
|
||||
m_viewportInteractionImpl->m_screenSizeFn = []
|
||||
{
|
||||
return ScreenDimensions;
|
||||
};
|
||||
|
||||
m_viewportInteractionImpl->Connect(TestViewportId);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_viewportInteractionImpl->Disconnect();
|
||||
m_viewportInteractionImpl.reset();
|
||||
|
||||
m_view.reset();
|
||||
|
||||
AZ::NameDictionary::Destroy();
|
||||
}
|
||||
|
||||
AZ::RPI::ViewPtr m_view;
|
||||
AZStd::unique_ptr<AtomToolsFramework::ViewportInteractionImpl> m_viewportInteractionImpl;
|
||||
};
|
||||
|
||||
// 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,
|
||||
AzToolsFramework::ViewportInteraction::ViewportInteractionRequests& viewportInteractionRequests)
|
||||
{
|
||||
const auto worldResult = viewportInteractionRequests.ViewportScreenToWorld(screenPoint);
|
||||
return viewportInteractionRequests.ViewportWorldToScreen(worldResult);
|
||||
}
|
||||
|
||||
TEST_F(ViewportInteractionImplFixture, ViewportInteractionRequestsMapsFromScreenToWorldAndBack)
|
||||
{
|
||||
using AzFramework::ScreenPoint;
|
||||
|
||||
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(10.0f, 0.0f, 5.0f)));
|
||||
|
||||
{
|
||||
const auto expectedScreenPoint = ScreenPoint{ 600, 450 };
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, *m_viewportInteractionImpl);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
|
||||
{
|
||||
auto expectedScreenPoint = ScreenCenter();
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, *m_viewportInteractionImpl);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
|
||||
{
|
||||
const auto expectedScreenPoint = ScreenPoint{ 0, 0 };
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, *m_viewportInteractionImpl);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
|
||||
{
|
||||
const auto expectedScreenPoint = ScreenPoint{ ScreenDimensions.m_width, ScreenDimensions.m_height };
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, *m_viewportInteractionImpl);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ViewportInteractionImplFixture, ScreenToWorldReturnsPositionOnNearClipPlaneInWorldSpace)
|
||||
{
|
||||
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(-90.0f)), AZ::Vector3(20.0f, 0.0f, 0.0f)));
|
||||
|
||||
const auto worldResult = m_viewportInteractionImpl->ViewportScreenToWorld(ScreenCenter());
|
||||
EXPECT_THAT(worldResult, IsClose(AZ::Vector3(20.1f, 0.0f, 0.0f)));
|
||||
}
|
||||
|
||||
// note: values produced by reproducing in the editor viewport
|
||||
TEST_F(ViewportInteractionImplFixture, WorldToScreenGivesExpectedScreenCoordinates)
|
||||
{
|
||||
using AzFramework::ScreenPoint;
|
||||
|
||||
{
|
||||
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(160.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-18.0f)),
|
||||
AZ::Vector3(-21.0f, 2.5f, 6.0f)));
|
||||
|
||||
const auto screenResult = m_viewportInteractionImpl->ViewportWorldToScreen(AZ::Vector3(-21.0f, -1.5f, 5.0f));
|
||||
EXPECT_EQ(screenResult, ScreenPoint(420, 326));
|
||||
}
|
||||
|
||||
{
|
||||
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(175.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-90.0f)),
|
||||
AZ::Vector3(-10.0f, -11.0f, 2.5f)));
|
||||
|
||||
const auto screenResult = m_viewportInteractionImpl->ViewportWorldToScreen(AZ::Vector3(-10.0f, -10.5f, 0.5f));
|
||||
EXPECT_EQ(screenResult, ScreenPoint(654, 515));
|
||||
}
|
||||
|
||||
{
|
||||
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(70.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(65.0f)),
|
||||
AZ::Vector3(-22.5f, -10.0f, 1.5f)));
|
||||
|
||||
const auto screenResult = m_viewportInteractionImpl->ViewportWorldToScreen(AZ::Vector3(-23.0f, -9.5f, 3.0f));
|
||||
EXPECT_EQ(screenResult, ScreenPoint(754, 340));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ViewportInteractionImplFixture, ScreenToWorldRayGivesGivesExpectedOriginAndDirection)
|
||||
{
|
||||
using AzFramework::ScreenPoint;
|
||||
|
||||
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(34.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-24.0f)),
|
||||
AZ::Vector3(-9.3f, -9.8f, 4.0f)));
|
||||
|
||||
const auto ray = m_viewportInteractionImpl->ViewportScreenToWorldRay(ScreenPoint(832, 226));
|
||||
|
||||
float unused;
|
||||
auto intersection = AZ::Intersect::IntersectRaySphere(ray.origin, ray.direction, AZ::Vector3(-14.0f, 5.7f, 0.75f), 0.5f, unused);
|
||||
|
||||
EXPECT_EQ(intersection, AZ::Intersect::SphereIsectTypes::ISECT_RAY_SPHERE_ISECT);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -28,6 +28,7 @@ set(FILES
|
||||
Include/AtomToolsFramework/Util/MaterialPropertyUtil.h
|
||||
Include/AtomToolsFramework/Util/Util.h
|
||||
Include/AtomToolsFramework/Viewport/RenderViewportWidget.h
|
||||
Include/AtomToolsFramework/Viewport/ViewportInteractionImpl.h
|
||||
Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h
|
||||
Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h
|
||||
Include/AtomToolsFramework/Window/AtomToolsMainWindow.h
|
||||
@@ -55,6 +56,7 @@ set(FILES
|
||||
Source/Util/Util.cpp
|
||||
Source/Viewport/RenderViewportWidget.cpp
|
||||
Source/Viewport/ModularViewportCameraController.cpp
|
||||
Source/Viewport/ViewportInteractionImpl.cpp
|
||||
Source/Window/AtomToolsMainWindow.cpp
|
||||
Source/Window/AtomToolsMainWindowSystemComponent.cpp
|
||||
Source/Window/AtomToolsMainWindowSystemComponent.h
|
||||
|
||||
@@ -8,4 +8,5 @@
|
||||
|
||||
set(FILES
|
||||
Tests/AtomToolsFrameworkTest.cpp
|
||||
Tests/ViewportInteractionImplTests.cpp
|
||||
)
|
||||
Reference in New Issue
Block a user