From 2639239085c87b70e3de372a7e08626ce70d2bcb Mon Sep 17 00:00:00 2001 From: Danil Iarosh Date: Wed, 24 Dec 2025 09:05:58 +0300 Subject: [PATCH] added MouseWorldPositionWindow for displaying world position under cursor in Scene View --- .../Editor/MouseWorldPositionWindow.cs | 132 ++++++++++++++++++ .../Editor/MouseWorldPositionWindow.cs.meta | 2 + 2 files changed, 134 insertions(+) create mode 100644 Assets/Scripts/Editor/MouseWorldPositionWindow.cs create mode 100644 Assets/Scripts/Editor/MouseWorldPositionWindow.cs.meta diff --git a/Assets/Scripts/Editor/MouseWorldPositionWindow.cs b/Assets/Scripts/Editor/MouseWorldPositionWindow.cs new file mode 100644 index 0000000..a5b3e21 --- /dev/null +++ b/Assets/Scripts/Editor/MouseWorldPositionWindow.cs @@ -0,0 +1,132 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +public class MouseWorldPositionWindow : EditorWindow +{ + private enum PlaneMode { XY, XZ, YZ, CameraFacing } + + private PlaneMode planeMode = PlaneMode.XZ; + private float planeOffset = 0f; // смещение плоскости по нормали (Z для XY, Y для XZ, X для YZ) + private bool lockToSceneView = true; + private int decimals = 3; + + private Vector3 lastWorld; + private bool hasPoint; + + [MenuItem("Tools/Mouse World Position")] + public static void Open() + { + GetWindow("Mouse World Pos"); + } + + private void OnEnable() + { + SceneView.duringSceneGui += OnSceneGUI; + } + + private void OnDisable() + { + SceneView.duringSceneGui -= OnSceneGUI; + } + + private void OnGUI() + { + EditorGUILayout.LabelField("Source", EditorStyles.boldLabel); + lockToSceneView = EditorGUILayout.ToggleLeft("Use last active Scene View", lockToSceneView); + + EditorGUILayout.Space(6); + EditorGUILayout.LabelField("Projection", EditorStyles.boldLabel); + + planeMode = (PlaneMode)EditorGUILayout.EnumPopup("Plane", planeMode); + if (planeMode != PlaneMode.CameraFacing) + planeOffset = EditorGUILayout.FloatField("Plane Offset", planeOffset); + + decimals = EditorGUILayout.IntSlider("Decimals", decimals, 0, 6); + + EditorGUILayout.Space(10); + EditorGUILayout.LabelField("Result", EditorStyles.boldLabel); + + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.Toggle("Has Point", hasPoint); + EditorGUILayout.Vector3Field("World", lastWorld); + } + + using (new EditorGUI.DisabledScope(!hasPoint)) + { + if (GUILayout.Button("Copy (x,y,z)")) + { + EditorGUIUtility.systemCopyBuffer = FormatVec(lastWorld, decimals); + } + } + + EditorGUILayout.HelpBox( + "Move mouse in Scene View. The window shows world position under cursor.\n" + + "3D uses ray-plane intersection (choose plane). 2D обычно: XY @ Z=0.", + MessageType.Info); + } + + private void OnSceneGUI(SceneView sv) + { + if (!lockToSceneView && sv != SceneView.lastActiveSceneView) return; + + var e = Event.current; + if (e == null) return; + + // Берём позицию мыши только когда курсор над SceneView + if (e.type != EventType.MouseMove && e.type != EventType.MouseDrag && e.type != EventType.Repaint) + return; + + Ray ray = HandleUtility.GUIPointToWorldRay(e.mousePosition); + + hasPoint = TryGetPoint(ray, sv.camera, out lastWorld); + + // чтобы окно обновлялось живо + Repaint(); + } + + private bool TryGetPoint(Ray ray, Camera cam, out Vector3 world) + { + // Для CameraFacing: плоскость, перпендикулярная камере, проходящая через origin камеры + (forward * planeOffset) + Plane plane; + + switch (planeMode) + { + case PlaneMode.XY: + plane = new Plane(Vector3.forward, new Vector3(0f, 0f, planeOffset)); // Z = offset + break; + + case PlaneMode.XZ: + plane = new Plane(Vector3.up, new Vector3(0f, planeOffset, 0f)); // Y = offset + break; + + case PlaneMode.YZ: + plane = new Plane(Vector3.right, new Vector3(planeOffset, 0f, 0f)); // X = offset + break; + + case PlaneMode.CameraFacing: + default: + var normal = cam.transform.forward; + var point = cam.transform.position; // можно поменять на position + forward*dist если надо + plane = new Plane(normal, point); + break; + } + + if (plane.Raycast(ray, out float enter)) + { + world = ray.GetPoint(enter); + return true; + } + + world = default; + return false; + } + + private static string FormatVec(Vector3 v, int d) + { + string f = "F" + Mathf.Clamp(d, 0, 6); + return $"{v.x.ToString(f)}, {v.y.ToString(f)}, {v.z.ToString(f)}"; + } +} +#endif diff --git a/Assets/Scripts/Editor/MouseWorldPositionWindow.cs.meta b/Assets/Scripts/Editor/MouseWorldPositionWindow.cs.meta new file mode 100644 index 0000000..862dd2c --- /dev/null +++ b/Assets/Scripts/Editor/MouseWorldPositionWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: eedb77236baea004994341514803f9e7 \ No newline at end of file