diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs b/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs
index 9f1fb770a..7630d4c26 100644
--- a/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs
+++ b/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs
@@ -75,6 +75,11 @@ namespace FlaxEditor.Gizmo
///
public bool ScaleSnapEnabled = false;
+ ///
+ /// True if enable absolute grid snapping
+ ///
+ public bool AbsoluteSnapEnabled = false;
+
///
/// Translation snap value
///
diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs
index 92846c907..886d56c4d 100644
--- a/Source/Editor/Gizmo/TransformGizmoBase.cs
+++ b/Source/Editor/Gizmo/TransformGizmoBase.cs
@@ -40,6 +40,7 @@ namespace FlaxEditor.Gizmo
private Vector3 _intersectPosition;
private bool _isActive;
private bool _isDuplicating;
+ private bool _hasAbsoluteSnapped;
private bool _isTransforming;
private bool _isSelected;
@@ -366,6 +367,7 @@ namespace FlaxEditor.Gizmo
if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping)
{
var snapValue = new Vector3(isScaling ? ScaleSnapValue : TranslationSnapValue);
+
_translationScaleSnapDelta += delta;
if (!isScaling && snapValue.X < 0.0f)
{
@@ -384,11 +386,29 @@ namespace FlaxEditor.Gizmo
else
snapValue.Z = (Real)b.Minimum.Z - b.Maximum.Z;
}
+
+ Vector3 absoluteDelta = Vector3.Zero;
+ if (!_hasAbsoluteSnapped && AbsoluteSnapEnabled && ActiveTransformSpace == TransformSpace.World)
+ {
+ _hasAbsoluteSnapped = true;
+
+ Vector3 currentTranslationScale = isScaling ? GetSelectedTransform(0).Scale : GetSelectedTransform(0).Translation;
+ absoluteDelta = currentTranslationScale - new Vector3(
+ (Real)Math.Round(currentTranslationScale.X / snapValue.X) * snapValue.X,
+ (Real)Math.Round(currentTranslationScale.Y / snapValue.Y) * snapValue.Y,
+ (Real)Math.Round(currentTranslationScale.Z / snapValue.Z) * snapValue.Z);
+ }
+
delta = new Vector3(
(int)(_translationScaleSnapDelta.X / snapValue.X) * snapValue.X,
(int)(_translationScaleSnapDelta.Y / snapValue.Y) * snapValue.Y,
(int)(_translationScaleSnapDelta.Z / snapValue.Z) * snapValue.Z);
_translationScaleSnapDelta -= delta;
+ delta -= absoluteDelta;
+ }
+ else
+ {
+ _hasAbsoluteSnapped = false;
}
if (_activeMode == Mode.Translate)
@@ -418,12 +438,34 @@ namespace FlaxEditor.Gizmo
if (RotationSnapEnabled || Owner.UseSnapping)
{
float snapValue = RotationSnapValue * Mathf.DegreesToRadians;
+
+ float absoluteDelta = 0.0f;
+ if (!_hasAbsoluteSnapped && AbsoluteSnapEnabled && ActiveTransformSpace == TransformSpace.World)
+ {
+ _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;
float snapped = Mathf.Round(_rotationSnapDelta / snapValue) * snapValue;
_rotationSnapDelta -= snapped;
delta = snapped;
+ delta -= absoluteDelta * Mathf.DegreesToRadians;
+ }
+ else
+ {
+ _hasAbsoluteSnapped = false;
}
switch (_activeAxis)
diff --git a/Source/Editor/Viewport/EditorGizmoViewport.cs b/Source/Editor/Viewport/EditorGizmoViewport.cs
index d230f53fb..46e81b4c0 100644
--- a/Source/Editor/Viewport/EditorGizmoViewport.cs
+++ b/Source/Editor/Viewport/EditorGizmoViewport.cs
@@ -138,7 +138,9 @@ namespace FlaxEditor.Viewport
if (useProjectCache)
{
// 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;
if (editor.ProjectCache.TryGetCustomData("RotationSnapState", out cachedBool))
transformGizmo.RotationSnapEnabled = cachedBool;
@@ -170,6 +172,22 @@ namespace FlaxEditor.Viewport
};
transformSpaceWidget.Parent = viewport;
+ // Absolute snapping widget
+ var absoluteSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
+ var enableAbsoluteSnapping = new ViewportWidgetButton("A", SpriteHandle.Default, null, true)
+ {
+ Checked = transformGizmo.AbsoluteSnapEnabled,
+ TooltipText = "Enable absolute snapping",
+ Parent = absoluteSnappingWidget
+ };
+ enableAbsoluteSnapping.Toggled += _ =>
+ {
+ transformGizmo.AbsoluteSnapEnabled = !transformGizmo.AbsoluteSnapEnabled;
+ if (useProjectCache)
+ editor.ProjectCache.SetCustomData("AbsoluteSnapState", transformGizmo.AbsoluteSnapEnabled);
+ };
+ absoluteSnappingWidget.Parent = viewport;
+
// Scale snapping widget
var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var enableScaleSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.ScaleSnap32, null, true)