From 8bcf4fdaf0f6235ce85582fb3f99122918538f65 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 24 Feb 2024 12:53:33 +0100 Subject: [PATCH] Cleanup and improve #2045 --- Source/Editor/Gizmo/IGizmoOwner.cs | 5 + Source/Editor/Gizmo/TransformGizmo.cs | 6 + .../Editor/Gizmo/TransformGizmoBase.Draw.cs | 263 +++++---- .../Gizmo/TransformGizmoBase.Selection.cs | 9 +- .../Editor/Gizmo/TransformGizmoBase.Types.cs | 6 +- Source/Editor/Gizmo/TransformGizmoBase.cs | 504 +++++++++--------- Source/Editor/Options/InputOptions.cs | 4 + .../Editor/SceneGraph/Actors/BoxBrushNode.cs | 6 +- .../Editor/SceneGraph/Actors/BoxVolumeNode.cs | 6 +- .../Editor/SceneGraph/Actors/FoliageNode.cs | 67 ++- .../Editor/SceneGraph/Actors/NavLinkNode.cs | 8 +- Source/Editor/SceneGraph/SceneGraphNode.cs | 81 ++- .../Editor/Tools/Foliage/EditFoliageGizmo.cs | 15 +- Source/Editor/Viewport/EditorGizmoViewport.cs | 3 + .../Editor/Viewport/PrefabWindowViewport.cs | 3 + 15 files changed, 507 insertions(+), 479 deletions(-) diff --git a/Source/Editor/Gizmo/IGizmoOwner.cs b/Source/Editor/Gizmo/IGizmoOwner.cs index 3ab0a917b..af3043fd6 100644 --- a/Source/Editor/Gizmo/IGizmoOwner.cs +++ b/Source/Editor/Gizmo/IGizmoOwner.cs @@ -51,6 +51,11 @@ namespace FlaxEditor.Gizmo /// bool SnapToGround { get; } + /// + /// Gets a value indicating whether to use vertex snapping (check if user pressed the given input key to call action). + /// + bool SnapToVertex { get; } + /// /// Gets the view forward direction. /// diff --git a/Source/Editor/Gizmo/TransformGizmo.cs b/Source/Editor/Gizmo/TransformGizmo.cs index 96584caa7..c000f4a30 100644 --- a/Source/Editor/Gizmo/TransformGizmo.cs +++ b/Source/Editor/Gizmo/TransformGizmo.cs @@ -274,6 +274,12 @@ namespace FlaxEditor.Gizmo return _selectionParents[index]; } + /// + protected override Transform GetSelectedTransform(int index) + { + return _selectionParents[index].Transform; + } + /// protected override void GetSelectedObjectsBounds(out BoundingBox bounds, out bool navigationDirty) { diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs index 33521a084..cb7a7600c 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs @@ -72,7 +72,6 @@ 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); @@ -81,129 +80,135 @@ namespace FlaxEditor.Gizmo switch (_activeMode) { - case Mode.Translate: - { - if (!_modelTranslationAxis || !_modelTranslationAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) - break; - var transAxisMesh = _modelTranslationAxis.LODs[0].Meshes[0]; - - sphereMesh = _modelSphere.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); - - // 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); - - // 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); - - // 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 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; - } - } - if (verts != null && selectedvert != -1) + case Mode.Translate: { - Transform t = thisTransform; + 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]; + + // 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); + + // 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); + + // 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); + + // 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 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; + } + } + + // Vertex snapping + if (verts != null && SelectedModel != null && selectedvert != -1) + { + if (!_modelCube || !_modelCube.IsLoaded) + return; + cubeMesh = _modelCube.LODs[0].Meshes[0]; + + Transform t = SelectedModel.Transform; 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); @@ -211,21 +216,9 @@ namespace FlaxEditor.Gizmo 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); } - - //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); - //} - - //t = GetSelectedObject(0).Transform; - } } } diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs b/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs index 1ebe0f254..2b9eae7b9 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).Transform.Translation; + center += GetSelectedTransform(i).Translation; // Return arithmetic average or whatever it means return center / count; @@ -36,22 +36,15 @@ namespace FlaxEditor.Gizmo private bool IntersectsRotateCircle(Vector3 normal, ref Ray ray, out Real distance) { var plane = new Plane(Vector3.Zero, normal); - if (!plane.Intersects(ref ray, out distance)) return false; Vector3 hitPoint = ray.Position + ray.Direction * distance; - Real distanceNormalized = hitPoint.Length / RotateRadiusRaw; return Mathf.IsInRange(distanceNormalized, 0.9f, 1.1f); } 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 d622a8fcf..66acb4c2b 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Types.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Types.cs @@ -32,17 +32,17 @@ namespace FlaxEditor.Gizmo /// /// The XY plane. /// - XY = X|Y, + XY = X | Y, /// /// The ZX plane. /// - ZX = Z|X, + ZX = Z | X, /// /// The YZ plane. /// - YZ = Y|Z, + YZ = Y | Z, /// /// The center point. diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs index ddd3272ee..3e788d28f 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.cs @@ -10,7 +10,6 @@ using System; using System.Collections.Generic; using FlaxEditor.SceneGraph; using FlaxEngine; -using FlaxEditor.Surface; namespace FlaxEditor.Gizmo { @@ -54,6 +53,15 @@ namespace FlaxEditor.Gizmo private Vector3 _translationDelta; private Vector3 _translationScaleSnapDelta; + //vertex snaping stff + private Mesh.Vertex[] verts; + private Mesh.Vertex[] otherVerts; + private Transform otherTransform; + private StaticModel SelectedModel; + private bool hasSelectedVertex; + private int selectedvert; + private int otherSelectedvert; + /// /// Gets the gizmo position. /// @@ -109,7 +117,7 @@ namespace FlaxEditor.Gizmo _startTransforms.Capacity = Mathf.NextPowerOfTwo(count); for (var i = 0; i < count; i++) { - _startTransforms.Add(GetSelectedObject(i).Transform); + _startTransforms.Add(GetSelectedTransform(i)); } GetSelectedObjectsBounds(out _startBounds, out _navigationDirty); @@ -136,25 +144,30 @@ namespace FlaxEditor.Gizmo private void UpdateGizmoPosition() { + // Get gizmo pivot 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 = GetSelectedTransform(0).Translation; + break; + case PivotType.SelectionCenter: + Position = GetSelectionCenter(); + break; + case PivotType.WorldOrigin: + Position = Vector3.Zero; + break; } - if(verts != null) + + // Apply vertex snapping + if (verts != null && SelectedModel != null) { - Transform t = thisTransform; + Transform t = SelectedModel.Transform; Vector3 selected = ((verts[selectedvert].Position * t.Orientation) * t.Scale) + t.Translation; Position += -(Position - selected); } + + // Apply current movement Position += _translationDelta; } @@ -186,8 +199,9 @@ namespace FlaxEditor.Gizmo float gizmoSize = Editor.Instance.Options.Options.Visual.GizmoSize; _screenScale = (float)(vLength.Length / GizmoScaleFactor * gizmoSize); } + // Setup world - Quaternion orientation = GetSelectedObject(0).Transform.Orientation; + Quaternion orientation = GetSelectedTransform(0).Orientation; _gizmoWorld = new Transform(position, orientation, new Float3(_screenScale)); if (_activeTransformSpace == TransformSpace.World && _activeMode != Mode.Scale) { @@ -217,88 +231,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 @@ -371,45 +385,36 @@ 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) { @@ -437,33 +442,28 @@ namespace FlaxEditor.Gizmo { switch (_activeMode) { - case Mode.Translate: - UpdateTranslateScale(); - if (Owner.UseSnapping) - VertexSnap(); - break; - case Mode.Scale: - UpdateTranslateScale(); - break; - case Mode.Rotate: - UpdateRotate(dt); - break; + case Mode.Translate: + UpdateTranslateScale(); + if (Owner.SnapToVertex) + UpdateVertexSnapping(); + 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; + if (Owner.SnapToVertex) + SelectVertexSnapping(); + else + SelectAxis(); } } @@ -533,6 +533,7 @@ namespace FlaxEditor.Gizmo // Deactivate _isActive = false; _activeAxis = Axis.None; + EndVertexSnapping(); return; } @@ -546,167 +547,138 @@ 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++) + private void SelectVertexSnapping() + { + // Find the closest object in selection that is hit by the mouse ray + var ray = new SceneGraphNode.RayCastData { - if (GetSelectedObject(i).EditableObject is StaticModel model) + Ray = Owner.MouseRay, + }; + var closestDistance = Real.MaxValue; + StaticModel closestModel = null; + for (int i = 0; i < SelectionCount; i++) + { + var obj = GetSelectedObject(i); + if (obj.EditableObject is StaticModel model) { - var bb = model.EditorBox; - if (CollisionsHelper.RayIntersectsBox(ref ray, ref bb, out Vector3 p)) + if (obj.RayCastSelf(ref ray, out var distance, out var normal) && distance < closestDistance) { - Lastmodel = model; - point = p; - index = 0; - break; + closestDistance = distance; + closestModel = model; } } } - - if (Lastmodel == null) // nothing to do return - return; - - //find closest bounding box in selection - for (; i < SelectionCount; i++) + if (closestModel == null) { - if (GetSelectedObject(i).EditableObject is StaticModel model) + // Find the closest object in selection (in case ray didn't hit anything) + for (int i = 0; i < SelectionCount; i++) { - var bb = model.EditorBox; - //check for other we might have one closer - var d = Vector3.Distance(model.Transform.Translation, ray.Position); - if (lastdistance < d) + var obj = GetSelectedObject(i); + if (obj.EditableObject is StaticModel model) { - if (CollisionsHelper.RayIntersectsBox(ref ray, ref bb, out Vector3 p)) + var bounds = model.Box; + CollisionsHelper.ClosestPointBoxPoint(ref bounds, ref ray.Ray.Position, out var point); + var distance = Vector3.Distance(ref point, ref ray.Ray.Position); + if (distance < closestDistance) { - lastdistance = d; - Lastmodel = model; - point = p; - index = i; + closestDistance = distance; + closestModel = model; } } } } - SelectedModel = Lastmodel; + SelectedModel = closestModel; + if (closestModel == null) + return; - //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); + // Find the closest vertex to bounding box point (collision detection approximation) + // TODO: replace this with collision detection which supports concave shapes (compute shader) + var hitPoint = SelectedModel.Transform.WorldToLocal(ray.Ray.GetPoint(closestDistance)); + // TODO: support multi-mesh models + verts = closestModel.Model.LODs[0].Meshes[0].DownloadVertexBuffer(); + closestDistance = Vector3.Distance(hitPoint, verts[0].Position); for (int j = 0; j < verts.Length; j++) { - var d = Vector3.Distance(point, verts[j].Position); - if (d <= lastdistance) + var distance = Vector3.Distance(hitPoint, verts[j].Position); + if (distance <= closestDistance) { - lastdistance = d; + closestDistance = distance; selectedvert = j; } - } } - void VertexSnap() + + private void EndVertexSnapping() { + // Clear current vertex snapping data + SelectedModel = null; + verts = null; + otherVerts = null; + } + + private void UpdateVertexSnapping() + { + if (Owner.SceneGraphRoot == null) + return; Profiler.BeginEvent("VertexSnap"); - //ray cast others + + // Ray cast others if (verts != null) { var ray = Owner.MouseRay; - - SceneGraphNode.RayCastData rayCast = new SceneGraphNode.RayCastData() + var rayCast = new SceneGraphNode.RayCastData { Ray = ray, - Exclude = new List() {}, - Scan = new List() { typeof(StaticModel) } + Flags = SceneGraphNode.RayCastData.FlagTypes.SkipColliders | SceneGraphNode.RayCastData.FlagTypes.SkipEditorPrimitives, + ExcludeObjects = new(), }; for (int i = 0; i < SelectionCount; i++) + rayCast.ExcludeObjects.Add(GetSelectedObject(i)); + + // Raycast objects + var hit = Owner.SceneGraphRoot.RayCast(ref rayCast, out var distance, out var _); + if (hit != null && hit.EditableObject is StaticModel model) { - 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 point = 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) + point = hit.Transform.WorldToLocal(point); + var closestDistance = Vector3.Distance(point, otherVerts[0].Position); + for (int i = 0; i < otherVerts.Length; i++) { - 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++) + distance = Vector3.Distance(point, otherVerts[i].Position); + if (distance < closestDistance) { - var d = Vector3.Distance(p, otherVerts[i].Position); - if (d <= lastdistance) - { - lastdistance = d; - otherSelectedvert = i; - } + closestDistance = distance; + otherSelectedvert = i; } + } - if(lastdistance > 25) - { - otherSelectedvert = -1; - otherVerts = null; - } + if (closestDistance > 25) + { + otherSelectedvert = -1; + otherVerts = null; } } } - if (verts != null && otherVerts != null) + if (verts != null && SelectedModel != 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; + // Snap current vertex to the other vertex + Vector3 selected = SelectedModel.Transform.LocalToWorld(verts[selectedvert].Position); + Vector3 other = otherTransform.LocalToWorld(otherVerts[otherSelectedvert].Position); + _translationDelta = other - selected; } 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. /// @@ -722,11 +694,19 @@ namespace FlaxEditor.Gizmo /// protected abstract int SelectionCount { get; } + /// + /// Gets the selected object. + /// + /// The selected object index. + /// The selected object (eg. actor node). + protected abstract SceneGraphNode GetSelectedObject(int index); + /// /// Gets the selected object transformation. /// /// The selected object index. - protected abstract SceneGraphNode GetSelectedObject(int index); + /// The transformation of the selected object. + protected abstract Transform GetSelectedTransform(int index); /// /// Gets the selected objects bounding box (contains the whole selection). diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index e2e7d0e71..ec50d1501 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -112,6 +112,10 @@ namespace FlaxEditor.Options [EditorDisplay("Scene", "Snap To Ground"), EditorOrder(500)] public InputBinding SnapToGround = new InputBinding(KeyboardKeys.End); + [DefaultValue(typeof(InputBinding), "End")] + [EditorDisplay("Scene", "Vertex Snapping"), EditorOrder(550)] + public InputBinding SnapToVertex = new InputBinding(KeyboardKeys.V); + [DefaultValue(typeof(InputBinding), "F5")] [EditorDisplay("Scene", "Play/Stop"), EditorOrder(510)] public InputBinding Play = new InputBinding(KeyboardKeys.F5); diff --git a/Source/Editor/SceneGraph/Actors/BoxBrushNode.cs b/Source/Editor/SceneGraph/Actors/BoxBrushNode.cs index da28dad2b..3d5bd9ed2 100644 --- a/Source/Editor/SceneGraph/Actors/BoxBrushNode.cs +++ b/Source/Editor/SceneGraph/Actors/BoxBrushNode.cs @@ -200,12 +200,8 @@ namespace FlaxEditor.SceneGraph.Actors : base(actor) { var id = ID; - var bytes = id.ToByteArray(); for (int i = 0; i < 6; i++) - { - bytes[0] += 1; - AddChildNode(new SideLinkNode(this, new Guid(bytes), i)); - } + AddChildNode(new SideLinkNode(this, GetSubID(id, i), i)); } /// diff --git a/Source/Editor/SceneGraph/Actors/BoxVolumeNode.cs b/Source/Editor/SceneGraph/Actors/BoxVolumeNode.cs index 92850857b..a2265e3bf 100644 --- a/Source/Editor/SceneGraph/Actors/BoxVolumeNode.cs +++ b/Source/Editor/SceneGraph/Actors/BoxVolumeNode.cs @@ -169,12 +169,8 @@ namespace FlaxEditor.SceneGraph.Actors : base(actor) { var id = ID; - var bytes = id.ToByteArray(); for (int i = 0; i < 6; i++) - { - bytes[0] += 1; - AddChildNode(new SideLinkNode(this, new Guid(bytes), i)); - } + AddChildNode(new SideLinkNode(this, GetSubID(id, i), i)); } /// diff --git a/Source/Editor/SceneGraph/Actors/FoliageNode.cs b/Source/Editor/SceneGraph/Actors/FoliageNode.cs index 50756170a..9e24d5b66 100644 --- a/Source/Editor/SceneGraph/Actors/FoliageNode.cs +++ b/Source/Editor/SceneGraph/Actors/FoliageNode.cs @@ -10,21 +10,68 @@ namespace FlaxEditor.SceneGraph.Actors [HideInEditor] public sealed class FoliageNode : ActorNode { - private FoliageInstance instance; - /// - /// The selected instance index - /// - public int SelectedInstanceIndex; - /// - public FoliageNode(Foliage actor, int selectedInstanceIndex = -1) + public FoliageNode(Actor actor) : base(actor) { - SelectedInstanceIndex = selectedInstanceIndex; - if (selectedInstanceIndex != -1) + } + } + + /// + /// Scene tree node for instance of . + /// + [HideInEditor] + public sealed class FoliageInstanceNode : SceneGraphNode + { + /// + /// The foliage actor that owns this instance. + /// + public Foliage Actor; + + /// + /// Index of the foliage instance. + /// + public int Index; + + /// + public FoliageInstanceNode(Foliage actor, int index) + : base(GetSubID(actor.ID, index)) + { + Actor = actor; + Index = index; + } + + /// + public override string Name => "Foliage Instance"; + + /// + public override SceneNode ParentScene + { + get { - instance = actor.GetInstance(selectedInstanceIndex); + var scene = Actor ? Actor.Scene : null; + return scene != null ? SceneGraphFactory.FindNode(scene.ID) as SceneNode : null; } } + + /// + public override Transform Transform + { + get => Actor.GetInstance(Index).Transform; + set => Actor.SetInstanceTransform(Index, ref value); + } + + /// + public override bool IsActive => Actor.IsActive; + + /// + public override bool IsActiveInHierarchy => Actor.IsActiveInHierarchy; + + /// + public override int OrderInParent + { + get => Index; + set { } + } } } diff --git a/Source/Editor/SceneGraph/Actors/NavLinkNode.cs b/Source/Editor/SceneGraph/Actors/NavLinkNode.cs index a0e90622f..4872c312a 100644 --- a/Source/Editor/SceneGraph/Actors/NavLinkNode.cs +++ b/Source/Editor/SceneGraph/Actors/NavLinkNode.cs @@ -77,11 +77,9 @@ namespace FlaxEditor.SceneGraph.Actors public NavLinkNode(Actor actor) : base(actor) { - var bytes = ID.ToByteArray(); - bytes[0] += 1; - AddChildNode(new LinkNode(this, new Guid(bytes), true)); - bytes[0] += 1; - AddChildNode(new LinkNode(this, new Guid(bytes), false)); + var id = ID; + AddChildNode(new LinkNode(this, GetSubID(id, 0), true)); + AddChildNode(new LinkNode(this, GetSubID(id, 1), false)); } /// diff --git a/Source/Editor/SceneGraph/SceneGraphNode.cs b/Source/Editor/SceneGraph/SceneGraphNode.cs index 4ca8034e1..a8a26a1b3 100644 --- a/Source/Editor/SceneGraph/SceneGraphNode.cs +++ b/Source/Editor/SceneGraph/SceneGraphNode.cs @@ -13,7 +13,6 @@ using FlaxEditor.Modules; using FlaxEditor.SceneGraph.Actors; using FlaxEditor.Windows; using FlaxEngine; -using System.Runtime.CompilerServices; namespace FlaxEditor.SceneGraph { @@ -147,7 +146,6 @@ namespace FlaxEditor.SceneGraph { if (ChildNodes.Contains(node)) return true; - return ChildNodes.Any(x => x.ContainsInHierarchy(node)); } @@ -219,20 +217,9 @@ namespace FlaxEditor.SceneGraph public FlagTypes Flags; /// - /// The exclude list actors specyfaied in + /// The list of objects to exclude from tracing against. Null if unused. /// - 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; + public List ExcludeObjects; /// /// Initializes a new instance of the struct. @@ -295,18 +282,16 @@ namespace FlaxEditor.SceneGraph normal = Vector3.Up; return null; } + + // Check itself SceneGraphNode minTarget = null; Real minDistance = Real.MaxValue; Vector3 minDistanceNormal = Vector3.Up; - if (Mask(ref ray)) + if (RayMask(ref ray) && RayCastSelf(ref ray, out distance, out normal)) { - // Check itself - if (RayCastSelf(ref ray, out distance, out normal)) - { - minTarget = this; - minDistance = distance; - minDistanceNormal = normal; - } + minTarget = this; + minDistance = distance; + minDistanceNormal = normal; } // Check all children @@ -320,36 +305,27 @@ 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) + + private bool RayMask(ref RayCastData ray) { - //filter actors - for (int j = 0; j < ray.Exclude.Count; j++) + if (ray.ExcludeObjects != null) { - if ((EditableObject is Actor a) && a == ray.Exclude[j]) + for (int j = 0; j < ray.ExcludeObjects.Count; 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; + if (ray.ExcludeObjects[j] == EditableObject) + { + // Remove form exclude because it is passed by ref and function is recursive it will slowly shrink the list until nothing is left as a micro optimization + ray.ExcludeObjects.RemoveAt(j); + if (ray.ExcludeObjects.Count == 0) + ray.ExcludeObjects = null; + return false; + } } } return true; @@ -493,5 +469,20 @@ namespace FlaxEditor.SceneGraph protected virtual void OnParentChanged() { } + + /// + /// Randomizes the owner node identifier. + /// + /// The owner node ID. + /// The sub-object index. + /// The sub-object ID. + protected static unsafe Guid GetSubID(Guid ownerId, int index) + { + var id = ownerId; + var idPtr = (FlaxEngine.Json.JsonSerializer.GuidInterop*)&id; + idPtr->B ^= (uint)(index * 387); + idPtr->D += (uint)(index + 1); + return id; + } } } diff --git a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs index 1ba8ef445..0955213d6 100644 --- a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs +++ b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs @@ -78,7 +78,20 @@ namespace FlaxEditor.Tools.Foliage var instanceIndex = GizmoMode.SelectedInstanceIndex; if (instanceIndex < 0 || instanceIndex >= foliage.InstancesCount) throw new InvalidOperationException("No foliage instance selected."); - return new FoliageNode(foliage, instanceIndex); + return new FoliageInstanceNode(foliage, instanceIndex); + } + + /// + protected override Transform GetSelectedTransform(int index) + { + var foliage = GizmoMode.SelectedFoliage; + if (!foliage) + throw new InvalidOperationException("No foliage selected."); + 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); } /// diff --git a/Source/Editor/Viewport/EditorGizmoViewport.cs b/Source/Editor/Viewport/EditorGizmoViewport.cs index fe579e7e5..89f8e82ef 100644 --- a/Source/Editor/Viewport/EditorGizmoViewport.cs +++ b/Source/Editor/Viewport/EditorGizmoViewport.cs @@ -68,6 +68,9 @@ namespace FlaxEditor.Viewport /// public bool SnapToGround => Editor.Instance.Options.Options.Input.SnapToGround.Process(Root); + /// + public bool SnapToVertex => Editor.Instance.Options.Options.Input.SnapToVertex.Process(Root); + /// public Float2 MouseDelta => _mouseDelta * 1000; diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 6c1509de8..8fb671017 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -337,6 +337,9 @@ namespace FlaxEditor.Viewport /// public bool SnapToGround => false; + /// + public bool SnapToVertex => Editor.Instance.Options.Options.Input.SnapToVertex.Process(Root); + /// public Float2 MouseDelta => _mouseDelta * 1000;