Cleanup and improve #2045
This commit is contained in:
@@ -51,6 +51,11 @@ namespace FlaxEditor.Gizmo
|
||||
/// </summary>
|
||||
bool SnapToGround { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to use vertex snapping (check if user pressed the given input key to call action).
|
||||
/// </summary>
|
||||
bool SnapToVertex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view forward direction.
|
||||
/// </summary>
|
||||
|
||||
@@ -274,6 +274,12 @@ namespace FlaxEditor.Gizmo
|
||||
return _selectionParents[index];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Transform GetSelectedTransform(int index)
|
||||
{
|
||||
return _selectionParents[index].Transform;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void GetSelectedObjectsBounds(out BoundingBox bounds, out bool navigationDirty)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -32,17 +32,17 @@ namespace FlaxEditor.Gizmo
|
||||
/// <summary>
|
||||
/// The XY plane.
|
||||
/// </summary>
|
||||
XY = X|Y,
|
||||
XY = X | Y,
|
||||
|
||||
/// <summary>
|
||||
/// The ZX plane.
|
||||
/// </summary>
|
||||
ZX = Z|X,
|
||||
ZX = Z | X,
|
||||
|
||||
/// <summary>
|
||||
/// The YZ plane.
|
||||
/// </summary>
|
||||
YZ = Y|Z,
|
||||
YZ = Y | Z,
|
||||
|
||||
/// <summary>
|
||||
/// The center point.
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the gizmo position.
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
/// <inheritdoc />
|
||||
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<Actor>() {},
|
||||
Scan = new List<Type>() { 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// zeros the <see cref="Vector3"/> <paramref name="v"/> component using the <see cref="Axis"/> <paramref name="lockAxis"/>
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this tool can transform objects.
|
||||
/// </summary>
|
||||
@@ -722,11 +694,19 @@ namespace FlaxEditor.Gizmo
|
||||
/// </summary>
|
||||
protected abstract int SelectionCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected object.
|
||||
/// </summary>
|
||||
/// <param name="index">The selected object index.</param>
|
||||
/// <returns>The selected object (eg. actor node).</returns>
|
||||
protected abstract SceneGraphNode GetSelectedObject(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected object transformation.
|
||||
/// </summary>
|
||||
/// <param name="index">The selected object index.</param>
|
||||
protected abstract SceneGraphNode GetSelectedObject(int index);
|
||||
/// <returns>The transformation of the selected object.</returns>
|
||||
protected abstract Transform GetSelectedTransform(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected objects bounding box (contains the whole selection).
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -10,21 +10,68 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
[HideInEditor]
|
||||
public sealed class FoliageNode : ActorNode
|
||||
{
|
||||
private FoliageInstance instance;
|
||||
/// <summary>
|
||||
/// The selected instance index
|
||||
/// </summary>
|
||||
public int SelectedInstanceIndex;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FoliageNode(Foliage actor, int selectedInstanceIndex = -1)
|
||||
public FoliageNode(Actor actor)
|
||||
: base(actor)
|
||||
{
|
||||
SelectedInstanceIndex = selectedInstanceIndex;
|
||||
if (selectedInstanceIndex != -1)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scene tree node for instance of <see cref="Foliage"/>.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public sealed class FoliageInstanceNode : SceneGraphNode
|
||||
{
|
||||
/// <summary>
|
||||
/// The foliage actor that owns this instance.
|
||||
/// </summary>
|
||||
public Foliage Actor;
|
||||
|
||||
/// <summary>
|
||||
/// Index of the foliage instance.
|
||||
/// </summary>
|
||||
public int Index;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FoliageInstanceNode(Foliage actor, int index)
|
||||
: base(GetSubID(actor.ID, index))
|
||||
{
|
||||
Actor = actor;
|
||||
Index = index;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Foliage Instance";
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Transform Transform
|
||||
{
|
||||
get => Actor.GetInstance(Index).Transform;
|
||||
set => Actor.SetInstanceTransform(Index, ref value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsActive => Actor.IsActive;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsActiveInHierarchy => Actor.IsActiveInHierarchy;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int OrderInParent
|
||||
{
|
||||
get => Index;
|
||||
set { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// The exclude list actors specyfaied in <see cref="Exclude"/>
|
||||
/// The list of objects to exclude from tracing against. Null if unused.
|
||||
/// </summary>
|
||||
public List<Actor> Exclude = new List<Actor>();
|
||||
|
||||
/// <summary>
|
||||
/// The scan for types
|
||||
/// </summary>
|
||||
public List<Type> Scan = new List<Type>();
|
||||
|
||||
/// <summary>
|
||||
/// if this is true it will include the types specyfaied in <see cref="Scan"/>
|
||||
/// otherwise it will include all types excluding types specyfaied in <see cref="Scan"/>
|
||||
/// </summary>
|
||||
public bool ExcludeScan;
|
||||
public List<object> ExcludeObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RayCastData"/> 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;
|
||||
}
|
||||
/// <summary>
|
||||
/// Masks the objects base of <see cref="RayCastData.Exclude"/> and <see cref="RayCastData.Scan"/>.
|
||||
/// </summary>
|
||||
/// <param name="ray">The ray.</param>
|
||||
/// <returns>true if can pass through mask</returns>
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Randomizes the owner node identifier.
|
||||
/// </summary>
|
||||
/// <param name="ownerId">The owner node ID.</param>
|
||||
/// <param name="index">The sub-object index.</param>
|
||||
/// <returns>The sub-object ID.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -68,6 +68,9 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public bool SnapToGround => Editor.Instance.Options.Options.Input.SnapToGround.Process(Root);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SnapToVertex => Editor.Instance.Options.Options.Input.SnapToVertex.Process(Root);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Float2 MouseDelta => _mouseDelta * 1000;
|
||||
|
||||
|
||||
@@ -337,6 +337,9 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public bool SnapToGround => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SnapToVertex => Editor.Instance.Options.Options.Input.SnapToVertex.Process(Root);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Float2 MouseDelta => _mouseDelta * 1000;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user