Merge branch 'Zode-absolutesnap'

This commit is contained in:
Wojtek Figat
2025-03-11 14:05:30 +01:00
3 changed files with 74 additions and 6 deletions

View File

@@ -75,6 +75,11 @@ namespace FlaxEditor.Gizmo
/// </summary> /// </summary>
public bool ScaleSnapEnabled = false; public bool ScaleSnapEnabled = false;
/// <summary>
/// True if enable absolute grid snapping (snaps objects to world-space grid, not the one relative to gizmo location)
/// </summary>
public bool AbsoluteSnapEnabled = false;
/// <summary> /// <summary>
/// Translation snap value /// Translation snap value
/// </summary> /// </summary>

View File

@@ -2,8 +2,10 @@
#if USE_LARGE_WORLDS #if USE_LARGE_WORLDS
using Real = System.Double; using Real = System.Double;
using Mathr = FlaxEngine.Mathd;
#else #else
using Real = System.Single; using Real = System.Single;
using Mathr = FlaxEngine.Mathf;
#endif #endif
using System; using System;
@@ -40,6 +42,7 @@ namespace FlaxEditor.Gizmo
private Vector3 _intersectPosition; private Vector3 _intersectPosition;
private bool _isActive; private bool _isActive;
private bool _isDuplicating; private bool _isDuplicating;
private bool _hasAbsoluteSnapped;
private bool _isTransforming; private bool _isTransforming;
private bool _isSelected; private bool _isSelected;
@@ -366,6 +369,7 @@ namespace FlaxEditor.Gizmo
if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping) if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping)
{ {
var snapValue = new Vector3(isScaling ? ScaleSnapValue : TranslationSnapValue); var snapValue = new Vector3(isScaling ? ScaleSnapValue : TranslationSnapValue);
_translationScaleSnapDelta += delta; _translationScaleSnapDelta += delta;
if (!isScaling && snapValue.X < 0.0f) if (!isScaling && snapValue.X < 0.0f)
{ {
@@ -384,11 +388,29 @@ namespace FlaxEditor.Gizmo
else else
snapValue.Z = (Real)b.Minimum.Z - b.Maximum.Z; snapValue.Z = (Real)b.Minimum.Z - b.Maximum.Z;
} }
Vector3 absoluteDelta = Vector3.Zero;
if (!_hasAbsoluteSnapped && AbsoluteSnapEnabled && ActiveTransformSpace == TransformSpace.World)
{
// Remove delta to offset local-space grid into the world-space grid
_hasAbsoluteSnapped = true;
Vector3 currentTranslationScale = isScaling ? GetSelectedTransform(0).Scale : GetSelectedTransform(0).Translation;
absoluteDelta = currentTranslationScale - new Vector3(
Mathr.Round(currentTranslationScale.X / snapValue.X) * snapValue.X,
Mathr.Round(currentTranslationScale.Y / snapValue.Y) * snapValue.Y,
Mathr.Round(currentTranslationScale.Z / snapValue.Z) * snapValue.Z);
}
delta = new Vector3( delta = new Vector3(
(int)(_translationScaleSnapDelta.X / snapValue.X) * snapValue.X, (int)(_translationScaleSnapDelta.X / snapValue.X) * snapValue.X,
(int)(_translationScaleSnapDelta.Y / snapValue.Y) * snapValue.Y, (int)(_translationScaleSnapDelta.Y / snapValue.Y) * snapValue.Y,
(int)(_translationScaleSnapDelta.Z / snapValue.Z) * snapValue.Z); (int)(_translationScaleSnapDelta.Z / snapValue.Z) * snapValue.Z);
_translationScaleSnapDelta -= delta; _translationScaleSnapDelta -= delta;
delta -= absoluteDelta;
}
else
{
_hasAbsoluteSnapped = false;
} }
if (_activeMode == Mode.Translate) if (_activeMode == Mode.Translate)
@@ -418,12 +440,33 @@ namespace FlaxEditor.Gizmo
if (RotationSnapEnabled || Owner.UseSnapping) if (RotationSnapEnabled || Owner.UseSnapping)
{ {
float snapValue = RotationSnapValue * Mathf.DegreesToRadians; float snapValue = RotationSnapValue * Mathf.DegreesToRadians;
float absoluteDelta = 0.0f;
if (!_hasAbsoluteSnapped && AbsoluteSnapEnabled && ActiveTransformSpace == TransformSpace.World)
{
// Remove delta to offset world-space grid into the local-space grid
_hasAbsoluteSnapped = true;
float currentAngle = 0.0f;
switch (_activeAxis)
{
case Axis.X: currentAngle = GetSelectedTransform(0).Orientation.EulerAngles.X; break;
case Axis.Y: currentAngle = GetSelectedTransform(0).Orientation.EulerAngles.Y; break;
case Axis.Z: currentAngle = GetSelectedTransform(0).Orientation.EulerAngles.Z; break;
}
absoluteDelta = currentAngle - (Mathf.Round(currentAngle / RotationSnapValue) * RotationSnapValue);
}
_rotationSnapDelta += delta; _rotationSnapDelta += delta;
float snapped = Mathf.Round(_rotationSnapDelta / snapValue) * snapValue; float snapped = Mathf.Round(_rotationSnapDelta / snapValue) * snapValue;
_rotationSnapDelta -= snapped; _rotationSnapDelta -= snapped;
delta = snapped; delta = snapped;
delta -= absoluteDelta * Mathf.DegreesToRadians;
}
else
{
_hasAbsoluteSnapped = false;
} }
switch (_activeAxis) switch (_activeAxis)

