RoboticArms/Library/PackageCache/com.unity.splines@d3e1e500c9a0/Editor/Controls/DirectManipulation.cs
2025-11-17 15:16:36 +07:00

201 lines
8.5 KiB
C#

using Unity.Mathematics;
using UnityEditor.SettingsManagement;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Splines
{
static class DirectManipulation
{
[UserSetting("Tweak Mode", "Plane Color")]
static readonly Pref<Color> s_GuidePlaneColor = new Pref<Color>("Handles.DirectManipulation.PlaneColor", new Color(1f, 1f, 1f, 5f/255f));
[UserSetting("Tweak Mode", "Snap to Guide Enabled")]
static readonly Pref<bool> s_SnapToGuide = new Pref<bool>("Handles.DirectManipulation.SnapToGuide", true);
[UserSetting("Tweak Mode", "Snap to Guide Distance")]
static readonly Pref<float> s_SnapToGuideDistance = new Pref<float>("Handles.DirectManipulation.SnapToGuideDistance", 7f);
static readonly Vector3[] s_VertexBuffer = new Vector3[4];
public static bool IsDragging => s_IsDragging;
static readonly Vector3 k_GuidePlaneZTestOffset = new Vector3(0.001f, 0.001f, 0.001f);
static Vector3 s_InitialPosition;
static Quaternion s_InitialRotation;
static Vector2 s_InitialMousePosition;
static bool s_IsDragging;
#if UNITY_2022_2_OR_NEWER
static bool IncrementalSnapActive => EditorSnapSettings.incrementalSnapActive;
#else
static bool IncrementalSnapActive => false;
#endif
const float k_HandleColorAlphaFactor = 0.3f;
static bool ShouldMoveOnNormal(int controlId) => GUIUtility.hotControl == controlId && Event.current.alt;
public static void BeginDrag(Vector3 position, Quaternion rotation)
{
s_InitialPosition = position;
s_InitialRotation = rotation;
s_InitialMousePosition = Event.current.mousePosition;
}
public static Vector3 UpdateDrag(int controlId)
{
var position = ShouldMoveOnNormal(controlId)
? MoveOnNormal(Event.current.mousePosition, s_InitialPosition, s_InitialRotation)
: MoveOnPlane(Event.current.mousePosition, s_InitialPosition, s_InitialRotation, IncrementalSnapActive);
s_IsDragging = true;
return position;
}
public static void EndDrag()
{
s_IsDragging = false;
}
public static void DrawHandles(int controlId, Vector3 position)
{
if (GUIUtility.hotControl != controlId || !s_IsDragging)
return;
EditorGUIUtility.AddCursorRect(new Rect(0, 0, 100000, 10000), MouseCursor.MoveArrow);
if (ShouldMoveOnNormal(controlId))
{
var yDir = s_InitialRotation * Vector3.up;
DrawGuideAxis(s_InitialPosition, yDir, Handles.yAxisColor);
}
else
{
var zDir = s_InitialRotation * Vector3.forward;
var xDir = s_InitialRotation * Vector3.right;
DrawGuidePlane(s_InitialPosition, xDir, zDir, position);
DrawGuideDottedLine(s_InitialPosition, zDir, position);
DrawGuideDottedLine(s_InitialPosition, xDir, position);
DrawGuideAxis(s_InitialPosition, zDir, Handles.zAxisColor);
DrawGuideAxis(s_InitialPosition, xDir, Handles.xAxisColor);
}
}
static (Vector3 projection, float distance) GetSnapToGuideData(Vector3 current, Vector3 origin, Vector3 axis)
{
var projection = Vector3.Project(current - origin, axis);
var screenPos = HandleUtility.WorldToGUIPoint(origin + projection);
var distance = Vector2.Distance(screenPos, Event.current.mousePosition);
return (projection, distance);
}
static Vector3 MoveOnPlane(Vector2 mousePosition, Vector3 origin, Quaternion rotation, bool snapping)
{
var ray = HandleUtility.GUIPointToWorldRay(mousePosition);
var manipPlane = new Plane(rotation * Vector3.up, origin);
var position = manipPlane.Raycast(ray, out float distance)
? ray.origin + ray.direction * distance
: origin;
var dir = position - origin;
var forward = GetSnapToGuideData(position, origin, rotation * Vector3.forward);
var right = GetSnapToGuideData(position, origin, rotation * Vector3.right);
if (!snapping && s_SnapToGuide)
{
if (forward.distance < s_SnapToGuideDistance || right.distance < s_SnapToGuideDistance)
{
var snapToForward = forward.distance < right.distance;
var axis = (snapToForward ? forward : right).projection;
return origin + axis;
}
}
if(Mathf.Approximately(dir.magnitude, 0f))
dir = Vector3.forward;
var translation = Handles.SnapValue(Quaternion.Inverse(rotation) * dir, new Vector3(EditorSnapSettings.move.x, 0, EditorSnapSettings.move.z));
return origin + rotation * translation;
}
static Vector3 MoveOnNormal(Vector2 mousePosition, Vector3 origin, Quaternion rotation)
{
var upAxis = rotation * Vector3.up;
var translation = upAxis * Handles.SnapValue(HandleUtility.CalcLineTranslation(s_InitialMousePosition, mousePosition, origin, upAxis), EditorSnapSettings.move.y);
return origin + translation;
}
static void DrawGuideAxis(Vector3 origin, Vector3 axis, Color color)
{
var start = origin - axis.normalized * 10000f;
var end = origin + axis.normalized * 10000f;
using (new ZTestScope(CompareFunction.Less))
using (new Handles.DrawingScope(color))
{
Handles.DrawLine(origin, start, 0f);
Handles.DrawLine(origin, end, 0f);
}
color = new Color(color.r, color.g, color.b, color.a * k_HandleColorAlphaFactor);
using (new ZTestScope(CompareFunction.Greater))
using (new Handles.DrawingScope(color))
{
Handles.DrawLine(origin, start, 0f);
Handles.DrawLine(origin, end, 0f);
}
}
static void DrawGuidePlane(Vector3 origin, Vector3 axisX, Vector3 axisZ, Vector3 position)
{
var xAxisProjection = Vector3.Project(position - origin, axisX);
var zAxisProjection = Vector3.Project(position - origin, axisZ);
var cross = math.cross(xAxisProjection, zAxisProjection);
var normal = math.normalizesafe(cross);
var scaledOffset = k_GuidePlaneZTestOffset * HandleUtility.GetHandleSize(origin);
var calculatedOffset = new Vector3(scaledOffset.x * normal.x, scaledOffset.y * normal.y, scaledOffset.z * normal.z);
position += calculatedOffset;
origin += calculatedOffset;
s_VertexBuffer[0] = origin;
s_VertexBuffer[1] = origin + Vector3.Project(position - origin, axisX);
s_VertexBuffer[2] = position;
s_VertexBuffer[3] = origin + Vector3.Project(position - origin, axisZ);
DrawGuidePlane(Matrix4x4.identity);
}
static void DrawGuidePlane(Matrix4x4 matrix)
{
var color = s_GuidePlaneColor.value;
using (new ZTestScope(CompareFunction.Less))
using (new Handles.DrawingScope(matrix))
Handles.DrawSolidRectangleWithOutline(s_VertexBuffer, color, Color.clear);
color = new Color(s_GuidePlaneColor.value.r, s_GuidePlaneColor.value.g, s_GuidePlaneColor.value.b,
s_GuidePlaneColor.value.a * k_HandleColorAlphaFactor);
using (new ZTestScope(CompareFunction.Greater))
using (new Handles.DrawingScope(matrix))
Handles.DrawSolidRectangleWithOutline(s_VertexBuffer, color, Color.clear);
}
static void DrawGuideDottedLine(Vector3 origin, Vector3 axis, Vector3 position)
{
using (new ZTestScope(CompareFunction.Less))
Handles.DrawDottedLine(origin + Vector3.Project(position - origin, axis), position, 3f);
var color = new Color(Handles.color.r, Handles.color.g, Handles.color.b, Handles.color.a * k_HandleColorAlphaFactor);
using (new ZTestScope(CompareFunction.Greater))
using (new Handles.DrawingScope(color))
Handles.DrawDottedLine(origin + Vector3.Project(position - origin, axis), position, 3f);
}
}
}