diff --git a/Source/Editor/Gizmo/TransformGizmo.cs b/Source/Editor/Gizmo/TransformGizmo.cs index 4918743ce..64f969990 100644 --- a/Source/Editor/Gizmo/TransformGizmo.cs +++ b/Source/Editor/Gizmo/TransformGizmo.cs @@ -263,6 +263,8 @@ namespace FlaxEditor.Gizmo // Note: because selection may contain objects and their children we have to split them and get only parents. // Later during transformation we apply translation/scale/rotation only on them (children inherit transformations) SceneGraphTools.BuildNodesParents(_selection, _selectionParents); + + base.OnSelectionChanged(newSelection); } /// diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs index 99b1c8122..81f76d392 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.cs @@ -437,8 +437,6 @@ namespace FlaxEditor.Gizmo { case Mode.Translate: UpdateTranslateScale(); - if (Owner.SnapToVertex) - UpdateVertexSnapping(); break; case Mode.Scale: UpdateTranslateScale(); @@ -447,6 +445,8 @@ namespace FlaxEditor.Gizmo UpdateRotate(dt); break; } + if (Owner.SnapToVertex) + UpdateVertexSnapping(); } else { @@ -553,41 +553,21 @@ namespace FlaxEditor.Gizmo for (int i = 0; i < SelectionCount; i++) { var obj = GetSelectedObject(i); - if (obj.CanVertexSnap && obj.RayCastSelf(ref ray, out var distance, out _) && distance < closestDistance) + if (obj.RayCastSelf(ref ray, out var distance, out _) && distance < closestDistance) { closestDistance = distance; closestObject = obj; } } if (closestObject == null) - { - // Find the closest object in selection (in case ray didn't hit anything) - for (int i = 0; i < SelectionCount; i++) - { - var obj = GetSelectedObject(i); - if (obj.CanVertexSnap) - { - GetSelectedObjectsBounds(out var bounds, out _); - CollisionsHelper.ClosestPointBoxPoint(ref bounds, ref ray.Ray.Position, out var point); - var distance = Vector3.Distance(ref point, ref ray.Ray.Position); - if (distance < closestDistance) - { - closestDistance = distance; - closestObject = obj; - } - } - } - } - _vertexSnapObject = closestObject; - if (closestObject == null) - return; + return; // ignore it if there is nothing under the mouse closestObject is only null if ray caster missed everything or Selection Count == 0 - // Find the closest vertex to bounding box point (collision detection approximation) - var closestPoint = ray.Ray.GetPoint(closestDistance); - if (!closestObject.OnVertexSnap(ref closestPoint, out _vertexSnapPoint)) + _vertexSnapObject = closestObject; + if (!closestObject.OnVertexSnap(ref ray.Ray, closestDistance, out _vertexSnapPoint)) { - // Failed to get the closest point - _vertexSnapPoint = closestPoint; + // The OnVertexSnap is unimplemented or failed to get point return because there is nothing to do + _vertexSnapPoint = Vector3.Zero; + return; } // Transform back to the local space of the object to work when moving it @@ -619,12 +599,11 @@ namespace FlaxEditor.Gizmo for (int i = 0; i < SelectionCount; i++) rayCast.ExcludeObjects.Add(GetSelectedObject(i)); var hit = Owner.SceneGraphRoot.RayCast(ref rayCast, out var distance, out var _); - if (hit != null && hit.CanVertexSnap) + if (hit != null) { - var point = rayCast.Ray.GetPoint(distance); - if (hit.OnVertexSnap(ref point, out var pointSnapped) + if (hit.OnVertexSnap(ref rayCast.Ray, distance, out var pointSnapped) //&& Vector3.Distance(point, pointSnapped) <= 25.0f - ) + ) { _vertexSnapObjectTo = hit; _vertexSnapPointTo = hit.Transform.WorldToLocal(pointSnapped); @@ -712,5 +691,12 @@ namespace FlaxEditor.Gizmo protected virtual void OnDuplicate() { } + + /// + public override void OnSelectionChanged(List newSelection) + { + EndVertexSnapping(); + UpdateGizmoPosition(); + } } } diff --git a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs index f1ab36041..1c09691e5 100644 --- a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs +++ b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs @@ -24,19 +24,22 @@ namespace FlaxEditor.SceneGraph.Actors { } + /// - public override bool OnVertexSnap(ref Vector3 point, out Vector3 result) + public override bool OnVertexSnap(ref Ray ray, float hitDistance, out Vector3 result) { - result = point; + // Find the closest vertex to bounding box point (collision detection approximation) + result = ray.GetPoint(hitDistance); var model = ((StaticModel)Actor).Model; if (model && !model.WaitForLoaded()) { // TODO: move to C++ and use cached vertex buffer internally inside the Mesh if (_vertices == null) _vertices = new(); - var pointLocal = (Float3)Actor.Transform.WorldToLocal(point); + var pointLocal = (Float3)Actor.Transform.WorldToLocal(result); var minDistance = float.MaxValue; - foreach (var lod in model.LODs) + var lodIndex = 0; // TODO: use LOD index based on the game view + var lod = model.LODs[lodIndex]; { var hit = false; foreach (var mesh in lod.Meshes) diff --git a/Source/Editor/SceneGraph/SceneGraphNode.cs b/Source/Editor/SceneGraph/SceneGraphNode.cs index 5cf28af37..dd6a4f9fe 100644 --- a/Source/Editor/SceneGraph/SceneGraphNode.cs +++ b/Source/Editor/SceneGraph/SceneGraphNode.cs @@ -94,18 +94,6 @@ namespace FlaxEditor.SceneGraph /// public virtual bool CanTransform => true; - /// - /// Gets a value indicating whether this node can be used for the vertex snapping feature. - /// - public bool CanVertexSnap - { - get - { - var v = Vector3.Zero; - return OnVertexSnap(ref v, out _); - } - } - /// /// Gets a value indicating whether this is active. /// @@ -365,14 +353,15 @@ namespace FlaxEditor.SceneGraph } /// - /// Performs the vertex snapping of a given point on the object surface that is closest to a given location. + /// Performs the vertex snapping for a given ray and hitDistance. /// - /// The position to snap. + /// The ray to raycast. + /// Hit distance from ray to object bounding box. /// The result point on the object mesh that is closest to the specified location. /// True if got a valid result value, otherwise false (eg. if missing data or not initialized). - public virtual bool OnVertexSnap(ref Vector3 point, out Vector3 result) + public virtual bool OnVertexSnap(ref Ray ray, float hitDistance, out Vector3 result) { - result = point; + result = Vector3.Zero; return false; }