diff --git a/Source/Editor/Gizmo/GizmoBase.cs b/Source/Editor/Gizmo/GizmoBase.cs index a44c677dd..5dfa742bd 100644 --- a/Source/Editor/Gizmo/GizmoBase.cs +++ b/Source/Editor/Gizmo/GizmoBase.cs @@ -80,6 +80,13 @@ namespace FlaxEditor.Gizmo { } + /// + /// Performs scene objects snapping to the ground. + /// + public virtual void SnapToGround() + { + } + /// /// Draws the gizmo. /// diff --git a/Source/Editor/Gizmo/IGizmoOwner.cs b/Source/Editor/Gizmo/IGizmoOwner.cs index d3dc6cbc0..54983b3b8 100644 --- a/Source/Editor/Gizmo/IGizmoOwner.cs +++ b/Source/Editor/Gizmo/IGizmoOwner.cs @@ -89,5 +89,10 @@ namespace FlaxEditor.Gizmo /// Gets a object used by the gizmo owner. /// Undo Undo { get; } + + /// + /// Gets the root tree node for the scene graph. + /// + SceneGraph.RootNode SceneGraphRoot { get; } } } diff --git a/Source/Editor/Gizmo/TransformGizmo.cs b/Source/Editor/Gizmo/TransformGizmo.cs index f490de430..6d7a2ccd3 100644 --- a/Source/Editor/Gizmo/TransformGizmo.cs +++ b/Source/Editor/Gizmo/TransformGizmo.cs @@ -218,6 +218,12 @@ namespace FlaxEditor.Gizmo } } + /// + protected override bool IsSelected(SceneGraphNode obj) + { + return _selection.Contains(obj); + } + /// protected override void OnApplyTransformation(ref Vector3 translationDelta, ref Quaternion rotationDelta, ref Vector3 scaleDelta) { diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs index 768fa0617..60fc7b816 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using FlaxEditor.SceneGraph; using FlaxEngine; namespace FlaxEditor.Gizmo @@ -398,15 +399,7 @@ namespace FlaxEditor.Gizmo // Snap to ground if (_activeAxis == Axis.None && SelectionCount != 0 && Owner.SnapToGround) { - if (Physics.RayCast(Position, Vector3.Down, out var hit, float.MaxValue, uint.MaxValue, false)) - { - StartTransforming(); - var translationDelta = hit.Point - Position; - var rotationDelta = Quaternion.Identity; - var scaleDelta = Vector3.Zero; - OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta); - EndTransforming(); - } + SnapToGround(); } // Only when is active else if (_isActive) @@ -517,6 +510,39 @@ namespace FlaxEditor.Gizmo UpdateMatrices(); } + /// + public override void SnapToGround() + { + if (Owner.SceneGraphRoot == null) + return; + var ray = new Ray(Position, Vector3.Down); + while (true) + { + var view = new Ray(Owner.ViewPosition, Owner.ViewDirection); + var rayCastFlags = SceneGraphNode.RayCastData.FlagTypes.SkipEditorPrimitives; + var hit = Owner.SceneGraphRoot.RayCast(ref ray, ref view, out var distance, out _, rayCastFlags); + if (hit != null) + { + // Skip snapping selection to itself + if (IsSelected(hit)) + { + GetSelectedObjectsBounds(out var selectionBounds, out _); + ray.Position = ray.GetPoint(selectionBounds.Size.Y * 0.5f); + continue; + } + + // Snap + StartTransforming(); + var translationDelta = ray.GetPoint(distance) - Position; + var rotationDelta = Quaternion.Identity; + var scaleDelta = Vector3.Zero; + OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta); + EndTransforming(); + } + break; + } + } + /// /// Gets a value indicating whether this tool can transform objects. /// @@ -545,6 +571,13 @@ namespace FlaxEditor.Gizmo /// True if editing the selected objects transformations marks the navigation system area dirty (for auto-rebuild), otherwise skip update. protected abstract void GetSelectedObjectsBounds(out BoundingBox bounds, out bool navigationDirty); + /// + /// Checks if the specified object is selected. + /// + /// The object to check. + /// True if it's selected, otherwise false. + protected abstract bool IsSelected(SceneGraphNode obj); + /// /// Called when user starts transforming selected objects. /// diff --git a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs index 7443b52ad..5401000c9 100644 --- a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs +++ b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs @@ -2,6 +2,7 @@ using System; using FlaxEditor.Gizmo; +using FlaxEditor.SceneGraph; using FlaxEditor.Tools.Foliage.Undo; using FlaxEngine; @@ -87,6 +88,12 @@ namespace FlaxEditor.Tools.Foliage navigationDirty = false; } + /// + protected override bool IsSelected(SceneGraphNode obj) + { + return false; + } + /// protected override void OnStartTransforming() { @@ -231,6 +238,21 @@ namespace FlaxEditor.Tools.Foliage Owner.Undo?.AddAction(action); } + /// + public override void SnapToGround() + { + if (Physics.RayCast(Position, Vector3.Down, out var hit, float.MaxValue, uint.MaxValue, false)) + { + // Snap + StartTransforming(); + var translationDelta = hit.Point - Position; + var rotationDelta = Quaternion.Identity; + var scaleDelta = Vector3.Zero; + OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta); + EndTransforming(); + } + } + /// public override void OnActivated() { diff --git a/Source/Editor/Viewport/EditorGizmoViewport.cs b/Source/Editor/Viewport/EditorGizmoViewport.cs index 5c9fcf034..0e81292a3 100644 --- a/Source/Editor/Viewport/EditorGizmoViewport.cs +++ b/Source/Editor/Viewport/EditorGizmoViewport.cs @@ -21,10 +21,12 @@ namespace FlaxEditor.Viewport /// /// The task. /// The undo. - public EditorGizmoViewport(SceneRenderTask task, Undo undo) + /// The scene graph root. + public EditorGizmoViewport(SceneRenderTask task, Undo undo, SceneGraph.RootNode sceneGraphRoot) : base(task, new FPSCamera(), true) { Undo = undo; + SceneGraphRoot = sceneGraphRoot; SetUpdate(ref _update, OnUpdate); } @@ -73,6 +75,9 @@ namespace FlaxEditor.Viewport /// public Undo Undo { get; } + /// + public SceneGraph.RootNode SceneGraphRoot { get; } + /// protected override bool IsControllingMouse => Gizmos.Active?.IsControllingMouse ?? false; diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 0c759c950..e29b97dc7 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -184,7 +184,7 @@ namespace FlaxEditor.Viewport /// /// Editor instance. public MainEditorGizmoViewport(Editor editor) - : base(Object.New(), editor.Undo) + : base(Object.New(), editor.Undo, editor.Scene.Root) { _editor = editor; _dragAssets = new DragAssets(ValidateDragItem); diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 4e71677b2..9b2c9b189 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -336,6 +336,9 @@ namespace FlaxEditor.Viewport /// public Undo Undo { get; } + /// + public RootNode SceneGraphRoot => _window.Graph.Root; + /// public EditorViewport Viewport => this;