Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[SOLVED] Interaction broken when Raycasting GameObjects in the Editor Scene View

Discussion in 'Scripting' started by Alesk, Mar 31, 2020.

  1. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    339
    Hi,

    I'm working on an Editor script to raycast and identify the GameObject under the mouse in the Scene view.
    But I'm facing a problem : all default mouse interactions to navigate in the view are not responding anymore, and clicking in another panel view of the Editor seems to interact with the scene view instead.

    Does anyone have an answer to this please ?

    Here is the full source code.

    Thanks for your help !

    EDIT : on Linux Mint + Unity 2019.3.6f1

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System;
    4. using System.Linq;
    5. using System.Reflection;
    6.  
    7. public class MeshPickerWindow : EditorWindow
    8. {
    9.     // ***************************************************************************************
    10.     // Scene Picking Code
    11.     //
    12.     // SOURCE : https://forum.unity.com/threads/editor-raycast-against-scene-meshes-without-collider-editor-select-object-using-gui-coordinate.485502/
    13.  
    14.     // powerful class, allows to detect intersection with mesh, without requiring any collider, etc
    15.     // Works in editor only
    16.     //
    17.     // Main Author https://gist.github.com/MattRix
    18.     // Igor Aherne improved it to include object picking as well   facebook.com/igor.aherne
    19.     // https://github.com/MattRix/UnityDecompiled/blob/master/UnityEditor/UnityEditor/HandleUtility.cs
    20.     static Type type_HandleUtility;
    21.     static MethodInfo meth_IntersectRayMesh;
    22.     static MethodInfo meth_PickObjectMeth;
    23.  
    24.     static MeshPickerWindow() {
    25.         var editorTypes = typeof(Editor).Assembly.GetTypes();
    26.         type_HandleUtility = editorTypes.FirstOrDefault(t => t.Name == "HandleUtility");
    27.         meth_IntersectRayMesh = type_HandleUtility.GetMethod("IntersectRayMesh",
    28.                                                               BindingFlags.Static | BindingFlags.NonPublic);
    29.         meth_PickObjectMeth = type_HandleUtility.GetMethod("PickGameObject",
    30.                                                             BindingFlags.Static | BindingFlags.Public,
    31.                                                             null,
    32.                                                             new [] {typeof(Vector2), typeof(bool)},
    33.                                                             null);
    34.     }
    35.  
    36.     // NO COLLIDER REQUIRED
    37.  
    38.     //get a point from intersected meshes in scene, based on mouse position.
    39.      public static bool IntersectRayMesh(Ray ray, MeshFilter meshFilter, out RaycastHit hit) {
    40.         return IntersectRayMesh(ray, meshFilter.sharedMesh, meshFilter.transform.localToWorldMatrix, out hit);
    41.     }
    42.     //get a point from intersected meshes in scene, based on mouse position.
    43.      public static bool IntersectRayMesh(Ray ray, Mesh mesh, Matrix4x4 matrix, out RaycastHit hit) {
    44.         var parameters = new object[] { ray, mesh, matrix, null };
    45.         bool result = (bool)meth_IntersectRayMesh.Invoke(null, parameters);
    46.         hit = (RaycastHit)parameters[3];
    47.         return result;
    48.     }
    49.     //select a gameObject in scene, based on mouse position.
    50.     public static GameObject PickGameObject(Vector2 position, bool updateSelection = true, bool selectPrefabRoot = false) {
    51.         if (updateSelection == false && Event.current != null) {
    52.             int blocking_ix = GUIUtility.GetControlID(FocusType.Passive);
    53.             HandleUtility.AddDefaultControl(blocking_ix);
    54.             GUIUtility.hotControl = blocking_ix; //tell unity that your control is active now, so it won't do selections etc.
    55.         }
    56.         GameObject pickedGameObject = (GameObject)meth_PickObjectMeth.Invoke(null, new object[] { position, selectPrefabRoot });
    57.         return pickedGameObject;
    58.     }
    59.     // ***************************************************************************************
    60.  
    61.     // ***************************************************************************************
    62.     // Test code
    63.     string myString = "nothing";
    64.  
    65.     // Add menu item named "My Window" to the Window menu
    66.     [MenuItem("Window/Mesh Picker Window")]
    67.     public static void ShowWindow()
    68.     {
    69.         //Show existing window instance. If one doesn't exist, make one.
    70.         EditorWindow.GetWindow(typeof(MeshPickerWindow));
    71.     }
    72.  
    73.     GameObject currentGameObject;
    74.     MeshFilter lastMeshFilter;
    75.     RaycastHit hit;
    76.  
    77.  
    78.     void OnEnable() {
    79.         SceneView.duringSceneGui += MySceneGUI;
    80.     }
    81.     void OnDisable() {
    82.         SceneView.duringSceneGui -= MySceneGUI;
    83.     }
    84.  
    85.     void MySceneGUI(SceneView sceneView){
    86.  
    87.         if (Event.current.type == EventType.MouseMove)
    88.         {
    89.             GameObject go = PickGameObject(Event.current.mousePosition,false,false);
    90.             if(go != null){
    91.                 if( go != currentGameObject){
    92.                     lastMeshFilter = go.GetComponent<MeshFilter>();
    93.                 }
    94.                 if(lastMeshFilter != null){
    95.                     Ray ray = HandleUtility.GUIPointToWorldRay (Event.current.mousePosition);
    96.                     IntersectRayMesh( ray, lastMeshFilter,out hit );
    97.                 }else{
    98.                     go = null;
    99.                 }
    100.             }
    101.  
    102.             if(go != currentGameObject){
    103.                 currentGameObject = go;
    104.                 this.Repaint();
    105.             }
    106.          
    107.         }else if(Event.current.type == EventType.Repaint){
    108.          
    109.             if(currentGameObject != null){
    110.                 float size = HandleUtility.GetHandleSize(hit.point)*0.05f;
    111.                 Handles.DotHandleCap(0,hit.point,Quaternion.identity,size,EventType.Repaint);
    112.             }
    113.         }
    114.  
    115.     }
    116.  
    117.     void OnGUI()
    118.     {
    119.         GUILayout.Label ("Base Settings", EditorStyles.boldLabel);
    120.         myString = EditorGUILayout.TextField ("Current object", this.currentGameObject == null?"nothing":this.currentGameObject.name);
    121.     }
    122.  
    123. }
     
    Last edited: Mar 31, 2020
  2. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    339
    Ouch !

    Solution found : lines 51 to 55 are the problem !

    Code (CSharp):
    1. if (updateSelection == false && Event.current != null) {
    2.             int blocking_ix = GUIUtility.GetControlID(FocusType.Passive);
    3.             HandleUtility.AddDefaultControl(blocking_ix);
    4.             GUIUtility.hotControl = blocking_ix; //tell unity that your control is active now, so it won't do selections etc.
    5.         }
    I guess I should have it only executed while clicking, and not hovering the mouse ;)

    So, to fix it I just had to replace line 89 by :

    GameObject go = (GameObject)meth_PickObjectMeth.Invoke(null, new object[] { Event.current.mousePosition, false });
     
    Last edited: Mar 31, 2020
    Kurt-Dekker likes this.