First pass for getting things ready for grid snap button (#1118)

* first pass of change to simplify snapping for snap-to-grid button and fix snapping bug caused by non-uniform scale
This commit is contained in:
Tom Hulton-Harrop
2021-06-04 14:32:06 +01:00
committed by GitHub
parent f20ae8345a
commit 05e20803a8
15 changed files with 295 additions and 260 deletions
@@ -433,6 +433,11 @@ namespace AzToolsFramework
return m_manipulatorSpaceWithLocalTransform.GetSpace();
}
const AZ::Vector3& Manipulators::GetNonUniformScale() const
{
return m_manipulatorSpaceWithLocalTransform.GetNonUniformScale();
}
void Manipulators::SetSpace(const AZ::Transform& worldFromLocal)
{
m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal);
@@ -192,8 +192,7 @@ namespace AzToolsFramework
/// for each vertex associated with the translation manipulator to use with offset calculations when updating.
template<typename Vertex>
void InitializeVertexLookup(
IndexedTranslationManipulator<Vertex>& translationManipulator,
const AZ::EntityId entityId, const AZ::Vector3& snapOffset)
IndexedTranslationManipulator<Vertex>& translationManipulator, const AZ::EntityId entityId)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -202,7 +201,7 @@ namespace AzToolsFramework
AZ::FixedVerticesRequestBus<Vertex>::Bind(fixedVertices, entityId);
translationManipulator.Process(
[snapOffset, fixedVertices]
[fixedVertices]
(typename IndexedTranslationManipulator<Vertex>::VertexLookup& vertexLookup)
{
Vertex vertex;
@@ -213,7 +212,7 @@ namespace AzToolsFramework
if (found)
{
vertexLookup.m_start = vertex + AZ::AdaptVertexIn<Vertex>(snapOffset);
vertexLookup.m_start = vertex;
vertexLookup.m_offset = Vertex::CreateZero();
}
});
@@ -250,10 +249,10 @@ namespace AzToolsFramework
// linear manipulator callbacks
m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseDownCallback(
[this](const LinearManipulator::Action& action)
[this]([[maybe_unused]] const LinearManipulator::Action& action)
{
BeginBatchMovement();
InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_positionSnapOffset);
InitializeVertexLookup(*m_translationManipulator, GetEntityId());
});
m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseMoveCallback(
@@ -264,17 +263,17 @@ namespace AzToolsFramework
});
m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseUpCallback(
[this](const LinearManipulator::Action& /*action*/)
[this]([[maybe_unused]] const LinearManipulator::Action& action)
{
EndBatchMovement();
});
// planar manipulator callbacks
m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseDownCallback(
[this](const PlanarManipulator::Action& action)
[this]([[maybe_unused]] const PlanarManipulator::Action& action)
{
BeginBatchMovement();
InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_snapOffset);
InitializeVertexLookup(*m_translationManipulator, GetEntityId());
});
m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseMoveCallback(
@@ -285,17 +284,17 @@ namespace AzToolsFramework
});
m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseUpCallback(
[this](const PlanarManipulator::Action& /*action*/)
[this]([[maybe_unused]] const PlanarManipulator::Action& action)
{
EndBatchMovement();
});
// surface manipulator callbacks
m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseDownCallback(
[this](const SurfaceManipulator::Action& action)
[this]([[maybe_unused]] const SurfaceManipulator::Action& action)
{
BeginBatchMovement();
InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_snapOffset);
InitializeVertexLookup(*m_translationManipulator, GetEntityId());
});
m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseMoveCallback(
@@ -306,7 +305,7 @@ namespace AzToolsFramework
});
m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseUpCallback(
[this](const SurfaceManipulator::Action& /*action*/)
[this]([[maybe_unused]] const SurfaceManipulator::Action& action)
{
EndBatchMovement();
});
@@ -893,7 +892,7 @@ namespace AzToolsFramework
{
BeginBatchMovement();
InitializeVertexLookup(*m_translationManipulator, GetEntityId(), AZ::Vector3::CreateZero());
InitializeVertexLookup(*m_translationManipulator, GetEntityId());
// note: AdaptVertexIn/Out is to ensure we clamp the vertex local Z position to 0 if
// dealing with Vector2s when setting the position of the manipulator.
const AZ::Vector3 localOffset =
@@ -23,8 +23,8 @@ namespace AzToolsFramework
{
LinearManipulator::Starter CalculateLinearManipulationDataStart(
const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
const float intersectionDistance, const AzFramework::CameraState& cameraState)
const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance,
const AzFramework::CameraState& cameraState)
{
const ManipulatorInteraction manipulatorInteraction =
BuildManipulatorInteraction(
@@ -50,28 +50,9 @@ namespace AzToolsFramework
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection,
localIntersectionPoint, startTransition.m_localNormal, start.m_localHitPosition);
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
// calculate position amount to snap, to align with grid
const AZ::Vector3 positionSnapOffset = snapping && !gridSnapAction.m_localSnapping
? CalculateSnappedOffset(localTransform.GetTranslation(), axis, gridSize * scaleRecip)
: AZ::Vector3::CreateZero();
const AZ::Vector3 localScale = AZ::Vector3(localTransform.GetUniformScale());
const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform);
// calculate scale amount to snap, to align to round scale value
const AZ::Vector3 scaleSnapOffset = snapping && !gridSnapAction.m_localSnapping
? localRotation.GetInverseFull().TransformVector(CalculateSnappedOffset(
localRotation.TransformVector(localScale), axis, gridSize * scaleRecip))
: AZ::Vector3::CreateZero();
start.m_screenPosition = interaction.m_mousePick.m_screenCoordinates;
start.m_positionSnapOffset = positionSnapOffset;
start.m_scaleSnapOffset = scaleSnapOffset;
start.m_localPosition = localTransform.GetTranslation() + positionSnapOffset;
start.m_localScale = localScale + scaleSnapOffset;
start.m_localPosition = localTransform.GetTranslation();
start.m_localScale = AZ::Vector3(localTransform.GetUniformScale());;
start.m_localAxis = axis;
// sign to determine which side of the linear axis we pressed
// (useful to know when the visual axis flips to face the camera)
@@ -87,7 +68,7 @@ namespace AzToolsFramework
LinearManipulator::Action CalculateLinearManipulationDataAction(
const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter,
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction)
const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction)
{
const ManipulatorInteraction manipulatorInteraction =
BuildManipulatorInteraction(
@@ -108,31 +89,34 @@ namespace AzToolsFramework
GetCameraState(interaction.m_interactionId.m_viewportId));
const AZ::Vector3 axis = TransformDirectionNoScaling(localTransform, fixed.m_axis);
// The local positions have been transformed to the reference frame of the object being manipulated. But they appear in the world
// with non-uniform scale applied, and the object being manipulated will want to work with unscaled deltas, so we need to divide by
// the non-uniform scale here.
// the local positions have been transformed to the reference frame of the object being manipulated, but they appear in the world
// with non-uniform scale applied, the object being manipulated will want to work with unscaled deltas, so we need to divide by
// the non-uniform scale here
const AZ::Vector3 hitDelta = (localHitPosition - start.m_localHitPosition) / nonUniformScale;
const AZ::Vector3 unsnappedOffset = axis * axis.Dot(hitDelta);
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal * axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal);
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
const float scaleRecip =
manipulatorInteraction.m_scaleReciprocal * fixed.m_axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal);
const float gridSize = gridSnapParams.m_gridSize;
const bool snapping = gridSnapParams.m_gridSnap;
LinearManipulator::Action action;
action.m_fixed = fixed;
action.m_start = start;
action.m_current.m_localPositionOffset = snapping
? unsnappedOffset + CalculateSnappedOffset(unsnappedOffset, axis, gridSize * scaleRecip)
? CalculateSnappedAmount(unsnappedOffset, axis, gridSize * scaleRecip)
: unsnappedOffset;
action.m_current.m_screenPosition = interaction.m_mousePick.m_screenCoordinates;
action.m_viewportId = interaction.m_interactionId.m_viewportId;
const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform);
const AZ::Vector3 scaledUnsnappedOffset = unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale);
const AZ::Vector3 scaledUnsnappedOffset =
unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale);
// how much to adjust the scale based on movement
const AZ::Quaternion invLocalRotation = localRotation.GetInverseFull();
action.m_current.m_localScaleOffset = snapping
? invLocalRotation.TransformVector((scaledUnsnappedOffset + CalculateSnappedOffset(scaledUnsnappedOffset, axis, gridSize * scaleRecip)))
? invLocalRotation.TransformVector(CalculateSnappedAmount(scaledUnsnappedOffset, axis, gridSize * scaleRecip))
: invLocalRotation.TransformVector(scaledUnsnappedOffset);
// record what modifier keys are held during this action
@@ -171,19 +155,18 @@ namespace AzToolsFramework
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
m_starter = CalculateLinearManipulationDataStart(
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, rayIntersectionDistance,
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, rayIntersectionDistance,
GetCameraState(interaction.m_interactionId.m_viewportId));
if (m_onLeftMouseDownCallback)
{
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
m_onLeftMouseDownCallback(CalculateLinearManipulationDataAction(
m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction));
}
}
@@ -195,8 +178,8 @@ namespace AzToolsFramework
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
m_onMouseMoveCallback(CalculateLinearManipulationDataAction(
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams,
interaction));
}
}
@@ -208,8 +191,7 @@ namespace AzToolsFramework
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
m_onLeftMouseUpCallback(CalculateLinearManipulationDataAction(
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction));
}
}
@@ -232,8 +214,8 @@ namespace AzToolsFramework
GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId);
const auto action = CalculateLinearManipulationDataAction(
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction);
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams,
mouseInteraction);
// display the exact hit (ray intersection) of the mouse pick on the manipulator
DrawTransformAxes(
@@ -20,7 +20,7 @@
namespace AzToolsFramework
{
struct GridSnapAction;
struct GridSnapParameters;
/// LinearManipulator serves as a visual tool for users to modify values
/// in one dimension on an axis defined in 3D space.
@@ -68,8 +68,6 @@ namespace AzToolsFramework
AZ::Vector3 m_localScale; ///< The current scale of the manipulator in local space.
AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens.
AZ::Vector3 m_localAxis; ///< The axis in the local space of the manipulator itself.
AZ::Vector3 m_positionSnapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid.
AZ::Vector3 m_scaleSnapOffset; ///< The snap offset amount to ensure manipulator is aligned to round scale increments.
float m_sign; ///< Used to determine which side of the axis we clicked on in case it's flipped to face the camera.
AzFramework::ScreenPoint m_screenPosition; ///< The initial position in screen space of the manipulator.
};
@@ -91,7 +89,7 @@ namespace AzToolsFramework
ViewportInteraction::KeyboardModifiers m_modifiers;
int m_viewportId; ///< The id of the viewport this manipulator is being used in.
AZ::Vector3 LocalScale() const { return m_start.m_localScale + m_current.m_localScaleOffset; }
AZ::Vector3 LocalScaleOffset() const { return m_start.m_scaleSnapOffset + m_current.m_localScaleOffset; }
AZ::Vector3 LocalScaleOffset() const { return m_current.m_localScaleOffset; }
AZ::Vector3 LocalPosition() const { return m_start.m_localPosition + m_current.m_localPositionOffset; }
AZ::Vector3 LocalPositionOffset() const { return m_current.m_localPositionOffset; }
AZ::Vector2 ScreenOffset() const
@@ -162,11 +160,11 @@ namespace AzToolsFramework
LinearManipulator::Starter CalculateLinearManipulationDataStart(
const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
float intersectionDistance, const AzFramework::CameraState& cameraState);
const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance,
const AzFramework::CameraState& cameraState);
LinearManipulator::Action CalculateLinearManipulationDataAction(
const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter,
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction);
const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction);
} // namespace AzToolsFramework
@@ -42,12 +42,6 @@ namespace AzToolsFramework
{
}
GridSnapAction::GridSnapAction(const GridSnapParameters& gridSnapParameters, const bool localSnapping)
: m_gridSnapParams(gridSnapParameters)
, m_localSnapping(localSnapping)
{
}
ManipulatorInteraction BuildManipulatorInteraction(
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection)
@@ -57,19 +51,39 @@ namespace AzToolsFramework
return {localFromWorldUniform.TransformPoint(worldRayOrigin),
TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection),
ScaleReciprocal(worldFromLocalUniform),
NonUniformScaleReciprocal(nonUniformScale)};
NonUniformScaleReciprocal(nonUniformScale),
ScaleReciprocal(worldFromLocalUniform)};
}
AZ::Vector3 CalculateSnappedOffset(
const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size)
struct SnapAdjustment
{
float m_existingSnapDistance; //!< How far to snap up or down to align to the grid.
float m_nextSnapDistance; //!< The snap increment (will return full signed value (grid size) when distance
//!< moved is greater than half of the grid size in either direction).
};
static SnapAdjustment CalculateSnapDistance(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size)
{
// calculate total distance along axis
const float axisDistance = axis.Dot(unsnappedPosition);
// round to nearest step size
const float snappedAxisDistance = floorf((axisDistance / size) + 0.5f) * size;
return { axisDistance, snappedAxisDistance };
}
AZ::Vector3 CalculateSnappedOffset(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size)
{
const auto snapAdjustment = CalculateSnapDistance(unsnappedPosition, axis, size);
// return offset along axis to snap to step size
return axis * (snappedAxisDistance - axisDistance);
return axis * (snapAdjustment.m_nextSnapDistance - snapAdjustment.m_existingSnapDistance);
}
AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size)
{
const auto snapAdjustment = CalculateSnapDistance(unsnappedPosition, axis, size);
// return offset along axis to snap to step size
return axis * snapAdjustment.m_nextSnapDistance;
}
AZ::Vector3 CalculateSnappedTerrainPosition(
@@ -31,24 +31,15 @@ namespace AzToolsFramework
float m_gridSize;
};
/// Structure to encapsulate the current grid snapping state.
struct GridSnapAction
{
GridSnapAction(const GridSnapParameters& gridSnapParameters, bool localSnapping);
GridSnapParameters m_gridSnapParams;
bool m_localSnapping;
};
/// Structure to hold transformed incoming viewport interaction from world space to manipulator space.
struct ManipulatorInteraction
{
AZ::Vector3 m_localRayOrigin; ///< The ray origin (start) in the reference from of the manipulator.
AZ::Vector3 m_localRayDirection; ///< The ray direction in the reference from of the manipulator.
float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the
///< ray from world space to local space.
AZ::Vector3 m_nonUniformScaleReciprocal; ///< Handles inverting any non-uniform scale which was applied
///< separately from the transform.
float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the
///< ray from world space to local space.
};
/// Build a ManipulatorInteraction structure from the incoming viewport interaction.
@@ -56,11 +47,16 @@ namespace AzToolsFramework
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection);
/// Calculate the offset along an axis to adjust a position
/// to stay snapped to a given grid size.
/// Calculate the offset along an axis to adjust a position to stay snapped to a given grid size.
/// @note This is snap up or down to the nearest grid segment (e.g. 0.2 snaps to 0.0 -> delta 0.2,
/// 0.7 snaps to 1.0 -> delta 0.3).
AZ::Vector3 CalculateSnappedOffset(
const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size);
/// Return the amount to snap from the starting position given the current grid size.
/// @note A movement of more than half size (in either direction) will cause a snap by size.
AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size);
/// For a given point on the terrain, calculate the closest xy position snapped to the grid
/// (z position is aligned to terrain height, not snapped to z grid)
AZ::Vector3 CalculateSnappedTerrainPosition(
@@ -59,17 +59,16 @@ namespace AzToolsFramework
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const ViewportInteraction::MouseInteraction& interaction,
const AZStd::vector<LinearManipulator::Fixed>& fixedAxes,
const AZStd::vector<LinearManipulator::Starter>& starterStates, const GridSnapAction& gridSnapAction)
const AZStd::vector<LinearManipulator::Starter>& starterStates, const GridSnapParameters& gridSnapParams)
{
MultiLinearManipulator::Action action;
action.m_viewportId = interaction.m_interactionId.m_viewportId;
// build up action state for each axis
for (size_t fixedIndex = 0; fixedIndex < fixedAxes.size(); ++fixedIndex)
{
action.m_actions.push_back(
CalculateLinearManipulationDataAction(
fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform,
gridSnapAction, interaction));
action.m_actions.push_back(CalculateLinearManipulationDataAction(
fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform, gridSnapParams,
interaction));
}
return action;
@@ -79,8 +78,6 @@ namespace AzToolsFramework
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
const AzFramework::CameraState cameraState = GetCameraState(interaction.m_interactionId.m_viewportId);
// build up initial start state for each axis
@@ -88,20 +85,19 @@ namespace AzToolsFramework
{
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
const auto linearStart = CalculateLinearManipulationDataStart(
fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction,
rayIntersectionDistance, cameraState);
fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, rayIntersectionDistance,
cameraState);
m_starters.push_back(linearStart);
}
if (m_onLeftMouseDownCallback)
{
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
// pass action containing all linear actions for each axis to handler
m_onLeftMouseDownCallback(BuildMultiLinearManipulatorAction(
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
interaction, m_fixedAxes, m_starters, gridSnapAction));
interaction, m_fixedAxes, m_starters, gridSnapParams));
}
}
@@ -111,11 +107,9 @@ namespace AzToolsFramework
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
m_onMouseMoveCallback(BuildMultiLinearManipulatorAction(
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
interaction, m_fixedAxes, m_starters, gridSnapAction));
interaction, m_fixedAxes, m_starters, gridSnapParams));
}
}
@@ -125,11 +119,9 @@ namespace AzToolsFramework
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
m_onLeftMouseUpCallback(BuildMultiLinearManipulatorAction(
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
interaction, m_fixedAxes, m_starters, gridSnapAction));
interaction, m_fixedAxes, m_starters, gridSnapParams));
m_starters.clear();
}
@@ -20,8 +20,6 @@
namespace AzToolsFramework
{
struct GridSnapAction;
//! MultiLinearManipulator serves as a visual tool for users to modify values
//! in one or more dimensions on axes defined in 3D space.
class MultiLinearManipulator
@@ -22,8 +22,7 @@
namespace AzToolsFramework
{
PlanarManipulator::StartInternal PlanarManipulator::CalculateManipulationDataStart(
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance)
{
const ManipulatorInteraction manipulatorInteraction =
@@ -31,8 +30,6 @@ namespace AzToolsFramework
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal);
const AZ::Vector3 axis1 = TransformDirectionNoScaling(localTransform, fixed.m_axis1);
const AZ::Vector3 axis2 = TransformDirectionNoScaling(localTransform, fixed.m_axis2);
// initial intersect point
const AZ::Vector3 localIntersectionPoint =
@@ -43,25 +40,14 @@ namespace AzToolsFramework
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection,
localIntersectionPoint, normal, startInternal.m_localHitPosition);
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
// calculate amount to snap to align with grid
const AZ::Vector3 snapOffset = snapping && !gridSnapAction.m_localSnapping
? CalculateSnappedOffset(localTransform.GetTranslation(), axis1, gridSize * scaleRecip) +
CalculateSnappedOffset(localTransform.GetTranslation(), axis2, gridSize * scaleRecip)
: AZ::Vector3::CreateZero();
startInternal.m_snapOffset = snapOffset;
startInternal.m_localPosition = localTransform.GetTranslation() + snapOffset;
startInternal.m_localPosition = localTransform.GetTranslation();
return startInternal;
}
PlanarManipulator::Action PlanarManipulator::CalculateManipulationDataAction(
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams,
const ViewportInteraction::MouseInteraction& interaction)
{
const ManipulatorInteraction manipulatorInteraction =
@@ -88,20 +74,18 @@ namespace AzToolsFramework
const AZ::Vector3 hitDelta = (localHitPosition - startInternal.m_localHitPosition) / nonUniformScale;
const AZ::Vector3 unsnappedOffset = axis1.Dot(hitDelta) * axis1 + axis2.Dot(hitDelta) * axis2;
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
const AZ::Vector3 nonUniformScaleRecip = manipulatorInteraction.m_nonUniformScaleReciprocal;
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
const float gridSize = gridSnapParams.m_gridSize;
const bool snapping = gridSnapParams.m_gridSnap;
Action action;
action.m_fixed = fixed;
action.m_start.m_localPosition = startInternal.m_localPosition;
action.m_start.m_snapOffset = startInternal.m_snapOffset;
action.m_start.m_localHitPosition = startInternal.m_localHitPosition;
action.m_current.m_localOffset = snapping
? unsnappedOffset +
CalculateSnappedOffset(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis1)) +
CalculateSnappedOffset(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis2))
? CalculateSnappedAmount(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(fixed.m_axis1)) +
CalculateSnappedAmount(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(fixed.m_axis2))
: unsnappedOffset;
// record what modifier keys are held during this action
@@ -141,18 +125,17 @@ namespace AzToolsFramework
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
m_startInternal = CalculateManipulationDataStart(
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()),
interaction, rayIntersectionDistance);
if (m_onLeftMouseDownCallback)
{
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
m_onLeftMouseDownCallback(CalculateManipulationDataAction(
m_fixed, m_startInternal, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
gridSnapParams, interaction));
}
}
@@ -164,8 +147,7 @@ namespace AzToolsFramework
m_onMouseMoveCallback(CalculateManipulationDataAction(
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
TransformNormalizedScale(GetLocalTransform()), gridSnapParams, interaction));
}
}
@@ -177,8 +159,7 @@ namespace AzToolsFramework
m_onLeftMouseUpCallback(CalculateManipulationDataAction(
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
TransformNormalizedScale(GetLocalTransform()), gridSnapParams, interaction));
}
}
@@ -195,8 +176,7 @@ namespace AzToolsFramework
const GridSnapParameters gridSnapParams = GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId);
const auto action = CalculateManipulationDataAction(
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction);
TransformNormalizedScale(GetLocalTransform()), gridSnapParams, mouseInteraction);
// display the exact hit (ray intersection) of the mouse pick on the manipulator
DrawTransformAxes(
@@ -21,7 +21,7 @@
namespace AzToolsFramework
{
class ManipulatorView;
struct GridSnapAction;
struct GridSnapParameters;
/// PlanarManipulator serves as a visual tool for users to modify values
/// in two dimension in a plane defined two non-collinear axes in 3D space.
@@ -58,7 +58,6 @@ namespace AzToolsFramework
{
AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space.
AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens.
AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid.
};
/// The state of the manipulator during an interaction.
@@ -120,7 +119,6 @@ namespace AzToolsFramework
{
AZ::Vector3 m_localPosition; ///< The starting position of the manipulator in local space.
AZ::Vector3 m_localHitPosition; ///< The intersection point in world space between the ray and the manipulator when the mouse down event happens.
AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid.
};
Fixed m_fixed;
@@ -134,12 +132,11 @@ namespace AzToolsFramework
static StartInternal CalculateManipulationDataStart(
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance);
const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance);
static Action CalculateManipulationDataAction(
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction);
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams,
const ViewportInteraction::MouseInteraction& interaction);
};
} // namespace AzToolsFramework