Allow SurfaceManipulator to self-intersect when holding Ctrl (#6453)
* beginning updates to surface manipulator intersect Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * initial changes to support surface manipulator being able to ignore custom entity ids Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * updates to use type aliases Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add test for self-intersection test for SurfaceManipulator when holding Ctrl Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
9e32c83d30
commit
deeb59cb83
+8
-8
@@ -46,9 +46,9 @@ namespace AzManipulatorTestFramework
|
||||
//! Send a double click event.
|
||||
DerivedDispatcherT* MouseLButtonDoubleClick();
|
||||
//! Set the keyboard modifier button down.
|
||||
DerivedDispatcherT* KeyboardModifierDown(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
|
||||
DerivedDispatcherT* KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier);
|
||||
//! Set the keyboard modifier button up.
|
||||
DerivedDispatcherT* KeyboardModifierUp(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
|
||||
DerivedDispatcherT* KeyboardModifierUp(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier);
|
||||
//! Set the mouse position to the specified screen space position.
|
||||
DerivedDispatcherT* MousePosition(const AzFramework::ScreenPoint& position);
|
||||
//! Expect the selected manipulator to be interacting.
|
||||
@@ -81,8 +81,8 @@ namespace AzManipulatorTestFramework
|
||||
virtual void MouseMButtonUpImpl() = 0;
|
||||
virtual void MouseLButtonDoubleClickImpl() = 0;
|
||||
virtual void MousePositionImpl(const AzFramework::ScreenPoint& position) = 0;
|
||||
virtual void KeyboardModifierDownImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) = 0;
|
||||
virtual void KeyboardModifierUpImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) = 0;
|
||||
virtual void KeyboardModifierDownImpl(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier) = 0;
|
||||
virtual void KeyboardModifierUpImpl(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier) = 0;
|
||||
virtual void ExpectManipulatorBeingInteractedImpl() = 0;
|
||||
virtual void ExpectManipulatorNotBeingInteractedImpl() = 0;
|
||||
virtual void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) = 0;
|
||||
@@ -94,7 +94,7 @@ namespace AzManipulatorTestFramework
|
||||
bool m_logging = false;
|
||||
|
||||
private:
|
||||
const char* KeyboardModifierString(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
|
||||
const char* KeyboardModifierString(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier);
|
||||
static void DebugPrint(const char* format, ...);
|
||||
};
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace AzManipulatorTestFramework
|
||||
|
||||
template<typename DerivedDispatcherT>
|
||||
const char* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierString(
|
||||
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
|
||||
const AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier)
|
||||
{
|
||||
using namespace AzToolsFramework::ViewportInteraction;
|
||||
switch (keyModifier)
|
||||
@@ -235,7 +235,7 @@ namespace AzManipulatorTestFramework
|
||||
|
||||
template<typename DerivedDispatcherT>
|
||||
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierDown(
|
||||
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
|
||||
const AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier)
|
||||
{
|
||||
Log("Keyboard modifier down: %s", KeyboardModifierString(keyModifier));
|
||||
KeyboardModifierDownImpl(keyModifier);
|
||||
@@ -244,7 +244,7 @@ namespace AzManipulatorTestFramework
|
||||
|
||||
template<typename DerivedDispatcherT>
|
||||
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierUp(
|
||||
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
|
||||
const AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier)
|
||||
{
|
||||
Log("Keyboard modifier up: %s", KeyboardModifierString(keyModifier));
|
||||
KeyboardModifierUpImpl(keyModifier);
|
||||
|
||||
+2
-2
@@ -66,8 +66,8 @@ namespace AzManipulatorTestFramework
|
||||
void MouseMButtonUpImpl() override;
|
||||
void MouseLButtonDoubleClickImpl() override;
|
||||
void MousePositionImpl(const AzFramework::ScreenPoint& position) override;
|
||||
void KeyboardModifierDownImpl(const KeyboardModifier& keyModifier) override;
|
||||
void KeyboardModifierUpImpl(const KeyboardModifier& keyModifier) override;
|
||||
void KeyboardModifierDownImpl(KeyboardModifier keyModifier) override;
|
||||
void KeyboardModifierUpImpl(KeyboardModifier keyModifier) override;
|
||||
void ExpectManipulatorBeingInteractedImpl() override;
|
||||
void ExpectManipulatorNotBeingInteractedImpl() override;
|
||||
void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) override;
|
||||
|
||||
@@ -126,12 +126,12 @@ namespace AzManipulatorTestFramework
|
||||
m_manipulatorViewportInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event);
|
||||
}
|
||||
|
||||
void ImmediateModeActionDispatcher::KeyboardModifierDownImpl(const KeyboardModifier& keyModifier)
|
||||
void ImmediateModeActionDispatcher::KeyboardModifierDownImpl(const KeyboardModifier keyModifier)
|
||||
{
|
||||
ToggleOn(GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers.m_keyModifiers, keyModifier);
|
||||
}
|
||||
|
||||
void ImmediateModeActionDispatcher::KeyboardModifierUpImpl(const KeyboardModifier& keyModifier)
|
||||
void ImmediateModeActionDispatcher::KeyboardModifierUpImpl(const KeyboardModifier keyModifier)
|
||||
{
|
||||
ToggleOff(GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers.m_keyModifiers, keyModifier);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ namespace AzToolsFramework
|
||||
|
||||
virtual ~BaseManipulator();
|
||||
|
||||
using EntityComponentIds = AZStd::unordered_set<AZ::EntityComponentIdPair>;
|
||||
using UniqueEntityIds = AZStd::unordered_set<AZ::EntityId>;
|
||||
using UniqueEntityComponentIds = AZStd::unordered_set<AZ::EntityComponentIdPair>;
|
||||
|
||||
//! Callback for the event when the mouse pointer is over this manipulator and the left mouse button is pressed.
|
||||
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
|
||||
@@ -137,7 +138,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
//! Returns all EntityComponentIdPairs associated with this manipulator.
|
||||
const EntityComponentIds& EntityComponentIdPairs() const
|
||||
const UniqueEntityComponentIds& EntityComponentIdPairs() const
|
||||
{
|
||||
return m_entityComponentIdPairs;
|
||||
}
|
||||
@@ -147,10 +148,10 @@ namespace AzToolsFramework
|
||||
|
||||
//! Remove an entity from being affected by this manipulator.
|
||||
//! @note All components on this entity registered with the manipulator will be removed.
|
||||
EntityComponentIds::iterator RemoveEntityId(AZ::EntityId entityId);
|
||||
UniqueEntityComponentIds::iterator RemoveEntityId(AZ::EntityId entityId);
|
||||
|
||||
//! Remove a specific component (via a EntityComponentIdPair) being affected by this manipulator.
|
||||
EntityComponentIds::iterator RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair);
|
||||
UniqueEntityComponentIds::iterator RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair);
|
||||
|
||||
//! Is this entity currently being tracked by this manipulator.
|
||||
bool HasEntityId(AZ::EntityId entityId) const;
|
||||
|
||||
+10
-13
@@ -80,23 +80,18 @@ namespace AzToolsFramework
|
||||
m_onMouseMoveCallback = onMouseMoveCallback;
|
||||
}
|
||||
|
||||
void SurfaceManipulator::InstallEntityIdsToIgnoreFn(EntityIdsToIgnoreFn entityIdsToIgnoreCallback)
|
||||
{
|
||||
m_entityIdsToIgnoreFn = AZStd::move(entityIdsToIgnoreCallback);
|
||||
}
|
||||
|
||||
void SurfaceManipulator::OnLeftMouseDownImpl(
|
||||
const ViewportInteraction::MouseInteraction& interaction, [[maybe_unused]] float rayIntersectionDistance)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
|
||||
|
||||
const AzFramework::ViewportId viewportId = interaction.m_interactionId.m_viewportId;
|
||||
|
||||
const auto& entityComponentIdPairs = EntityComponentIdPairs();
|
||||
m_rayRequest.m_entityFilter.m_ignoreEntities.clear();
|
||||
m_rayRequest.m_entityFilter.m_ignoreEntities.reserve(entityComponentIdPairs.size());
|
||||
AZStd::transform(
|
||||
entityComponentIdPairs.begin(), entityComponentIdPairs.end(),
|
||||
AZStd::inserter(m_rayRequest.m_entityFilter.m_ignoreEntities, m_rayRequest.m_entityFilter.m_ignoreEntities.begin()),
|
||||
[](const AZ::EntityComponentIdPair& entityComponentIdPair)
|
||||
{
|
||||
return entityComponentIdPair.GetEntityId();
|
||||
});
|
||||
m_rayRequest.m_entityFilter.m_ignoreEntities = m_entityIdsToIgnoreFn(interaction);
|
||||
|
||||
// calculate the start and end of the ray
|
||||
RefreshRayRequest(
|
||||
@@ -139,6 +134,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
const AzFramework::ViewportId viewportId = interaction.m_interactionId.m_viewportId;
|
||||
|
||||
m_rayRequest.m_entityFilter.m_ignoreEntities = m_entityIdsToIgnoreFn(interaction);
|
||||
|
||||
// update the start and end of the ray
|
||||
RefreshRayRequest(
|
||||
m_rayRequest, ViewportInteraction::ViewportScreenToWorldRay(viewportId, interaction.m_mousePick.m_screenCoordinates),
|
||||
@@ -162,12 +159,12 @@ namespace AzToolsFramework
|
||||
const ManipulatorManagerState& managerState,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const AzFramework::CameraState& cameraState,
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction)
|
||||
const ViewportInteraction::MouseInteraction& interaction)
|
||||
{
|
||||
m_manipulatorView->Draw(
|
||||
GetManipulatorManagerId(), managerState, GetManipulatorId(),
|
||||
ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay,
|
||||
cameraState, mouseInteraction);
|
||||
cameraState, interaction);
|
||||
}
|
||||
|
||||
void SurfaceManipulator::InvalidateImpl()
|
||||
|
||||
@@ -40,6 +40,9 @@ namespace AzToolsFramework
|
||||
//! A Manipulator must only be created and managed through a shared_ptr.
|
||||
static AZStd::shared_ptr<SurfaceManipulator> MakeShared(const AZ::Transform& worldFromLocal);
|
||||
|
||||
//! Callback function to determine which EntityIds to ignore when performing the ray intersection.
|
||||
using EntityIdsToIgnoreFn = AZStd::function<UniqueEntityIds(const ViewportInteraction::MouseInteraction&)>;
|
||||
|
||||
//! The state of the manipulator at the start of an interaction.
|
||||
struct Start
|
||||
{
|
||||
@@ -77,11 +80,13 @@ namespace AzToolsFramework
|
||||
void InstallLeftMouseUpCallback(const MouseActionCallback& onMouseUpCallback);
|
||||
void InstallMouseMoveCallback(const MouseActionCallback& onMouseMoveCallback);
|
||||
|
||||
void InstallEntityIdsToIgnoreFn(EntityIdsToIgnoreFn entityIdsToIgnoreFn);
|
||||
|
||||
void Draw(
|
||||
const ManipulatorManagerState& managerState,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const AzFramework::CameraState& cameraState,
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
|
||||
const ViewportInteraction::MouseInteraction& interaction) override;
|
||||
|
||||
void SetView(AZStd::unique_ptr<ManipulatorView>&& view);
|
||||
|
||||
@@ -109,6 +114,9 @@ namespace AzToolsFramework
|
||||
MouseActionCallback m_onLeftMouseUpCallback = nullptr;
|
||||
MouseActionCallback m_onMouseMoveCallback = nullptr;
|
||||
|
||||
//! Customization point to determine which (if any) EntityIds to ignore while performing the ray intersection.
|
||||
EntityIdsToIgnoreFn m_entityIdsToIgnoreFn = nullptr;
|
||||
|
||||
//! Cached ray request initialized at mouse down and updated during mouse move.
|
||||
AzFramework::RenderGeometry::RayRequest m_rayRequest;
|
||||
|
||||
|
||||
+9
@@ -145,6 +145,15 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void TranslationManipulators::InstallSurfaceManipulatorEntityIdsToIgnoreFn(
|
||||
SurfaceManipulator::EntityIdsToIgnoreFn entityIdsToIgnoreFn)
|
||||
{
|
||||
if (m_surfaceManipulator)
|
||||
{
|
||||
m_surfaceManipulator->InstallEntityIdsToIgnoreFn(AZStd::move(entityIdsToIgnoreFn));
|
||||
}
|
||||
}
|
||||
|
||||
void TranslationManipulators::SetLocalTransformImpl(const AZ::Transform& localTransform)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_linearManipulators)
|
||||
|
||||
+2
@@ -61,6 +61,8 @@ namespace AzToolsFramework
|
||||
void InstallSurfaceManipulatorMouseMoveCallback(const SurfaceManipulator::MouseActionCallback& onMouseMoveCallback);
|
||||
void InstallSurfaceManipulatorMouseUpCallback(const SurfaceManipulator::MouseActionCallback& onMouseUpCallback);
|
||||
|
||||
void InstallSurfaceManipulatorEntityIdsToIgnoreFn(SurfaceManipulator::EntityIdsToIgnoreFn entityIdsToIgnoreFn);
|
||||
|
||||
void SetSpaceImpl(const AZ::Transform& worldFromLocal) override;
|
||||
void SetLocalTransformImpl(const AZ::Transform& localTransform) override;
|
||||
void SetLocalPositionImpl(const AZ::Vector3& localPosition) override;
|
||||
|
||||
+13
@@ -1360,6 +1360,19 @@ namespace AzToolsFramework
|
||||
EndRecordManipulatorCommand();
|
||||
});
|
||||
|
||||
translationManipulators->InstallSurfaceManipulatorEntityIdsToIgnoreFn(
|
||||
[this](const ViewportInteraction::MouseInteraction& interaction)
|
||||
{
|
||||
if (interaction.m_keyboardModifiers.Ctrl())
|
||||
{
|
||||
return AZStd::unordered_set<AZ::EntityId>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_selectedEntityIds;
|
||||
}
|
||||
});
|
||||
|
||||
// transfer ownership
|
||||
m_entityIdManipulators.m_manipulators = AZStd::move(translationManipulators);
|
||||
}
|
||||
|
||||
@@ -3277,4 +3277,45 @@ namespace UnitTest
|
||||
const AZ::Transform finalEntityTransform = AzToolsFramework::GetWorldTransform(m_entityIdBox);
|
||||
EXPECT_THAT(finalEntityTransform.GetTranslation(), IsCloseTolerance(expectedWorldPosition, 0.01f));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
EditorTransformComponentSelectionRenderGeometryIntersectionManipulatorFixture, SurfaceManipulatorSelfIntersectsMeshWhenCtrlIsHeld)
|
||||
{
|
||||
// camera (go to position format) - 47.00, -52.00, 20.00, 0.00, -60.00
|
||||
m_cameraState.m_viewportSize = AZ::Vector2(1280.0f, 720.0f);
|
||||
// position camera
|
||||
AzFramework::SetCameraTransform(
|
||||
m_cameraState,
|
||||
AZ::Transform::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(-60.0f)), AZ::Vector3(47.0f, -52.0f, 20.0f)));
|
||||
// position box
|
||||
AzToolsFramework::SetWorldTransform(m_entityIdBox, AZ::Transform::CreateTranslation(AZ::Vector3(50.0f, -50.0f, 20.0f)));
|
||||
|
||||
// the initial starting position of the entity
|
||||
const auto initialTransformWorld = AzToolsFramework::GetWorldTransform(m_entityIdBox);
|
||||
// where the surface manipulator should end up (surface of the box)
|
||||
const auto finalTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(49.5f, -49.6337357f, 19.5793953f));
|
||||
|
||||
// calculate the position in screen space of the initial position of the entity
|
||||
const auto initialPositionScreen = AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState);
|
||||
// calculate the position in screen space of the final position of the entity
|
||||
const auto finalPositionScreen = AzFramework::WorldToScreen(finalTransformWorld.GetTranslation(), m_cameraState);
|
||||
|
||||
// select the entity (this will cause the manipulators to appear in EditorTransformComponentSelection)
|
||||
AzToolsFramework::SelectEntity(m_entityIdBox);
|
||||
|
||||
// press and drag the mouse (starting where the surface manipulator is)
|
||||
m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MousePosition(initialPositionScreen)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(finalPositionScreen)
|
||||
->MouseLButtonUp();
|
||||
|
||||
// read back the position of the entity now
|
||||
const AZ::Transform finalManipulatorTransform = GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity());
|
||||
|
||||
// ensure final world positions match
|
||||
EXPECT_THAT(finalManipulatorTransform, IsCloseTolerance(finalTransformWorld, 0.01f));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
Reference in New Issue
Block a user