#if UNITY_EDITOR using UnityEditor; using UnityEngine; public class MouseWorldPositionWindow : EditorWindow { private enum PlaneMode { XY, XZ, YZ, CameraFacing } // Множители для быстрого доступа: multipliers[d] = 10^d private static readonly float[] Multipliers = { 1f, 10f, 100f, 1000f, 10000f, 100000f, 1000000f }; private PlaneMode planeMode = PlaneMode.XZ; private float planeOffset; private bool lockToSceneView = true; private int decimals = 3; private Vector3 lastWorld; private Vector3 displayWorld; 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("Плоскость", planeMode); if (planeMode != PlaneMode.CameraFacing) planeOffset = EditorGUILayout.FloatField("Смещение плоскости", 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", displayWorld); } using (new EditorGUI.DisabledScope(!hasPoint)) { if (GUILayout.Button("Copy (x,y,z)")) { string f = "F" + decimals; EditorGUIUtility.systemCopyBuffer = $"{displayWorld.x.ToString(f)}, {displayWorld.y.ToString(f)}, {displayWorld.z.ToString(f)}"; } } } private void OnSceneGUI(SceneView sv) { if (!lockToSceneView && sv != SceneView.lastActiveSceneView) return; Event 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); // Вычисляем displayWorld один раз при изменении позиции if (hasPoint) { float mult = Multipliers[decimals]; displayWorld = new Vector3( Mathf.Ceil(lastWorld.x * mult) / mult, Mathf.Ceil(lastWorld.y * mult) / mult, Mathf.Ceil(lastWorld.z * mult) / mult ); } else { displayWorld = default; } 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: Vector3 normal = cam.transform.forward; Vector3 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; } } #endif