From d11166082c566809c474ac4a4ef347689df38bc1 Mon Sep 17 00:00:00 2001 From: Wojciech Figat Date: Mon, 10 Jan 2022 17:46:53 +0100 Subject: [PATCH] Add improvements for objects spawning and snapping in Editor to include object bounds --- Source/Editor/Content/Proxy/PrefabProxy.cs | 2 +- Source/Editor/Editor.cs | 17 ------ Source/Editor/Gizmo/TransformGizmo.cs | 55 +++++++++++++++++-- Source/Editor/Gizmo/TransformGizmoBase.cs | 36 ------------ .../Editor/Tools/Foliage/EditFoliageGizmo.cs | 7 +++ .../Viewport/MainEditorGizmoViewport.cs | 8 ++- .../Editor/Viewport/PrefabWindowViewport.cs | 5 +- Source/Engine/Level/Actors/AnimatedModel.cpp | 7 +++ Source/Engine/Level/Actors/AnimatedModel.h | 1 + Source/Engine/Level/Actors/Decal.cpp | 6 ++ Source/Engine/Level/Actors/Decal.h | 1 + 11 files changed, 82 insertions(+), 63 deletions(-) diff --git a/Source/Editor/Content/Proxy/PrefabProxy.cs b/Source/Editor/Content/Proxy/PrefabProxy.cs index d597919ff..81d0ba8c6 100644 --- a/Source/Editor/Content/Proxy/PrefabProxy.cs +++ b/Source/Editor/Content/Proxy/PrefabProxy.cs @@ -164,7 +164,7 @@ namespace FlaxEditor.Content // Auto fit actor to camera float targetSize = 30.0f; - Editor.GetActorEditorBox(_preview.Instance, out var bounds); + var bounds = _preview.Instance.EditorBoxChildren; float maxSize = Mathf.Max(0.001f, bounds.Size.MaxValue); _preview.Instance.Scale = new Vector3(targetSize / maxSize); _preview.Instance.Position = Vector3.Zero; diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index d96f6f55f..40923e97f 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -917,23 +917,6 @@ namespace FlaxEditor } } - /// - /// Gets the actor bounding box (including child actors). - /// - /// The actor. - /// The bounding box. - public static void GetActorEditorBox(Actor actor, out BoundingBox box) - { - if (actor) - { - Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out box); - } - else - { - box = BoundingBox.Zero; - } - } - /// /// Closes editor splash screen popup window. /// diff --git a/Source/Editor/Gizmo/TransformGizmo.cs b/Source/Editor/Gizmo/TransformGizmo.cs index feed70b57..db4c0aa1d 100644 --- a/Source/Editor/Gizmo/TransformGizmo.cs +++ b/Source/Editor/Gizmo/TransformGizmo.cs @@ -85,6 +85,56 @@ namespace FlaxEditor.Gizmo return node; } + /// + 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 + bool isSelected = false; + for (var e = hit; e != null && !isSelected; e = e.ParentNode) + isSelected |= IsSelected(e); + if (isSelected) + { + GetSelectedObjectsBounds(out var selectionBounds, out _); + ray.Position = ray.GetPoint(selectionBounds.Size.Y * 0.5f); + continue; + } + + // Include objects bounds into target snap location + var editorBounds = BoundingBox.Empty; + var bottomToCenter = 100000.0f; + for (int i = 0; i < _selectionParents.Count; i++) + { + if (_selectionParents[i] is ActorNode actorNode) + { + var b = actorNode.Actor.EditorBoxChildren; + BoundingBox.Merge(ref editorBounds, ref b, out editorBounds); + bottomToCenter = Mathf.Min(bottomToCenter, actorNode.Actor.Position.Y - editorBounds.Minimum.Y); + } + } + var newPosition = ray.GetPoint(distance) + new Vector3(0, bottomToCenter, 0); + + // Snap + StartTransforming(); + var translationDelta = newPosition - Position; + var rotationDelta = Quaternion.Identity; + var scaleDelta = Vector3.Zero; + OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta); + EndTransforming(); + } + break; + } + } + /// public override void Pick() { @@ -211,10 +261,7 @@ namespace FlaxEditor.Gizmo if (_selectionParents[i] is ActorNode actorNode) { bounds = BoundingBox.Merge(bounds, actorNode.Actor.BoxWithChildren); - if (actorNode.AffectsNavigationWithChildren) - { - navigationDirty |= actorNode.Actor.HasStaticFlag(StaticFlags.Navigation); - } + navigationDirty |= actorNode.AffectsNavigationWithChildren; } } } diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs index 518b312ad..d0b10f2a8 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.cs @@ -510,42 +510,6 @@ 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 - bool isSelected = false; - for (var e = hit; e != null && !isSelected; e = e.ParentNode) - isSelected |= IsSelected(e); - if (isSelected) - { - 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. /// diff --git a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs index 5401000c9..e965532c7 100644 --- a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs +++ b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs @@ -86,6 +86,13 @@ namespace FlaxEditor.Tools.Foliage { bounds = BoundingBox.Empty; navigationDirty = false; + var foliage = GizmoMode.SelectedFoliage; + var instanceIndex = GizmoMode.SelectedInstanceIndex; + if (foliage && instanceIndex >= 0 && instanceIndex < foliage.InstancesCount) + { + var instance = foliage.GetInstance(instanceIndex); + BoundingBox.FromSphere(ref instance.Bounds, out bounds); + } } /// diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 4bf399bd8..268d55492 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -887,11 +887,15 @@ namespace FlaxEditor.Viewport private Vector3 PostProcessSpawnedActorLocation(Actor actor, ref Vector3 hitLocation) { - Editor.GetActorEditorBox(actor, out _); + // Refresh actor position to ensure that cached bounds are valid + actor.Position = Vector3.One; + actor.Position = Vector3.Zero; // Place the object //var location = hitLocation - (box.Size.Length * 0.5f) * ViewDirection; - var location = hitLocation; + var editorBounds = actor.EditorBoxChildren; + var bottomToCenter = actor.Position.Y - editorBounds.Minimum.Y; + var location = hitLocation + new Vector3(0, bottomToCenter, 0); // Apply grid snapping if enabled if (UseSnapping || TransformGizmo.TranslationSnapEnable) diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 0ed67ab8e..c83e738f3 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -702,10 +702,9 @@ namespace FlaxEditor.Viewport private Vector3 PostProcessSpawnedActorLocation(Actor actor, ref Vector3 hitLocation) { - Editor.GetActorEditorBox(actor, out BoundingBox box); - // Place the object - var location = hitLocation - (box.Size.Length * 0.5f) * ViewDirection; + //var location = hitLocation - (box.Size.Length * 0.5f) * ViewDirection; + var location = hitLocation; // Apply grid snapping if enabled if (UseSnapping || TransformGizmo.TranslationSnapEnable) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 9fc6672d1..17e59e37c 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -745,6 +745,13 @@ void AnimatedModel::OnDebugDrawSelected() ModelInstanceActor::OnDebugDrawSelected(); } +BoundingBox AnimatedModel::GetEditorBox() const +{ + if (SkinnedModel) + SkinnedModel->WaitForLoaded(100); + return BoundingBox::MakeScaled(_box, 1.0f / BoundsScale); +} + #endif bool AnimatedModel::IntersectsItself(const Ray& ray, float& distance, Vector3& normal) diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index f3eb2500b..eec987831 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -378,6 +378,7 @@ public: void DrawGeneric(RenderContext& renderContext) override; #if USE_EDITOR void OnDebugDrawSelected() override; + BoundingBox GetEditorBox() const override; #endif bool IntersectsItself(const Ray& ray, float& distance, Vector3& normal) override; void Serialize(SerializeStream& stream, const void* otherObj) override; diff --git a/Source/Engine/Level/Actors/Decal.cpp b/Source/Engine/Level/Actors/Decal.cpp index 994b0fb72..200a635da 100644 --- a/Source/Engine/Level/Actors/Decal.cpp +++ b/Source/Engine/Level/Actors/Decal.cpp @@ -58,6 +58,12 @@ void Decal::OnDebugDrawSelected() Actor::OnDebugDrawSelected(); } +BoundingBox Decal::GetEditorBox() const +{ + const Vector3 size(10.0f); + return BoundingBox(_transform.Translation - size, _transform.Translation + size); +} + #endif void Decal::OnLayerChanged() diff --git a/Source/Engine/Level/Actors/Decal.h b/Source/Engine/Level/Actors/Decal.h index 7bff6dbff..f026da8bb 100644 --- a/Source/Engine/Level/Actors/Decal.h +++ b/Source/Engine/Level/Actors/Decal.h @@ -77,6 +77,7 @@ public: // [Actor] #if USE_EDITOR void OnDebugDrawSelected() override; + BoundingBox GetEditorBox() const override; #endif void OnLayerChanged() override; void Draw(RenderContext& renderContext) override;