Search Unity

Mouse position in Scene view

Discussion in 'Scripting' started by Melang, Jun 6, 2014.

  1. Melang

    Melang

    Joined:
    Mar 30, 2014
    Posts:
    166
    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.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class SceneViewMouse : MonoBehaviour
    5.  
    6. {
    7. }
    8.  
    in Editor folder:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEditor;
    5.  
    6. [CustomEditor(typeof(SceneViewMouse))]
    7. class SceneViewMouseEditor : Editor {
    8.  
    9.     void OnSceneGUI() {
    10.         SceneViewMouse obj = (SceneViewMouse)target;
    11.  
    12.         Vector3 mousepos = Event.current.mousePosition;
    13.  
    14.         mousepos = SceneView.lastActiveSceneView.camera.ScreenToWorldPoint (mousepos);
    15.         mousepos.y = -mousepos.y;
    16.      
    17.  
    18.         Debug.Log("mousepos: " + mousepos);
    19.         if (Event.current.type == EventType.mouseDown) {
    20.          
    21.          
    22.             Debug.Log("click");
    23.          
    24.         }
    25.     }
    26. }
    27.  
     

    Attached Files:

  2. mmankt

    mmankt

    Joined:
    Apr 29, 2015
    Posts:
    49
    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;
     
  3. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Here are the same scripts corrected to work both in 2D and 3D:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. [CustomEditor(typeof(SceneViewMouse))]
    5. class SceneViewMouseEditor : Editor {
    6.  
    7.     void OnSceneGUI()
    8.     {
    9.         SceneViewMouse obj = (SceneViewMouse)target;
    10.  
    11.         Camera cam = SceneView.lastActiveSceneView.camera;
    12.  
    13.         Vector3 mousepos = Event.current.mousePosition;
    14.         mousepos.z = -cam.worldToCameraMatrix.MultiplyPoint(obj.transform.position).z;
    15.         mousepos.y = Screen.height - mousepos.y - 36.0f; // ??? Why that offset?!
    16.         mousepos = cam.ScreenToWorldPoint (mousepos);
    17.  
    18.         obj.mousePositionWorld = mousepos;
    19.     }
    20. }
    and:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class SceneViewMouse : MonoBehaviour
    4. {
    5.     public Vector3 mousePositionWorld;
    6.  
    7.     void OnDrawGizmos()
    8.     {
    9.         Gizmos.DrawLine(this.transform.position, mousePositionWorld);
    10.     }
    11. }
    12.  
    13.  
    About that line that corrects the mouse position:
    Code (CSharp):
    1. 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?
     
    Last edited: Aug 18, 2016
    sdb7, deus0 and IgorAherne like this.
  4. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    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).
     

    Attached Files:

  5. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    Did anyone find a way to get the correct mouse position?
     
    deus0 likes this.
  6. IgorAherne

    IgorAherne

    Joined:
    May 15, 2013
    Posts:
    393
    It's because of that top ribbon.

    sceneView.jpg

    Code (CSharp):
    1.  
    2. SceneView sv = //get your scene view as usual;
    3.  
    4. var style = (GUIStyle) "GV Gizmo DropDown";
    5. Vector2 ribbon = style.CalcSize( sv.titleContent );
    6.  
    7. Vector2 sv_correctSize = sv.position.size;
    8. sv_correctSize.y -= ribbon.y; //exclude this nasty ribbon
    9.  
    10. //flip the position:
    11. Vector2 mousePosFlipped = Event.current.mousePosition;
    12. 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.

    ...How the f did I know which style to use? ctrl+f for "style" inside this link:
    https://github.com/jamesjlinden/unity-decompiled/blob/master/UnityEditor/UnityEditor/SceneView.cs

    ------------------
    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:

    Code (CSharp):
    1. //gives coordinate inside SceneView context.
    2. // WorldToViewportPoint() returns 0-to-1 value, where 0 means 0% and 1.0 means 100% of the dimension
    3. Vector3 pointInSceneView =  sv.camera.WorldToViewportPoint() * sv_correctSize;
     
    Last edited: Oct 9, 2018
    ratking, deus0 and CheekySparrow78 like this.
  7. CheekySparrow78

    CheekySparrow78

    Joined:
    Feb 9, 2019
    Posts:
    15
    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.

    Click1.jpg
    Then I pan the view and click the SAME wall tile (screenshot 2), but now I get different world coordinates! (3.7, -7.47)

    Click2.jpg

    Here's the contents of my CustomTileInspector script, which lives on a Tilemap.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4.  
    5. [ExecuteAlways]
    6. public class CustomTileInspector : MonoBehaviour
    7. {  
    8.     public Vector3 mousePositionWorld;
    9.    
    10. }
    11.  
    12. [CustomEditor(typeof(CustomTileInspector))]
    13. public class MyTileEditor : Editor
    14. {
    15.     void OnSceneGUI()
    16.     {
    17.         CustomTileInspector obj = (CustomTileInspector)target;      
    18.  
    19.         if (Event.current.type == EventType.MouseDown)
    20.         {
    21.             Camera cam = SceneView.lastActiveSceneView.camera;
    22.  
    23.             Vector3 mousepos = Event.current.mousePosition;
    24.             mousepos.z = -cam.worldToCameraMatrix.MultiplyPoint(obj.transform.position).z;
    25.             mousepos.y = Screen.height - mousepos.y - 36.0f;
    26.             mousepos = cam.ScreenToWorldPoint(mousepos);
    27.  
    28.             obj.mousePositionWorld = mousepos;
    29.         }
    30.     }
    31.  
    32.  
    33.  
    34. }

    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.
     
    deus0 and xpxilom like this.
  8. tonytopper

    tonytopper

    Joined:
    Jun 25, 2018
    Posts:
    226
    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.

    The tricky bit was this:

    Code (CSharp):
    1.  
    2. Vector3 worldPoint = camera.ScreenToWorldPoint(
    3.      new Vector3(
    4.           p.x * EditorGUIUtility.pixelsPerPoint,
    5.           camera.pixelHeight - p.y * EditorGUIUtility.pixelsPerPoint,
    6.           1
    7.      )
    8. );
    With p being Event.current.mousePosition. No mention of pixel density or EditorGUIUtility.pixelsPerPoint in the documentation for ScreenToWorldPoint. Found it mentioned here: https://forum.unity.com/threads/world-mouse-position-in-editorwindow.460917/

    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.
     
  9. OnlyFails

    OnlyFails

    Joined:
    Jan 24, 2015
    Posts:
    3
    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.
    Code (CSharp):
    1. /// <summary>
    2. /// Get the absolute coordinates and size of the current scene view.
    3. /// </summary>
    4. internal static Rect SceneViewCameraRect = (Rect)cameraRectPropertyInfo.GetValue(UnityEditor.SceneView.currentDrawingSceneView);
    5. // Caching to optimise performance.
    6. static PropertyInfo cameraRectPropertyInfo => _cameraRectPropertyInfo ??= typeof(UnityEditor.SceneView).GetProperty("cameraRect", BindingFlags.Instance | BindingFlags.NonPublic);
    7. static PropertyInfo _cameraRectPropertyInfo;
     

    Attached Files:

    Last edited: Dec 21, 2022
    thislop1 likes this.