View File

@@ -138,7 +138,9 @@ namespace FlaxEditor.Viewport
if (useProjectCache) if (useProjectCache)
{ {
// Initialize snapping enabled from cached values // Initialize snapping enabled from cached values
if (editor.ProjectCache.TryGetCustomData("TranslateSnapState", out bool cachedBool)) if (editor.ProjectCache.TryGetCustomData("AbsoluteSnapState", out bool cachedBool))
transformGizmo.AbsoluteSnapEnabled = cachedBool;
if (editor.ProjectCache.TryGetCustomData("TranslateSnapState", out cachedBool))
transformGizmo.TranslationSnapEnable = cachedBool; transformGizmo.TranslationSnapEnable = cachedBool;
if (editor.ProjectCache.TryGetCustomData("RotationSnapState", out cachedBool)) if (editor.ProjectCache.TryGetCustomData("RotationSnapState", out cachedBool))
transformGizmo.RotationSnapEnabled = cachedBool; transformGizmo.RotationSnapEnabled = cachedBool;
@@ -162,13 +164,31 @@ namespace FlaxEditor.Viewport
TooltipText = $"Gizmo transform space (world or local) ({inputOptions.ToggleTransformSpace})", TooltipText = $"Gizmo transform space (world or local) ({inputOptions.ToggleTransformSpace})",
Parent = transformSpaceWidget Parent = transformSpaceWidget
}; };
transformSpaceWidget.Parent = viewport;
// Absolute snapping widget
var absoluteSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var enableAbsoluteSnapping = new ViewportWidgetButton("A", SpriteHandle.Invalid, null, true)
{
Checked = transformGizmo.AbsoluteSnapEnabled,
TooltipText = "Enable absolute grid snapping (world-space absolute grid, rather than object-relative grid)",
Parent = absoluteSnappingWidget
};
enableAbsoluteSnapping.Toggled += _ =>
{
transformGizmo.AbsoluteSnapEnabled = !transformGizmo.AbsoluteSnapEnabled;
if (useProjectCache)
editor.ProjectCache.SetCustomData("AbsoluteSnapState", transformGizmo.AbsoluteSnapEnabled);
};
absoluteSnappingWidget.Parent = viewport;
transformSpaceToggle.Toggled += _ => transformSpaceToggle.Toggled += _ =>
{ {
transformGizmo.ToggleTransformSpace(); transformGizmo.ToggleTransformSpace();
if (useProjectCache) if (useProjectCache)
editor.ProjectCache.SetCustomData("TransformSpaceState", transformGizmo.ActiveTransformSpace.ToString()); editor.ProjectCache.SetCustomData("TransformSpaceState", transformGizmo.ActiveTransformSpace.ToString());
absoluteSnappingWidget.Visible = transformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World;
}; };
transformSpaceWidget.Parent = viewport;
// Scale snapping widget // Scale snapping widget
var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
@@ -383,17 +403,17 @@ namespace FlaxEditor.Viewport
gizmoModeRotate.Checked = mode == TransformGizmoBase.Mode.Rotate; gizmoModeRotate.Checked = mode == TransformGizmoBase.Mode.Rotate;
gizmoModeScale.Checked = mode == TransformGizmoBase.Mode.Scale; gizmoModeScale.Checked = mode == TransformGizmoBase.Mode.Scale;
}; };
// Setup input actions // Setup input actions
viewport.InputActions.Add(options => options.TranslateMode, () => viewport.InputActions.Add(options => options.TranslateMode, () =>
{ {
viewport.GetInput(out var input); viewport.GetInput(out var input);
if (input.IsMouseRightDown) if (input.IsMouseRightDown)
return; return;
transformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate; transformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate;
}); });
viewport.InputActions.Add(options => options.RotateMode, () => viewport.InputActions.Add(options => options.RotateMode, () =>
{ {
viewport.GetInput(out var input); viewport.GetInput(out var input);
if (input.IsMouseRightDown) if (input.IsMouseRightDown)