added MouseWorldPositionWindow for displaying world position under cursor in Scene View
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled

This commit is contained in:
Данил Ярош 2025-12-24 09:05:58 +03:00
parent 384a8fad82
commit 2639239085
2 changed files with 134 additions and 0 deletions

View File

@ -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<MouseWorldPositionWindow>("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

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: eedb77236baea004994341514803f9e7