diff --git a/Source/Editor/Gizmo/TransformGizmo.cs b/Source/Editor/Gizmo/TransformGizmo.cs index 741b89d2d..96584caa7 100644 --- a/Source/Editor/Gizmo/TransformGizmo.cs +++ b/Source/Editor/Gizmo/TransformGizmo.cs @@ -269,9 +269,9 @@ namespace FlaxEditor.Gizmo protected override int SelectionCount => _selectionParents.Count; /// - protected override Transform GetSelectedObject(int index) + protected override SceneGraphNode GetSelectedObject(int index) { - return _selectionParents[index].Transform; + return _selectionParents[index]; } /// diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs index 0d421a17e..33521a084 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs @@ -72,139 +72,160 @@ namespace FlaxEditor.Gizmo const float gizmoModelsScale2RealGizmoSize = 0.075f; Mesh sphereMesh, cubeMesh; + cubeMesh = _modelCube.LODs[0].Meshes[0]; + + Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3); + Matrix.Multiply(ref m3, ref world, out m1); + mx1 = m1; + mx1.M41 += 0.05f; + switch (_activeMode) { - case Mode.Translate: - { - if (!_modelTranslationAxis || !_modelTranslationAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) - break; - var transAxisMesh = _modelTranslationAxis.LODs[0].Meshes[0]; - cubeMesh = _modelCube.LODs[0].Meshes[0]; - sphereMesh = _modelSphere.LODs[0].Meshes[0]; - Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3); - Matrix.Multiply(ref m3, ref world, out m1); - mx1 = m1; - mx1.M41 += 0.05f; + case Mode.Translate: + { + if (!_modelTranslationAxis || !_modelTranslationAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) + break; + var transAxisMesh = _modelTranslationAxis.LODs[0].Meshes[0]; - // X axis - Matrix.RotationY(-Mathf.PiOverTwo, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - transAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); + sphereMesh = _modelSphere.LODs[0].Meshes[0]; - // Y axis - Matrix.RotationX(Mathf.PiOverTwo, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - transAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3); + // X axis + Matrix.RotationY(-Mathf.PiOverTwo, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + transAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); - // Z axis - Matrix.RotationX(Mathf.Pi, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - transAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + // Y axis + Matrix.RotationX(Mathf.PiOverTwo, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + transAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3); - // XY plane - m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); - Matrix.Multiply(ref m2, ref m1, out m3); - cubeMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX, ref m3); + // Z axis + Matrix.RotationX(Mathf.Pi, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + transAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); - // ZX plane - m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); - Matrix.Multiply(ref m2, ref m1, out m3); - cubeMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ, ref m3); + // XY plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX, ref m3); - // YZ plane - m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); - Matrix.Multiply(ref m2, ref m1, out m3); - cubeMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY, ref m3); + // ZX plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ, ref m3); - // Center sphere - Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); + // YZ plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY, ref m3); - break; + // Center sphere + Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); + + break; + } + + case Mode.Rotate: + { + if (!_modelRotationAxis || !_modelRotationAxis.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) + break; + var rotationAxisMesh = _modelRotationAxis.LODs[0].Meshes[0]; + sphereMesh = _modelSphere.LODs[0].Meshes[0]; + + // X axis + Matrix.RotationZ(Mathf.PiOverTwo, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + rotationAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); + + // Y axis + rotationAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m1); + + // Z axis + Matrix.RotationX(-Mathf.PiOverTwo, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + rotationAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + + // Center box + Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); + + break; + } + + case Mode.Scale: + { + if (!_modelScaleAxis || !_modelScaleAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) + break; + var scaleAxisMesh = _modelScaleAxis.LODs[0].Meshes[0]; + cubeMesh = _modelCube.LODs[0].Meshes[0]; + sphereMesh = _modelSphere.LODs[0].Meshes[0]; + + // X axis + Matrix.RotationY(-Mathf.PiOverTwo, out m2); + Matrix.Multiply(ref m2, ref mx1, out m3); + scaleAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); + + // Y axis + Matrix.RotationX(Mathf.PiOverTwo, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + scaleAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3); + + // Z axis + Matrix.RotationX(Mathf.Pi, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + scaleAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + + // XY plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX, ref m3); + + // ZX plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ, ref m3); + + // YZ plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY, ref m3); + + // Center box + Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); + + break; + } } - - case Mode.Rotate: + if (verts != null && selectedvert != -1) { - if (!_modelRotationAxis || !_modelRotationAxis.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) - break; - var rotationAxisMesh = _modelRotationAxis.LODs[0].Meshes[0]; - sphereMesh = _modelSphere.LODs[0].Meshes[0]; - Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3); - Matrix.Multiply(ref m3, ref world, out m1); - mx1 = m1; - mx1.M41 += 0.05f; + 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); - // X axis - Matrix.RotationZ(Mathf.PiOverTwo, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - rotationAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); + if (otherVerts != null && otherSelectedvert != -1) + { + t = otherTransform; + Vector3 other = ((otherVerts[otherSelectedvert].Position * t.Orientation) * t.Scale) + t.Translation; + matrix = new Transform(selected, t.Orientation, new Float3(gizmoModelsScale2RealGizmoSize)).GetWorld(); + cubeMesh.Draw(ref renderContext, _materialSphere, ref matrix); + DebugDraw.DrawLine(other, selected, Color.Aqua); + } - // Y axis - rotationAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m1); + //t = otherTransform; + //for (int i = 0; i < otherVerts.Length; i++) + //{ + // Matrix matrix = new Transform(((otherVerts[i].Position * t.Orientation) * t.Scale) + t.Translation, t.Orientation, new Float3(gizmoModelsScale2RealGizmoSize)).GetWorld(); + // cubeMesh.Draw(ref renderContext, i == otherSelectedvert ? _materialAxisFocus : _materialSphere, ref matrix); + //} - // Z axis - Matrix.RotationX(-Mathf.PiOverTwo, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - rotationAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + //t = GetSelectedObject(0).Transform; - // Center box - Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); - - break; - } - - case Mode.Scale: - { - if (!_modelScaleAxis || !_modelScaleAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) - break; - var scaleAxisMesh = _modelScaleAxis.LODs[0].Meshes[0]; - cubeMesh = _modelCube.LODs[0].Meshes[0]; - sphereMesh = _modelSphere.LODs[0].Meshes[0]; - Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3); - Matrix.Multiply(ref m3, ref world, out m1); - mx1 = m1; - mx1.M41 -= 0.05f; - - // X axis - Matrix.RotationY(-Mathf.PiOverTwo, out m2); - Matrix.Multiply(ref m2, ref mx1, out m3); - scaleAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); - - // Y axis - Matrix.RotationX(Mathf.PiOverTwo, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - scaleAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3); - - // Z axis - Matrix.RotationX(Mathf.Pi, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - scaleAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); - - // XY plane - m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); - Matrix.Multiply(ref m2, ref m1, out m3); - cubeMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX, ref m3); - - // ZX plane - m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); - Matrix.Multiply(ref m2, ref m1, out m3); - cubeMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ, ref m3); - - // YZ plane - m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); - Matrix.Multiply(ref m2, ref m1, out m3); - cubeMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY, ref m3); - - // Center box - Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); - - break; - } } } } diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs b/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs index 86c0a6afe..1ebe0f254 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs @@ -27,7 +27,7 @@ namespace FlaxEditor.Gizmo // Get center point Vector3 center = Vector3.Zero; for (int i = 0; i < count; i++) - center += GetSelectedObject(i).Translation; + center += GetSelectedObject(i).Transform.Translation; // Return arithmetic average or whatever it means return center / count; @@ -47,6 +47,11 @@ namespace FlaxEditor.Gizmo private void SelectAxis() { + if (Owner.IsControlDown) + { + + } + // Get mouse ray Ray ray = Owner.MouseRay; 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 6123d348a..ddd3272ee 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 { @@ -108,7 +109,7 @@ namespace FlaxEditor.Gizmo _startTransforms.Capacity = Mathf.NextPowerOfTwo(count); for (var i = 0; i < count; i++) { - _startTransforms.Add(GetSelectedObject(i)); + _startTransforms.Add(GetSelectedObject(i).Transform); } GetSelectedObjectsBounds(out _startBounds, out _navigationDirty); @@ -137,16 +138,22 @@ namespace FlaxEditor.Gizmo { switch (_activePivotType) { - case PivotType.ObjectCenter: - if (SelectionCount > 0) - Position = GetSelectedObject(0).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; } @@ -180,7 +187,7 @@ namespace FlaxEditor.Gizmo _screenScale = (float)(vLength.Length / GizmoScaleFactor * gizmoSize); } // Setup world - Quaternion orientation = GetSelectedObject(0).Orientation; + Quaternion orientation = GetSelectedObject(0).Transform.Orientation; _gizmoWorld = new Transform(position, orientation, new Float3(_screenScale)); if (_activeTransformSpace == TransformSpace.World && _activeMode != Mode.Scale) { @@ -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,36 +371,45 @@ 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; } } /// public override bool IsControllingMouse => _isTransforming; + //vertex snaping stff + Mesh.Vertex[] verts; + Mesh.Vertex[] otherVerts; + Transform otherTransform; + StaticModel SelectedModel; + Transform thisTransform => SelectedModel.Transform; + bool hasSelectedVertex; + int selectedvert; + int otherSelectedvert; /// public override void Update(float dt) { @@ -421,20 +437,34 @@ namespace FlaxEditor.Gizmo { switch (_activeMode) { - case Mode.Scale: - case Mode.Translate: - UpdateTranslateScale(); - break; - case Mode.Rotate: - UpdateRotate(dt); - break; + case Mode.Translate: + UpdateTranslateScale(); + if (Owner.UseSnapping) + VertexSnap(); + break; + case Mode.Scale: + UpdateTranslateScale(); + break; + case Mode.Rotate: + UpdateRotate(dt); + break; } + } else { // If nothing selected, try to select any axis if (!isLeftBtnDown && !Owner.IsRightMouseButtonDown) + { + if (Owner.IsAltKeyDown && _activeMode == Mode.Translate) + SelectVertexSnaping(); SelectAxis(); + } + else if (Owner.IsAltKeyDown) + { + verts = null; + otherVerts = null; + } } // Set positions of the gizmo @@ -516,6 +546,166 @@ namespace FlaxEditor.Gizmo // Update UpdateMatrices(); } + void SelectVertexSnaping() + { + 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 (GetSelectedObject(i).EditableObject is StaticModel model) + { + var bb = model.EditorBox; + if (CollisionsHelper.RayIntersectsBox(ref ray, ref bb, out Vector3 p)) + { + 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)) + { + 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() + { + Profiler.BeginEvent("VertexSnap"); + //ray cast others + if (verts != null) + { + var ray = Owner.MouseRay; + + SceneGraphNode.RayCastData rayCast = new SceneGraphNode.RayCastData() + { + Ray = ray, + 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) + { + if (actor.EditableObject is StaticModel model) + { + 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); + if (d <= lastdistance) + { + lastdistance = d; + otherSelectedvert = i; + } + } + + if(lastdistance > 25) + { + otherSelectedvert = -1; + otherVerts = null; + } + } + } + } + + if (verts != null && otherVerts != null) + { + 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 + 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. @@ -536,7 +726,7 @@ namespace FlaxEditor.Gizmo /// Gets the selected object transformation. /// /// The selected object index. - protected abstract Transform GetSelectedObject(int index); + protected abstract SceneGraphNode GetSelectedObject(int index); /// /// Gets the selected objects bounding box (contains the whole selection). diff --git a/Source/Editor/SceneGraph/Actors/FoliageNode.cs b/Source/Editor/SceneGraph/Actors/FoliageNode.cs index 9cb405092..50756170a 100644 --- a/Source/Editor/SceneGraph/Actors/FoliageNode.cs +++ b/Source/Editor/SceneGraph/Actors/FoliageNode.cs @@ -10,10 +10,21 @@ namespace FlaxEditor.SceneGraph.Actors [HideInEditor] public sealed class FoliageNode : ActorNode { + private FoliageInstance instance; + /// + /// The selected instance index + /// + public int SelectedInstanceIndex; + /// - public FoliageNode(Actor actor) + public FoliageNode(Foliage actor, int selectedInstanceIndex = -1) : base(actor) { + SelectedInstanceIndex = selectedInstanceIndex; + if (selectedInstanceIndex != -1) + { + instance = actor.GetInstance(selectedInstanceIndex); + } } } } diff --git a/Source/Editor/SceneGraph/SceneGraphNode.cs b/Source/Editor/SceneGraph/SceneGraphNode.cs index 672a239dc..4ca8034e1 100644 --- a/Source/Editor/SceneGraph/SceneGraphNode.cs +++ b/Source/Editor/SceneGraph/SceneGraphNode.cs @@ -13,6 +13,7 @@ using FlaxEditor.Modules; using FlaxEditor.SceneGraph.Actors; using FlaxEditor.Windows; using FlaxEngine; +using System.Runtime.CompilerServices; namespace FlaxEditor.SceneGraph { @@ -216,6 +217,29 @@ namespace FlaxEditor.SceneGraph /// The flags. /// public FlagTypes Flags; + + /// + /// The exclude list actors specyfaied in + /// + public List Exclude = new List(); + + /// + /// The scan for types + /// + public List Scan = new List(); + + /// + /// if this is true it will include the types specyfaied in + /// otherwise it will include all types excluding types specyfaied in + /// + public bool ExcludeScan; + + /// + /// Initializes a new instance of the struct. + /// + public RayCastData() + { + } } /// @@ -271,16 +295,18 @@ namespace FlaxEditor.SceneGraph normal = Vector3.Up; return null; } - - // Check itself SceneGraphNode minTarget = null; Real minDistance = Real.MaxValue; Vector3 minDistanceNormal = Vector3.Up; - if (RayCastSelf(ref ray, out distance, out normal)) + if (Mask(ref ray)) { - minTarget = this; - minDistance = distance; - minDistanceNormal = normal; + // Check itself + if (RayCastSelf(ref ray, out distance, out normal)) + { + minTarget = this; + minDistance = distance; + minDistanceNormal = normal; + } } // Check all children @@ -294,12 +320,40 @@ namespace FlaxEditor.SceneGraph minDistanceNormal = normal; } } - // Return result distance = minDistance; normal = minDistanceNormal; return minTarget; } + /// + /// Masks the objects base of and . + /// + /// The ray. + /// true if can pass through mask + private bool Mask(ref RayCastData ray) + { + //filter actors + for (int j = 0; j < ray.Exclude.Count; j++) + { + if ((EditableObject is Actor a) && a == ray.Exclude[j]) + { + //remove form exclude + //because it is pased by ref and funcion is recursive it will slowly shrink the list untile nothing is left + //micro optimization + ray.Exclude.RemoveAt(j); + return false; + } + } + //filter types + for (int i = 0; i < ray.Scan.Count; i++) + { + if (EditableObject.GetType() != ray.Scan[i]) + { + return false; + } + } + return true; + } /// /// Checks if given ray intersects with the node. diff --git a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs index 0c0172b36..1ba8ef445 100644 --- a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs +++ b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs @@ -3,6 +3,7 @@ using System; using FlaxEditor.Gizmo; using FlaxEditor.SceneGraph; +using FlaxEditor.SceneGraph.Actors; using FlaxEditor.Tools.Foliage.Undo; using FlaxEngine; @@ -69,7 +70,7 @@ namespace FlaxEditor.Tools.Foliage } /// - protected override Transform GetSelectedObject(int index) + protected override SceneGraphNode GetSelectedObject(int index) { var foliage = GizmoMode.SelectedFoliage; if (!foliage) @@ -77,8 +78,7 @@ namespace FlaxEditor.Tools.Foliage var instanceIndex = GizmoMode.SelectedInstanceIndex; if (instanceIndex < 0 || instanceIndex >= foliage.InstancesCount) throw new InvalidOperationException("No foliage instance selected."); - var instance = foliage.GetInstance(instanceIndex); - return foliage.Transform.LocalToWorld(instance.Transform); + return new FoliageNode(foliage, instanceIndex); } ///