Just thought I’d share, could be useful to someone. If you select a GameObject with the script SceneMouseView, you will see the current mouse position (in world points, works for 2D only) in console for as long as it’s selected.
using UnityEngine;
public class SceneViewMouse : MonoBehaviour
{
}
in Editor folder:
using UnityEngine;
using System.Collections;
using UnityEditor;
[CustomEditor(typeof(SceneViewMouse))]
class SceneViewMouseEditor : Editor {
void OnSceneGUI() {
SceneViewMouse obj = (SceneViewMouse)target;
Vector3 mousepos = Event.current.mousePosition;
mousepos = SceneView.lastActiveSceneView.camera.ScreenToWorldPoint (mousepos);
mousepos.y = -mousepos.y;
Debug.Log("mousepos: " + mousepos);
if (Event.current.type == EventType.mouseDown) {
Debug.Log("click");
}
}
}
hey, to anyone using this: you need to correct the mouse y position if the scence view camere is moved, you’ll get offest results. just add mousepos.y+= UnityEditor.SceneView.currentDrawingSceneView.camera.transform.position.y * 2;
Here are the same scripts corrected to work both in 2D and 3D:
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(SceneViewMouse))]
class SceneViewMouseEditor : Editor {
void OnSceneGUI()
{
SceneViewMouse obj = (SceneViewMouse)target;
Camera cam = SceneView.lastActiveSceneView.camera;
Vector3 mousepos = Event.current.mousePosition;
mousepos.z = -cam.worldToCameraMatrix.MultiplyPoint(obj.transform.position).z;
mousepos.y = Screen.height - mousepos.y - 36.0f; // ??? Why that offset?!
mousepos = cam.ScreenToWorldPoint (mousepos);
obj.mousePositionWorld = mousepos;
}
}
and:
using UnityEngine;
public class SceneViewMouse : MonoBehaviour
{
public Vector3 mousePositionWorld;
void OnDrawGizmos()
{
Gizmos.DrawLine(this.transform.position, mousePositionWorld);
}
}
About that line that corrects the mouse position:
mousepos.y = Screen.height - mousepos.y - 36.0f;
I’ve noticed that the y-coordinate is inverted in scene view, but that does not surprise me much since sometime Unity inverses the Y coordinate depending on the platform. I’ve experienced that issue while writing shaders for both mobile and pc. But what I found more surprising is the mouse position seems to be shifted up by ~36 pixels. I can’t figure out why that is. Anyone has an idea?
The mouse position is fine. The problem is that Screen.height is erroneous. I took a screen shot of the scene and measured the actual scene view in Gimp: It does not match with the Screen.height printed in the console (see attachment).
SceneView sv = //get your scene view as usual;
var style = (GUIStyle) "GV Gizmo DropDown";
Vector2 ribbon = style.CalcSize( sv.titleContent );
Vector2 sv_correctSize = sv.position.size;
sv_correctSize.y -= ribbon.y; //exclude this nasty ribbon
//flip the position:
Vector2 mousePosFlipped = Event.current.mousePosition;
mousePosFlipped.y = sv_correctSize.y - mousePosFlipped.y;
Notice, sv.titleContent is actually 14 pixels (if we look into sv.titleContent.image.height). However, the style that’s showing it interprets it differently. Therefore we use style.CalcSize() to see how tall that title-ribbon will become when Unity uses this particual style.
A couple of useful things to remember for future (but not useful here): sv.position.height sv.position.position
Also, if your sv.camera.WorldPointToScreenPoint() produces some weird coordinates that are too large, you might wish to do this instead:
//gives coordinate inside SceneView context.
// WorldToViewportPoint() returns 0-to-1 value, where 0 means 0% and 1.0 means 100% of the dimension
Vector3 pointInSceneView = sv.camera.WorldToViewportPoint() * sv_correctSize;
I’ve tried like a dozen different methods including the one from ericbegue, and none of them work - as soon as I pan the scene view, the numbers change, even if I click the same world point.
It is as though the script still reports local coordinates instead of the world coordinates.
Maybe I’m missing something obvious.
I click a piece of wall tile (marked red) and get world mouse position reported as 6.22, -8,7.
Here’s the contents of my CustomTileInspector script, which lives on a Tilemap.
using UnityEngine;
using UnityEditor;
[ExecuteAlways]
public class CustomTileInspector : MonoBehaviour
{
public Vector3 mousePositionWorld;
}
[CustomEditor(typeof(CustomTileInspector))]
public class MyTileEditor : Editor
{
void OnSceneGUI()
{
CustomTileInspector obj = (CustomTileInspector)target;
if (Event.current.type == EventType.MouseDown)
{
Camera cam = SceneView.lastActiveSceneView.camera;
Vector3 mousepos = Event.current.mousePosition;
mousepos.z = -cam.worldToCameraMatrix.MultiplyPoint(obj.transform.position).z;
mousepos.y = Screen.height - mousepos.y - 36.0f;
mousepos = cam.ScreenToWorldPoint(mousepos);
obj.mousePositionWorld = mousepos;
}
}
}
I’m totally stuck. I feel like I’m missing something basic, but either I lack the necessary experience and/or the documentation is really scarce on this topic. Why it has to be this difficult (compared to runtime) is beyond me. Would anybody please help, any insights would be greatly appreciated.
This just seems like a dumpster fire to still be having this problem come up.
Event.current.mousePosition says, “The top-left of the window returns (0, 0). The bottom-right returns (Screen.width, Screen.height).”
ScreenToWorldPoint says, “Screenspace is defined in pixels. The bottom-left of the screen is (0,0); the right-top is (pixelWidth,pixelHeight). The z position is in world units from the camera.”
The y is flipped between these two functions and that is confusing API design.
My scene view camera is in 2D mode, so the Z doesn’t seem to matter to me.
With p being Event.current.mousePosition. No mention of pixel density or EditorGUIUtility.pixelsPerPoint in the documentation for ScreenToWorldPoint. Found it mentioned here: World mouse position in EditorWindow
Proposal: deprecate Event mousePosition. It’s poor API design, categorically. Replace it with Event position, or screenPosition perhaps. Have Event.current.position be in proper screen space, not flipped, and already account for pixelsPerPoint.
Fun fact in prefab mode there is another ribbon that is not accounted for in the title content.
This will get you the Rect of the current SceneView. The X and Y positions start under the prefab toolbar ribbon I highlighted and the width and height account for this offset giving the exact bounds of the view.
/// <summary>
/// Get the absolute coordinates and size of the current scene view.
/// </summary>
internal static Rect SceneViewCameraRect = (Rect)cameraRectPropertyInfo.GetValue(UnityEditor.SceneView.currentDrawingSceneView);
// Caching to optimise performance.
static PropertyInfo cameraRectPropertyInfo => _cameraRectPropertyInfo ??= typeof(UnityEditor.SceneView).GetProperty("cameraRect", BindingFlags.Instance | BindingFlags.NonPublic);
static PropertyInfo _cameraRectPropertyInfo;
The solutions here did not worked for me in Unity 2022.3 and seemed outdated. I implemented this logic to calculate the world coordinates of the mouse. Important to note is, that the result seems to be depending where the call is coming from. In this case I used the call from a method tied to the UnityEditor.EditorApplication.update event. But when for example the call come froms OnSceneGUI a different calculation has to be used, also stated in the code below.
Determine current mouse world position
private static void UpdateCurrentMouseWorldPosition()
{
// Gets the current scene view and scene view camera while design-time and play mode
var sceneView = SceneView.sceneViews.Count > 0 ? (SceneView)SceneView.sceneViews[0] : null;
var sceneViewCamera = sceneView?.camera;
if (sceneView != null && sceneViewCamera != null)
{
// Determine current mouse position with new input system
var mouseScreenPosition = Mouse.current.position.ReadValue();
// Determine offsets and bars of the scene view
var sceneViewTopBarsHeight = sceneView.rootVisualElement.worldBound.y;
var sceneViewAbsoluteScreenOffset = sceneView.position.min;
// Adjust y so it takes the top bars of the scene view into account and flip y-axis (cause of different coordinate systems)
// and also adjust x/y regarding the scene view offset
// (This is the correct code when calling from Update)
mouseScreenPosition.y = sceneViewCamera.pixelHeight - (mouseScreenPosition.y - sceneViewTopBarsHeight - sceneViewAbsoluteScreenOffset.y);
mouseScreenPosition.x -= sceneViewAbsoluteScreenOffset.x;
// Adjust y so it takes the top bars of the scene view into account and flip y-axis (cause of different coordinate systems)
// (This would be the correct code when calling from OnSceneGUI)
//mouseScreenPosition.y = sceneViewCamera.pixelHeight - (mouseScreenPosition.y - sceneViewTopBarsHeight);
MouseWorldSceneWindow._currentMouseWorldPosition = sceneViewCamera.ScreenToWorldPoint(mouseScreenPosition);
// Force repaint the scene view, so the scene window is also repainted with the new data
SceneView.RepaintAll();
}
}
}
I implemented a full script to display the coordinates in the scene view, just in case you are interessted in: