diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs index 8cc049716..33521a084 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs @@ -203,7 +203,7 @@ namespace FlaxEditor.Gizmo } if (verts != null && selectedvert != -1) { - Transform t = GetSelectedObject(0).Transform; + Transform t = thisTransform; Vector3 selected = ((verts[selectedvert].Position * t.Orientation) * t.Scale) + t.Translation; Matrix matrix = new Transform(selected, t.Orientation, new Float3(gizmoModelsScale2RealGizmoSize)).GetWorld(); cubeMesh.Draw(ref renderContext, _materialSphere, ref matrix); diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Types.cs b/Source/Editor/Gizmo/TransformGizmoBase.Types.cs index 377bd28a0..d622a8fcf 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Types.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Types.cs @@ -12,42 +12,42 @@ namespace FlaxEditor.Gizmo /// /// None. /// - None, + None = 0, /// /// The X axis. /// - X, + X = 1, /// /// The Y axis. /// - Y, + Y = 2, /// /// The Z axis. /// - Z, + Z = 4, /// /// The XY plane. /// - XY, + XY = X|Y, /// /// The ZX plane. /// - ZX, + ZX = Z|X, /// /// The YZ plane. /// - YZ, + YZ = Y|Z, /// /// The center point. /// - Center, + Center = 8, }; /// diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs index dfae81dc1..51e363014 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using FlaxEditor.SceneGraph; using FlaxEngine; +using FlaxEditor.Surface; namespace FlaxEditor.Gizmo { @@ -137,16 +138,22 @@ namespace FlaxEditor.Gizmo { switch (_activePivotType) { - case PivotType.ObjectCenter: - if (SelectionCount > 0) - Position = GetSelectedObject(0).Transform.Translation; - break; - case PivotType.SelectionCenter: - Position = GetSelectionCenter(); - break; - case PivotType.WorldOrigin: - Position = Vector3.Zero; - break; + case PivotType.ObjectCenter: + if (SelectionCount > 0) + Position = GetSelectedObject(0).Transform.Translation; + break; + case PivotType.SelectionCenter: + Position = GetSelectionCenter(); + break; + case PivotType.WorldOrigin: + Position = Vector3.Zero; + break; + } + if(verts != null) + { + Transform t = thisTransform; + Vector3 selected = ((verts[selectedvert].Position * t.Orientation) * t.Scale) + t.Translation; + Position += -(Position - selected); } Position += _translationDelta; } @@ -210,88 +217,88 @@ namespace FlaxEditor.Gizmo Real intersection; switch (_activeAxis) { - case Axis.X: - { - var plane = planeDotXY > planeDotZX ? planeXY : planeZX; - if (ray.Intersects(ref plane, out intersection)) - { - _intersectPosition = ray.Position + ray.Direction * intersection; - if (_lastIntersectionPosition != Vector3.Zero) - _tDelta = _intersectPosition - _lastIntersectionPosition; - delta = new Vector3(_tDelta.X, 0, 0); - } - break; - } - case Axis.Y: - { - var plane = planeDotXY > planeDotYZ ? planeXY : planeYZ; - if (ray.Intersects(ref plane, out intersection)) - { - _intersectPosition = ray.Position + ray.Direction * intersection; - if (_lastIntersectionPosition != Vector3.Zero) - _tDelta = _intersectPosition - _lastIntersectionPosition; - delta = new Vector3(0, _tDelta.Y, 0); - } - break; - } - case Axis.Z: - { - var plane = planeDotZX > planeDotYZ ? planeZX : planeYZ; - if (ray.Intersects(ref plane, out intersection)) - { - _intersectPosition = ray.Position + ray.Direction * intersection; - if (_lastIntersectionPosition != Vector3.Zero) - _tDelta = _intersectPosition - _lastIntersectionPosition; - delta = new Vector3(0, 0, _tDelta.Z); - } - break; - } - case Axis.YZ: - { - if (ray.Intersects(ref planeYZ, out intersection)) - { - _intersectPosition = ray.Position + ray.Direction * intersection; - if (_lastIntersectionPosition != Vector3.Zero) - _tDelta = _intersectPosition - _lastIntersectionPosition; - delta = new Vector3(0, _tDelta.Y, _tDelta.Z); - } - break; - } - case Axis.XY: - { - if (ray.Intersects(ref planeXY, out intersection)) - { - _intersectPosition = ray.Position + ray.Direction * intersection; - if (_lastIntersectionPosition != Vector3.Zero) - _tDelta = _intersectPosition - _lastIntersectionPosition; - delta = new Vector3(_tDelta.X, _tDelta.Y, 0); - } - break; - } - case Axis.ZX: - { - if (ray.Intersects(ref planeZX, out intersection)) - { - _intersectPosition = ray.Position + ray.Direction * intersection; - if (_lastIntersectionPosition != Vector3.Zero) - _tDelta = _intersectPosition - _lastIntersectionPosition; - delta = new Vector3(_tDelta.X, 0, _tDelta.Z); - } - break; - } - case Axis.Center: - { - var gizmoToView = Position - Owner.ViewPosition; - var plane = new Plane(-Vector3.Normalize(gizmoToView), gizmoToView.Length); - if (ray.Intersects(ref plane, out intersection)) - { - _intersectPosition = ray.Position + ray.Direction * intersection; - if (_lastIntersectionPosition != Vector3.Zero) - _tDelta = _intersectPosition - _lastIntersectionPosition; - } - delta = _tDelta; - break; - } + case Axis.X: + { + var plane = planeDotXY > planeDotZX ? planeXY : planeZX; + if (ray.Intersects(ref plane, out intersection)) + { + _intersectPosition = ray.Position + ray.Direction * intersection; + if (_lastIntersectionPosition != Vector3.Zero) + _tDelta = _intersectPosition - _lastIntersectionPosition; + delta = new Vector3(_tDelta.X, 0, 0); + } + break; + } + case Axis.Y: + { + var plane = planeDotXY > planeDotYZ ? planeXY : planeYZ; + if (ray.Intersects(ref plane, out intersection)) + { + _intersectPosition = ray.Position + ray.Direction * intersection; + if (_lastIntersectionPosition != Vector3.Zero) + _tDelta = _intersectPosition - _lastIntersectionPosition; + delta = new Vector3(0, _tDelta.Y, 0); + } + break; + } + case Axis.Z: + { + var plane = planeDotZX > planeDotYZ ? planeZX : planeYZ; + if (ray.Intersects(ref plane, out intersection)) + { + _intersectPosition = ray.Position + ray.Direction * intersection; + if (_lastIntersectionPosition != Vector3.Zero) + _tDelta = _intersectPosition - _lastIntersectionPosition; + delta = new Vector3(0, 0, _tDelta.Z); + } + break; + } + case Axis.YZ: + { + if (ray.Intersects(ref planeYZ, out intersection)) + { + _intersectPosition = ray.Position + ray.Direction * intersection; + if (_lastIntersectionPosition != Vector3.Zero) + _tDelta = _intersectPosition - _lastIntersectionPosition; + delta = new Vector3(0, _tDelta.Y, _tDelta.Z); + } + break; + } + case Axis.XY: + { + if (ray.Intersects(ref planeXY, out intersection)) + { + _intersectPosition = ray.Position + ray.Direction * intersection; + if (_lastIntersectionPosition != Vector3.Zero) + _tDelta = _intersectPosition - _lastIntersectionPosition; + delta = new Vector3(_tDelta.X, _tDelta.Y, 0); + } + break; + } + case Axis.ZX: + { + if (ray.Intersects(ref planeZX, out intersection)) + { + _intersectPosition = ray.Position + ray.Direction * intersection; + if (_lastIntersectionPosition != Vector3.Zero) + _tDelta = _intersectPosition - _lastIntersectionPosition; + delta = new Vector3(_tDelta.X, 0, _tDelta.Z); + } + break; + } + case Axis.Center: + { + var gizmoToView = Position - Owner.ViewPosition; + var plane = new Plane(-Vector3.Normalize(gizmoToView), gizmoToView.Length); + if (ray.Intersects(ref plane, out intersection)) + { + _intersectPosition = ray.Position + ray.Direction * intersection; + if (_lastIntersectionPosition != Vector3.Zero) + _tDelta = _intersectPosition - _lastIntersectionPosition; + } + delta = _tDelta; + break; + } } // Modifiers @@ -364,30 +371,30 @@ namespace FlaxEditor.Gizmo switch (_activeAxis) { - case Axis.X: - case Axis.Y: - case Axis.Z: - { - Float3 dir; - if (_activeAxis == Axis.X) - dir = Float3.Right * _gizmoWorld.Orientation; - else if (_activeAxis == Axis.Y) - dir = Float3.Up * _gizmoWorld.Orientation; - else - dir = Float3.Forward * _gizmoWorld.Orientation; + case Axis.X: + case Axis.Y: + case Axis.Z: + { + Float3 dir; + if (_activeAxis == Axis.X) + dir = Float3.Right * _gizmoWorld.Orientation; + else if (_activeAxis == Axis.Y) + dir = Float3.Up * _gizmoWorld.Orientation; + else + dir = Float3.Forward * _gizmoWorld.Orientation; - Float3 viewDir = Owner.ViewPosition - Position; - Float3.Dot(ref viewDir, ref dir, out float dot); - if (dot < 0.0f) - delta *= -1; + Float3 viewDir = Owner.ViewPosition - Position; + Float3.Dot(ref viewDir, ref dir, out float dot); + if (dot < 0.0f) + delta *= -1; - Quaternion.RotationAxis(ref dir, delta, out _rotationDelta); - break; - } + Quaternion.RotationAxis(ref dir, delta, out _rotationDelta); + break; + } - default: - _rotationDelta = Quaternion.Identity; - break; + default: + _rotationDelta = Quaternion.Identity; + break; } } @@ -398,6 +405,8 @@ namespace FlaxEditor.Gizmo Mesh.Vertex[] verts; Mesh.Vertex[] otherVerts; Transform otherTransform; + StaticModel SelectedModel; + Transform thisTransform => SelectedModel.Transform; bool hasSelectedVertex; int selectedvert; int otherSelectedvert; @@ -428,22 +437,25 @@ namespace FlaxEditor.Gizmo { switch (_activeMode) { - case Mode.Scale: - case Mode.Translate: - UpdateTranslateScale(); - break; - case Mode.Rotate: - UpdateRotate(dt); - break; + case Mode.Translate: + UpdateTranslateScale(); + VertexSnap(); + break; + case Mode.Scale: + UpdateTranslateScale(); + break; + case Mode.Rotate: + UpdateRotate(dt); + break; } - VertexSnap(); + } else { // If nothing selected, try to select any axis if (!isLeftBtnDown && !Owner.IsRightMouseButtonDown) { - if (Owner.IsAltKeyDown) + if (Owner.IsAltKeyDown && _activeMode == Mode.Translate) SelectVertexSnaping(); SelectAxis(); } @@ -535,31 +547,72 @@ namespace FlaxEditor.Gizmo } void SelectVertexSnaping() { - //this - if (GetSelectedObject(0).EditableObject is Actor e) + Vector3 point = Vector3.Zero; + var ray = Owner.MouseRay; + Real lastdistance = Real.MaxValue; + StaticModel Lastmodel = null; + int index = 0; + + int i = 0; + //get first + for (; i < SelectionCount; i++) { - if (e is StaticModel model) + if (GetSelectedObject(i).EditableObject is StaticModel model) { - verts = model.Model.LODs[0].Meshes[0].DownloadVertexBuffer(); - var ray = Owner.MouseRay; var bb = model.EditorBox; - //select vertex - if (CollisionsHelper.RayIntersectsBox(ref ray, ref bb, out Vector3 point)) + if (CollisionsHelper.RayIntersectsBox(ref ray, ref bb, out Vector3 p)) { - point = GetSelectedObject(0).Transform.WorldToLocal(point); - Real lastdistance = Vector3.Distance(point, verts[0].Position); - for (int i = 0; i < verts.Length; i++) + Lastmodel = model; + point = p; + index = 0; + break; + } + } + } + + if (Lastmodel == null) // nothing to do return + return; + + //find closest bounding box in selection + for (; i < SelectionCount; i++) + { + if (GetSelectedObject(i).EditableObject is StaticModel model) + { + var bb = model.EditorBox; + //check for other we might have one closer + var d = Vector3.Distance(model.Transform.Translation, ray.Position); + if (lastdistance < d) + { + if (CollisionsHelper.RayIntersectsBox(ref ray, ref bb, out Vector3 p)) { - var d = Vector3.Distance(point, verts[i].Position); - if (d <= lastdistance) - { - lastdistance = d; - selectedvert = i; - } + lastdistance = d; + Lastmodel = model; + point = p; + index = i; } } } } + SelectedModel = Lastmodel; + + //find closest vertex to bounding box point (collision detection approximation) + //[ToDo] replace this with collision detection with is suporting concave shapes (compute shader) + point = thisTransform.WorldToLocal(point); + + //[To Do] comlite this there is not suport for multy mesh model + verts = Lastmodel.Model.LODs[0].Meshes[0].DownloadVertexBuffer(); + + lastdistance = Vector3.Distance(point, verts[0].Position); + for (int j = 0; j < verts.Length; j++) + { + var d = Vector3.Distance(point, verts[j].Position); + if (d <= lastdistance) + { + lastdistance = d; + selectedvert = j; + } + + } } void VertexSnap() { @@ -572,9 +625,14 @@ namespace FlaxEditor.Gizmo SceneGraphNode.RayCastData rayCast = new SceneGraphNode.RayCastData() { Ray = ray, - Exclude = new List() { (Actor)GetSelectedObject(0).EditableObject }, + Exclude = new List() {}, Scan = new List() { typeof(StaticModel) } }; + for (int i = 0; i < SelectionCount; i++) + { + rayCast.Exclude.Add((Actor)GetSelectedObject(i).EditableObject); + } + //grab scene and raycast var actor = GetSelectedObject(0).ParentScene.RayCast(ref rayCast, out var distance, out var _); if (actor != null) { @@ -583,11 +641,13 @@ namespace FlaxEditor.Gizmo otherTransform = model.Transform; Vector3 p = rayCast.Ray.Position + (rayCast.Ray.Direction * distance); + //[To Do] comlite this there is not suport for multy mesh model otherVerts = model.Model.LODs[0].Meshes[0].DownloadVertexBuffer(); + //find closest vertex to bounding box point (collision detection approximation) + //[ToDo] replace this with collision detection with is suporting concave shapes (compute shader) p = actor.Transform.WorldToLocal(p); Real lastdistance = Vector3.Distance(p, otherVerts[0].Position); - for (int i = 0; i < otherVerts.Length; i++) { var d = Vector3.Distance(p, otherVerts[i].Position); @@ -597,6 +657,7 @@ namespace FlaxEditor.Gizmo otherSelectedvert = i; } } + if(lastdistance > 25) { otherSelectedvert = -1; @@ -608,19 +669,43 @@ namespace FlaxEditor.Gizmo if (verts != null && otherVerts != null) { - Transform t = GetSelectedObject(0).Transform; + Transform t = thisTransform; Vector3 selected = ((verts[selectedvert].Position * t.Orientation) * t.Scale) + t.Translation; t = otherTransform; Vector3 other = ((otherVerts[otherSelectedvert].Position * t.Orientation) * t.Scale) + t.Translation; // Translation - _translationDelta = -(selected - other); + var projection = -(selected - other); + + //at some point + //Quaternion inverse = t.Orientation; + //inverse.Invert(); + //projection *= inverse; //world to local + //flip mask + //var Not = ~_activeAxis; + //LockAxisWorld(Not, ref projection); //lock axis + //projection *= t.Orientation; //local to world + + _translationDelta = projection; } Profiler.EndEvent(); } + /// + /// zeros the component using the + /// + public static void LockAxisWorld(Axis lockAxis, ref Vector3 v) + { + if (lockAxis.HasFlag(Axis.X)) + v.X = 0; + if (lockAxis.HasFlag(Axis.Y)) + v.Y = 0; + if (lockAxis.HasFlag(Axis.Z)) + v.Z = 0; + } + /// /// Gets a value indicating whether this tool can transform objects. ///