add spline snap

This commit is contained in:
Ruan Lucas
2023-09-21 12:44:47 -04:00
parent 49a6b5734a
commit 4451f5feb2

View File

@@ -7,6 +7,7 @@ using Real = System.Single;
#endif
using System;
using System.Collections.Generic;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Modules;
using FlaxEngine;
@@ -287,6 +288,10 @@ namespace FlaxEditor.SceneGraph.Actors
private const Real PointNodeSize = 1.5f;
private const Real TangentNodeSize = 1.0f;
private const Real SnapIndicatorSize = 1.7f;
private const Real SnapPointIndicatorSize = 2f;
private static Spline _currentEditSpline;
/// <inheritdoc />
public SplineNode(Actor actor)
@@ -298,6 +303,11 @@ namespace FlaxEditor.SceneGraph.Actors
private unsafe void OnUpdate()
{
if (Input.Keyboard.GetKey(KeyboardKeys.Shift))
{
EditSplineWithSnap();
}
// Sync spline points with gizmo handles
var actor = (Spline)Actor;
var dstCount = actor.SplinePointsCount;
@@ -328,6 +338,56 @@ namespace FlaxEditor.SceneGraph.Actors
}
}
private void EditSplineWithSnap()
{
if (_currentEditSpline == null || _currentEditSpline != Actor)
return;
var selectedNode = SelectedSplineNode();
if (selectedNode == null)
return;
var selectedNodeBounds = new BoundingSphere(selectedNode.Transform.Translation, 1f);
var allSplinesInView = GetSplinesOnView();
allSplinesInView.Remove(_currentEditSpline);
if (allSplinesInView.Count == 0 || selectedNode == null)
return;
var snappedOnSplinePoint = false;
for (int i = 0; i < allSplinesInView.Count; i++)
{
for (int x = 0; x < allSplinesInView[i].SplineKeyframes.Length; x++)
{
var keyframePosition = allSplinesInView[i].GetSplinePoint(x);
var pointIndicatorSize = NodeSizeByDistance(keyframePosition, SnapPointIndicatorSize);
var keyframeBounds = new BoundingSphere(keyframePosition, pointIndicatorSize);
DebugDraw.DrawSphere(keyframeBounds, Color.Red, 0, false);
if (keyframeBounds.Intersects(selectedNodeBounds))
{
_currentEditSpline.SetSplinePoint(selectedNode.Index, keyframeBounds.Center);
snappedOnSplinePoint = true;
break;
}
}
}
if (!snappedOnSplinePoint)
{
var nearSplineSnapPoint = GetNearSplineSnapPosition(selectedNode.Transform.Translation, allSplinesInView);
var snapIndicatorSize = NodeSizeByDistance(nearSplineSnapPoint, SnapIndicatorSize);
var snapBounds = new BoundingSphere(nearSplineSnapPoint, snapIndicatorSize);
if (snapBounds.Intersects(selectedNodeBounds))
{
_currentEditSpline.SetSplinePoint(selectedNode.Index, snapBounds.Center);
}
DebugDraw.DrawSphere(snapBounds, Color.Yellow, 0, true);
}
}
/// <inheritdoc />
public override void PostSpawn()
{
@@ -396,6 +456,7 @@ namespace FlaxEditor.SceneGraph.Actors
internal static void OnSplineEdited(Spline spline)
{
_currentEditSpline = spline;
var collider = spline.GetChild<SplineCollider>();
if (collider && collider.Scene && collider.IsActiveInHierarchy && collider.HasStaticFlag(StaticFlags.Navigation) && !Editor.IsPlayMode)
{
@@ -407,6 +468,60 @@ namespace FlaxEditor.SceneGraph.Actors
}
}
private static SplinePointNode SelectedSplineNode()
{
var selection = Editor.Instance.SceneEditing.Selection;
if (selection.Count != 1)
return null;
if (selection[0] is not SplineNode.SplinePointNode)
return null;
return (SplinePointNode)selection[0];
}
private static List<Spline> GetSplinesOnView()
{
var splines = Level.GetActors<Spline>();
var splinesOnView = new List<Spline>();
var viewTransform = Editor.Instance.Windows.EditWin.Viewport.ViewTransform;
var viewFov = Editor.Instance.Windows.EditWin.Viewport.FieldOfView;
var viewNear = Editor.Instance.Windows.EditWin.Viewport.NearPlane;
var viewFar = Editor.Instance.Windows.EditWin.Viewport.FarPlane;
var viewAspect = Editor.Instance.Windows.EditWin.Width / Editor.Instance.Windows.EditWin.Height;
var viewBounds = BoundingFrustum.FromCamera(viewTransform.Translation, viewTransform.Forward, viewTransform.Up, viewFov, viewNear, viewFar, viewAspect);
foreach (var s in splines)
{
var contains = viewBounds.Contains(s.EditorBox);
if (contains == ContainmentType.Contains || contains == ContainmentType.Intersects)
{
splinesOnView.Add(s);
}
}
return splinesOnView;
}
private static Vector3 GetNearSplineSnapPosition(Vector3 position, List<Spline> splines)
{
var nearPoint = splines[0].GetSplinePointClosestToPoint(position);
var nearDistance = Vector3.Distance(nearPoint, position);
for (int i = 1; i < splines.Count; i++)
{
var point = splines[i].GetSplinePointClosestToPoint(position);
var distance = Vector3.Distance(point, position);
if (distance < nearDistance)
{
nearPoint = point;
nearDistance = distance;
}
}
return nearPoint;
}
internal static Real NodeSizeByDistance(Vector3 nodePosition, Real nodeSize)
{
var cameraTransform = Editor.Instance.Windows.EditWin.Viewport.ViewportCamera.Viewport.ViewTransform;