207 lines
8.0 KiB
C#
207 lines
8.0 KiB
C#
#if UNITY_EDITOR
|
|
|
|
using System.Collections;
|
|
using Unity.EditorCoroutines.Editor;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace SmoothSceneCamera.Editor
|
|
{
|
|
[InitializeOnLoad]
|
|
public class SmoothSceneCamera
|
|
{
|
|
#region Preferences
|
|
|
|
private const string UseSmoothZoomKey = "NnUtils_SmoothSceneCamera_SmoothZoom";
|
|
private static bool UseSmoothZoom
|
|
{
|
|
get => EditorPrefs.GetBool(UseSmoothZoomKey, true);
|
|
set => EditorPrefs.SetBool(UseSmoothZoomKey, value);
|
|
}
|
|
|
|
private const string ZoomAmountKey = "NnUtils_SmoothSceneCamera_ZoomAmount";
|
|
private static float ZoomAmount
|
|
{
|
|
get => EditorPrefs.GetFloat(ZoomAmountKey, 0.05f);
|
|
set => EditorPrefs.SetFloat(ZoomAmountKey, value);
|
|
}
|
|
|
|
private const string ZoomDistancePowerKey = "NnUtils_SmoothSceneCamera_ZoomDistancePower";
|
|
private static float ZoomDistancePower
|
|
{
|
|
get => EditorPrefs.GetFloat(ZoomDistancePowerKey, 1);
|
|
set => EditorPrefs.SetFloat(ZoomDistancePowerKey, value);
|
|
}
|
|
|
|
private const string ZoomDurationKey = "NnUtils_SmoothSceneCamera_ZoomDuration";
|
|
private static float ZoomDuration
|
|
{
|
|
get => EditorPrefs.GetFloat(ZoomDurationKey, 0.75f);
|
|
set => EditorPrefs.SetFloat(ZoomDurationKey, value);
|
|
}
|
|
|
|
private const string ZoomEasingKey = "NnUtils_SmoothSceneCamera_ZoomEasing";
|
|
private static Easings.Type ZoomEasing
|
|
{
|
|
get => (Easings.Type)EditorPrefs.GetInt(ZoomEasingKey, (int)Easings.Type.ExpoOut);
|
|
set => EditorPrefs.SetInt(ZoomEasingKey, (int)value);
|
|
}
|
|
|
|
private const string NearZoomLimitKey = "NnUtils_SmoothSceneCamera_NearZoomLimit";
|
|
private static float NearZoomLimit
|
|
{
|
|
get => EditorPrefs.GetFloat(NearZoomLimitKey, 0.0001f);
|
|
set => EditorPrefs.SetFloat(NearZoomLimitKey, value);
|
|
}
|
|
|
|
[SettingsProvider]
|
|
public static SettingsProvider CreateMyPreferencesProvider()
|
|
{
|
|
var provider =
|
|
new SettingsProvider("NnUtils/Smooth Scene Camera", SettingsScope.User)
|
|
{
|
|
label = "Smooth Scene Camera",
|
|
guiHandler = _ =>
|
|
{
|
|
var originalIndent = EditorGUI.indentLevel;
|
|
EditorGUI.indentLevel = 1;
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
EditorGUILayout.LabelField("Zoom", EditorStyles.boldLabel);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
var useSmoothZoom = EditorGUILayout.Toggle(
|
|
new GUIContent("Smooth Zoom",
|
|
"Toggles the smooth zoom option"),
|
|
UseSmoothZoom);
|
|
var zoomAmount = EditorGUILayout.FloatField(
|
|
new GUIContent("Zoom Amount",
|
|
"Amount of zoom per scroll step"),
|
|
ZoomAmount);
|
|
var zoomDistancePower = EditorGUILayout.FloatField(
|
|
new GUIContent("Zoom Distance Power",
|
|
"Exponent that the distance multiplier is raised to"),
|
|
ZoomDistancePower);
|
|
var zoomDuration = EditorGUILayout.FloatField(
|
|
new GUIContent("Zoom Duration",
|
|
"Duration of the zoom animation in seconds"),
|
|
ZoomDuration);
|
|
var zoomEasing = (Easings.Type)EditorGUILayout.EnumPopup(
|
|
new GUIContent("Zoom Easing",
|
|
"Easing applied to the zoom motion"),
|
|
ZoomEasing);
|
|
var nearZoomLimit = EditorGUILayout.FloatField(
|
|
new GUIContent("Near Zoom Limit",
|
|
"Minimum distance to the zoom pivot"),
|
|
NearZoomLimit);
|
|
|
|
if (!EditorGUI.EndChangeCheck()) return;
|
|
EditorGUI.indentLevel = originalIndent;
|
|
|
|
UseSmoothZoom = useSmoothZoom;
|
|
ZoomAmount = zoomAmount;
|
|
ZoomDistancePower = zoomDistancePower;
|
|
ZoomDuration = zoomDuration;
|
|
ZoomEasing = zoomEasing;
|
|
NearZoomLimit = nearZoomLimit;
|
|
}
|
|
};
|
|
|
|
return provider;
|
|
}
|
|
|
|
#endregion
|
|
|
|
private static float _lastFrameTime;
|
|
private static float _sizeDelta;
|
|
private static bool _rmbPressed;
|
|
private static bool _mmbPressed;
|
|
|
|
static SmoothSceneCamera() => SceneView.duringSceneGui += OnSceneGUI;
|
|
|
|
private static void OnSceneGUI(SceneView sceneView)
|
|
{
|
|
if (!UseSmoothZoom) return;
|
|
|
|
var e = Event.current;
|
|
if (e.type is EventType.MouseDown or EventType.MouseUp)
|
|
{
|
|
var isDown = e.type == EventType.MouseDown;
|
|
if (e.button == 1) _rmbPressed = isDown;
|
|
else if (e.button == 2) _mmbPressed = isDown;
|
|
}
|
|
|
|
if (e.type == EventType.ScrollWheel &&
|
|
!_rmbPressed && !_mmbPressed &&
|
|
e.modifiers == EventModifiers.None)
|
|
{
|
|
Zoom(e.delta.y);
|
|
e.Use();
|
|
}
|
|
}
|
|
|
|
private static void Zoom(float dir)
|
|
{
|
|
var sceneView = SceneView.lastActiveSceneView;
|
|
if (!sceneView) return;
|
|
|
|
// Reset size delta if its sign is opposite of current dir
|
|
if (!Mathf.Approximately(Mathf.Sign(dir), Mathf.Sign(_sizeDelta))) _sizeDelta = 0;
|
|
|
|
var startSize = sceneView.size;
|
|
var prevTargetSize = startSize + _sizeDelta;
|
|
var targetSize = prevTargetSize +
|
|
dir * ZoomAmount *
|
|
Mathf.Pow(prevTargetSize, ZoomDistancePower);
|
|
|
|
// Clamp the target size and calculate size delta
|
|
var startSign = Mathf.Sign(startSize);
|
|
targetSize = Mathf.Clamp(targetSize,
|
|
startSign * NearZoomLimit,
|
|
startSign * Mathf.Infinity);
|
|
_sizeDelta = targetSize - startSize;
|
|
|
|
if (_zoomRoutine != null) EditorCoroutineUtility.StopCoroutine(_zoomRoutine);
|
|
_zoomRoutine = EditorCoroutineUtility.StartCoroutineOwnerless(
|
|
ZoomRoutine(sceneView, startSize, targetSize));
|
|
}
|
|
|
|
private static EditorCoroutine _zoomRoutine;
|
|
|
|
private static IEnumerator ZoomRoutine(
|
|
SceneView sceneView, float startSize, float targetSize)
|
|
{
|
|
_lastFrameTime = (float)EditorApplication.timeSinceStartup;
|
|
var startSizeDelta = _sizeDelta;
|
|
|
|
float lerpPos = 0;
|
|
while (lerpPos < 1)
|
|
{
|
|
var deltaTime = (float)(EditorApplication.timeSinceStartup - _lastFrameTime);
|
|
lerpPos += deltaTime / ZoomDuration;
|
|
lerpPos = Mathf.Clamp01(lerpPos);
|
|
var t = Easings.Ease(lerpPos, ZoomEasing);
|
|
|
|
UpdateCameraDistance(sceneView, startSize, targetSize, t);
|
|
_sizeDelta = Mathf.LerpUnclamped(startSizeDelta, 0, t);
|
|
|
|
_lastFrameTime = (float)EditorApplication.timeSinceStartup;
|
|
yield return null;
|
|
}
|
|
|
|
_zoomRoutine = null;
|
|
}
|
|
|
|
private static void UpdateCameraDistance(SceneView sceneView,
|
|
float startPos, float targetPos, float t)
|
|
=> sceneView.LookAt(sceneView.pivot, sceneView.rotation,
|
|
Mathf.LerpUnclamped(startPos, targetPos, t),
|
|
sceneView.camera.orthographic, true);
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|