internal static Vector3[] Do(int id, Axis axis, Vector3[] points, Vector3 handleOrigin, Vector3 handleDirection, Vector3 slideDirection, float snappingStep = 0, float handleSize = 0, SceneHandles.CapFunction capFunction = null, bool selectLockingAxisOnClick = false) { if (snappingStep == 0) { snappingStep = Snapping.MoveSnappingSteps[(int)axis]; } if (handleSize == 0) { handleSize = UnityEditor.HandleUtility.GetHandleSize(handleOrigin) * 0.05f; } if (handleDirection.sqrMagnitude == 0) { return(points); } var evt = Event.current; var type = evt.GetTypeForControl(id); switch (type) { case EventType.MouseDown: { if (SceneHandles.InCameraOrbitMode) { break; } if (GUIUtility.hotControl != 0) { break; } if ((UnityEditor.HandleUtility.nearestControl != id || evt.button != 0) && (GUIUtility.keyboardControl != id || evt.button != 2)) { break; } GUIUtility.hotControl = GUIUtility.keyboardControl = id; evt.Use(); EditorGUIUtility.SetWantsMouseJumping(1); s_CurrentMousePosition = evt.mousePosition; s_StartPoints = points.ToArray(); var handleMatrix = SceneHandles.matrix; s_Snapping1D.Initialize(s_CurrentMousePosition, handleMatrix.MultiplyPoint(handleOrigin), handleMatrix.MultiplyVector(slideDirection), snappingStep, axis); s_Snapping1D.CalculateExtents(SceneHandles.inverseMatrix, s_StartPoints); s_MovedMouse = false; break; } case EventType.MouseDrag: { if (GUIUtility.hotControl != id) { break; } s_MovedMouse = true; if (SceneHandles.disabled || Snapping.IsAxisLocked(axis)) { break; } s_CurrentMousePosition += evt.delta; evt.Use(); if (!s_Snapping1D.Move(s_CurrentMousePosition)) { break; } var handleInverseMatrix = SceneHandles.inverseMatrix; var pointDelta = handleInverseMatrix.MultiplyVector(s_Snapping1D.WorldSnappedOffset); if (s_StartPoints != null) { points = new Vector3[points.Length]; // if we don't, it's hard to do Undo properly for (int i = 0; i < points.Length; i++) { points[i] = SnappingUtility.Quantize(s_StartPoints[i] + pointDelta); } } //SceneView.RepaintAll(); GUI.changed = true; break; } case EventType.MouseUp: { if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; //Grid.currentGrid = s_PrevGrid; s_StartPoints = null; evt.Use(); EditorGUIUtility.SetWantsMouseJumping(0); if (!s_MovedMouse && selectLockingAxisOnClick) { switch (axis) { case Axis.X: { Snapping.ActiveAxes = Axes.X; break; } case Axis.Y: { Snapping.ActiveAxes = Axes.Y; break; } case Axis.Z: { Snapping.ActiveAxes = Axes.Z; break; } } } SceneView.RepaintAll(); } break; } #if UNITY_2020_1_OR_NEWER case EventType.MouseMove: { if (SceneHandles.InCameraOrbitMode) { break; } var position = handleOrigin; var rotation = Quaternion.LookRotation(handleDirection); if (handleSize > 0) { if (capFunction != null) { capFunction(id, position, rotation, handleSize, type); } } int currentFocusControl = SceneHandleUtility.focusControl; if ((currentFocusControl == id && s_PrevFocusControl != id) || (currentFocusControl != id && s_PrevFocusControl == id)) { s_PrevFocusControl = currentFocusControl; SceneView.RepaintAll(); } break; } #endif case EventType.Layout: { if (SceneHandles.InCameraOrbitMode) { break; } var position = handleOrigin; var rotation = Quaternion.LookRotation(handleDirection); if (handleSize > 0) { if (capFunction != null) { capFunction(id, position, rotation, handleSize, type); } else { UnityEditor.HandleUtility.AddControl(id, UnityEditor.HandleUtility.DistanceToCircle(position, handleSize * .2f)); } } int currentFocusControl = SceneHandleUtility.focusControl; if ((currentFocusControl == id && s_PrevFocusControl != id) || (currentFocusControl != id && s_PrevFocusControl == id)) { s_PrevFocusControl = currentFocusControl; SceneView.RepaintAll(); } break; } case EventType.Repaint: { if (axis != Axis.None) { if (GUIUtility.hotControl == id) { var selectedColor = SceneHandles.StateColor(SceneHandles.MultiplyTransparency(SceneHandles.selectedColor, 0.5f)); using (new SceneHandles.DrawingScope(selectedColor)) HandleRendering.RenderSnapping1D(s_Snapping1D.Min, s_Snapping1D.Max, s_Snapping1D.WorldSnappedPosition, s_Snapping1D.SlideDirection, s_Snapping1D.SnapResult, axis); } } if (capFunction == null) { break; } var position = handleOrigin; var rotation = Quaternion.LookRotation(handleDirection); var color = SceneHandles.StateColor(SceneHandles.color, isSelected: (id == s_PrevFocusControl)); using (new SceneHandles.DrawingScope(color)) { capFunction(id, position, rotation, handleSize, EventType.Repaint); } break; } } return(points); }
public static float Radius3DHandle(Quaternion rotation, Vector3 position, float radius, float minRadius = 0, float maxRadius = float.PositiveInfinity) { minRadius = Mathf.Abs(minRadius); maxRadius = Mathf.Abs(maxRadius); if (maxRadius < minRadius) { maxRadius = minRadius; } const float kEpsilon = 0.000001F; var camera = Camera.current; var cameraLocalPos = SceneHandles.inverseMatrix.MultiplyPoint(camera.transform.position); var cameraLocalForward = SceneHandles.inverseMatrix.MultiplyVector(camera.transform.forward); var isCameraInsideSphere = (cameraLocalPos - position).magnitude < radius; var isCameraOrthographic = camera.orthographic; var isStatic = (!Tools.hidden && EditorApplication.isPlaying && GameObjectUtility.ContainsStatic(Selection.gameObjects)); var prevDisabled = SceneHandles.disabled; var prevColor = SceneHandles.color; var forward = rotation * Vector3.forward; var up = rotation * Vector3.up; var right = rotation * Vector3.right; bool guiHasChanged = GUI.changed; GUI.changed = false; Vector3 positiveXDir = right; Vector3 negativeXDir = -right; Vector3 positiveYDir = up; Vector3 negativeYDir = -up; Vector3 positiveZDir = forward; Vector3 negativeZDir = -forward; Vector3 positiveXHandle = position + positiveXDir * radius; Vector3 negativeXHandle = position + negativeXDir * radius; Vector3 positiveYHandle = position + positiveYDir * radius; Vector3 negativeYHandle = position + negativeYDir * radius; Vector3 positiveZHandle = position + positiveZDir * radius; Vector3 negativeZHandle = position + negativeZDir * radius; bool positiveXBackfaced = false; bool negativeXBackfaced = false; bool positiveYBackfaced = false; bool negativeYBackfaced = false; bool positiveZBackfaced = false; bool negativeZBackfaced = false; if (!isCameraInsideSphere) { float cosV; cosV = isCameraOrthographic ? Vector3.Dot(positiveXDir, -cameraLocalForward) : Vector3.Dot(positiveXDir, (cameraLocalPos - positiveXHandle)); positiveXBackfaced = (cosV < -0.0001f); cosV = isCameraOrthographic ? Vector3.Dot(negativeXDir, -cameraLocalForward) : Vector3.Dot(negativeXDir, (cameraLocalPos - negativeXHandle)); negativeXBackfaced = (cosV < -0.0001f); cosV = isCameraOrthographic ? Vector3.Dot(positiveYDir, -cameraLocalForward) : Vector3.Dot(positiveYDir, (cameraLocalPos - positiveYHandle)); positiveYBackfaced = (cosV < -0.0001f); cosV = isCameraOrthographic ? Vector3.Dot(negativeYDir, -cameraLocalForward) : Vector3.Dot(negativeYDir, (cameraLocalPos - negativeYHandle)); negativeYBackfaced = (cosV < -0.0001f); cosV = isCameraOrthographic ? Vector3.Dot(positiveZDir, -cameraLocalForward) : Vector3.Dot(positiveZDir, (cameraLocalPos - positiveZHandle)); positiveZBackfaced = (cosV < -0.0001f); cosV = isCameraOrthographic ? Vector3.Dot(negativeZDir, -cameraLocalForward) : Vector3.Dot(negativeZDir, (cameraLocalPos - negativeZHandle)); negativeZBackfaced = (cosV < -0.0001f); } float positiveXSize = UnityEditor.HandleUtility.GetHandleSize(positiveXHandle) * 0.05f * (positiveXBackfaced ? backfaceSizeMultiplier : 1); float negativeXSize = UnityEditor.HandleUtility.GetHandleSize(negativeXHandle) * 0.05f * (negativeXBackfaced ? backfaceSizeMultiplier : 1); float positiveYSize = UnityEditor.HandleUtility.GetHandleSize(positiveYHandle) * 0.05f * (positiveYBackfaced ? backfaceSizeMultiplier : 1); float negativeYSize = UnityEditor.HandleUtility.GetHandleSize(negativeYHandle) * 0.05f * (negativeYBackfaced ? backfaceSizeMultiplier : 1); float positiveZSize = UnityEditor.HandleUtility.GetHandleSize(positiveZHandle) * 0.05f * (positiveZBackfaced ? backfaceSizeMultiplier : 1); float negativeZSize = UnityEditor.HandleUtility.GetHandleSize(negativeZHandle) * 0.05f * (negativeZBackfaced ? backfaceSizeMultiplier : 1); var isDisabled = isStatic || prevDisabled || Snapping.AxisLocking[0]; var color = SceneHandles.StateColor(prevColor, isDisabled, false); var backfacedColor = SceneHandles.MultiplyTransparency(color, SceneHandles.backfaceAlphaMultiplier); GUI.changed = false; SceneHandles.color = positiveXBackfaced ? backfacedColor : color; positiveXHandle = Slider2DHandle(positiveXHandle, Vector3.zero, forward, up, right, positiveXSize, OutlinedDotHandleCap); if (GUI.changed) { radius = Vector3.Dot(positiveXHandle - position, positiveXDir); guiHasChanged = true; } GUI.changed = false; SceneHandles.color = negativeXBackfaced ? backfacedColor : color; negativeXHandle = Slider2DHandle(negativeXHandle, Vector3.zero, forward, up, right, negativeXSize, OutlinedDotHandleCap); if (GUI.changed) { radius = Vector3.Dot(negativeXHandle - position, negativeXDir); guiHasChanged = true; } isDisabled = isStatic || prevDisabled || Snapping.AxisLocking[1]; color = SceneHandles.StateColor(prevColor, isDisabled, false); backfacedColor = SceneHandles.MultiplyTransparency(color, SceneHandles.backfaceAlphaMultiplier); GUI.changed = false; SceneHandles.color = positiveYBackfaced ? backfacedColor : color; positiveYHandle = Slider2DHandle(positiveYHandle, Vector3.zero, forward, up, right, positiveYSize, OutlinedDotHandleCap); if (GUI.changed) { radius = Vector3.Dot(positiveYHandle - position, positiveYDir); guiHasChanged = true; } GUI.changed = false; SceneHandles.color = negativeYBackfaced ? backfacedColor : color; negativeYHandle = Slider2DHandle(negativeYHandle, Vector3.zero, forward, up, right, negativeYSize, OutlinedDotHandleCap); if (GUI.changed) { radius = Vector3.Dot(negativeYHandle - position, negativeYDir); guiHasChanged = true; } isDisabled = isStatic || prevDisabled || Snapping.AxisLocking[2]; color = SceneHandles.StateColor(prevColor, isDisabled, false); backfacedColor = SceneHandles.MultiplyTransparency(color, SceneHandles.backfaceAlphaMultiplier); GUI.changed = false; SceneHandles.color = positiveZBackfaced ? backfacedColor : color; positiveZHandle = Slider2DHandle(positiveZHandle, Vector3.zero, up, forward, right, positiveZSize, OutlinedDotHandleCap); if (GUI.changed) { radius = Vector3.Dot(positiveZHandle - position, positiveZDir); guiHasChanged = true; } GUI.changed = false; SceneHandles.color = negativeZBackfaced ? backfacedColor : color; negativeZHandle = Slider2DHandle(negativeZHandle, Vector3.zero, up, forward, right, negativeZSize, OutlinedDotHandleCap); if (GUI.changed) { radius = Vector3.Dot(negativeZHandle - position, negativeZDir); guiHasChanged = true; } radius = Mathf.Max(minRadius, Mathf.Min(Mathf.Abs(radius), maxRadius)); GUI.changed |= guiHasChanged; if (radius > 0) { isDisabled = isStatic || prevDisabled || (Snapping.AxisLocking[0] && Snapping.AxisLocking[1]); color = SceneHandles.StateColor(prevColor, isDisabled, false); backfacedColor = SceneHandles.MultiplyTransparency(color, SceneHandles.backfaceAlphaMultiplier); var discOrientations = new Vector3[] { rotation *Vector3.right, rotation *Vector3.up, rotation *Vector3.forward }; var currentCamera = Camera.current; var cameraTransform = currentCamera.transform; if (currentCamera.orthographic) { var planeNormal = cameraTransform.forward; SceneHandles.DrawWireDisc(position, planeNormal, radius); planeNormal.Normalize(); for (int i = 0; i < 3; i++) { var discOrientation = discOrientations[i]; var discTangent = Vector3.Cross(discOrientation, planeNormal); // we may have view dir locked to one axis if (discTangent.sqrMagnitude > kEpsilon) { SceneHandles.color = color; SceneHandles.DrawWireArc(position, discOrientation, discTangent, 180, radius); SceneHandles.color = backfacedColor; SceneHandles.DrawWireArc(position, discOrientation, discTangent, -180, radius); } } } else { // Since the geometry is transformed by Handles.matrix during rendering, we transform the camera position // by the inverse matrix so that the two-shaded wireframe will have the proper orientation. var invMatrix = SceneHandles.inverseMatrix; var cameraCenter = cameraTransform.position; var cameraToCenter = position - invMatrix.MultiplyPoint(cameraCenter); // vector from camera to center var sqrDistCameraToCenter = cameraToCenter.sqrMagnitude; var sqrRadius = radius * radius; // squared radius var sqrOffset = sqrRadius * sqrRadius / sqrDistCameraToCenter; // squared distance from actual center to drawn disc center var insideAmount = sqrOffset / sqrRadius; if (insideAmount < 1) { if (Mathf.Abs(sqrDistCameraToCenter) < kEpsilon) { return(radius); } var horizonRadius = Mathf.Sqrt(sqrRadius - sqrOffset); var horizonCenter = position - sqrRadius * cameraToCenter / sqrDistCameraToCenter; SceneHandles.color = color; SceneHandles.DrawWireDisc(horizonCenter, cameraToCenter, horizonRadius); var planeNormal = cameraToCenter.normalized; for (int i = 0; i < 3; i++) { var discOrientation = discOrientations[i]; var angleBetweenDiscAndNormal = Mathf.Acos(Vector3.Dot(discOrientation, planeNormal)); angleBetweenDiscAndNormal = (Mathf.PI * 0.5f) - Mathf.Min(angleBetweenDiscAndNormal, Mathf.PI - angleBetweenDiscAndNormal); float f = Mathf.Tan(angleBetweenDiscAndNormal); float g = Mathf.Sqrt(sqrOffset + f * f * sqrOffset) / radius; if (g < 1) { var angleToHorizon = Mathf.Asin(g) * Mathf.Rad2Deg; var discTangent = Vector3.Cross(discOrientation, planeNormal); var vectorToPointOnHorizon = Quaternion.AngleAxis(angleToHorizon, discOrientation) * discTangent; var horizonArcLength = (90 - angleToHorizon) * 2.0f; SceneHandles.color = color; SceneHandles.DrawWireArc(position, discOrientation, vectorToPointOnHorizon, horizonArcLength, radius); SceneHandles.color = backfacedColor; SceneHandles.DrawWireArc(position, discOrientation, vectorToPointOnHorizon, horizonArcLength - 360, radius); } else { SceneHandles.color = backfacedColor; SceneHandles.DrawWireDisc(position, discOrientation, radius); } } } else { SceneHandles.color = backfacedColor; for (int i = 0; i < 3; i++) { var discOrientation = discOrientations[i]; SceneHandles.DrawWireDisc(position, discOrientation, radius); } } } } SceneHandles.disabled = prevDisabled; SceneHandles.color = prevColor; return(radius); }