Add improvements for objects spawning and snapping in Editor to include object bounds

This commit is contained in:
Wojciech Figat
2022-01-10 17:46:53 +01:00
parent cd72916838
commit d11166082c
11 changed files with 82 additions and 63 deletions

View File

@@ -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;

View File

@@ -917,23 +917,6 @@ namespace FlaxEditor
}
}
/// <summary>
/// Gets the actor bounding box (including child actors).
/// </summary>
/// <param name="actor">The actor.</param>
/// <param name="box">The bounding box.</param>
public static void GetActorEditorBox(Actor actor, out BoundingBox box)
{
if (actor)
{
Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out box);
}
else
{
box = BoundingBox.Zero;
}
}
/// <summary>
/// Closes editor splash screen popup window.
/// </summary>

View File

@@ -85,6 +85,56 @@ namespace FlaxEditor.Gizmo
return node;
}
/// <inheritdoc />
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;
}
}
/// <inheritdoc />
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;
}
}
}

View File

@@ -510,42 +510,6 @@ namespace FlaxEditor.Gizmo
UpdateMatrices();
}
/// <inheritdoc />
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;
}
}
/// <summary>
/// Gets a value indicating whether this tool can transform objects.
/// </summary>

View File

@@ -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);
}
}
/// <inheritdoc />

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;

View File

@@ -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()

View File

@@ -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;