Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to raycast from mouse position in scene view?

Discussion in 'Scripting' started by chambino, Nov 21, 2019.

  1. chambino

    chambino

    Joined:
    Jun 4, 2018
    Posts:
    12
    I'm trying to raycast in scene view based mouse position. I pretty much want to mimic the unity's behavior when you click some where it selects that objects except I wish to get all the objects through that ray.

    Here's exactly what I want to do:
    1. Press a button on the inspector of a script to start raycasting.
    2. As user moving through scene it selects (keeps record of) all the objects that intersect with ray from current mouse position.
    3. Then user clicks in the scene view to stop the raycasting and the last set of selected objects is shown in the inspector.

    I've search and not seen a solution that works. It seems like such a trivial thing to be able to do.

    So if anyone can guide me to create a simple scriptthat works that would be great.

    Here's a link to what I have so far: https://gist.github.com/lordlycastle/fdc919da37585410309df3231ed03e00
     
  2. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,745
    You can get scene camera reference inside OnWillRenderObject handlers from Camera.current, but idk how to get mouse position in scene view coordinates if your scene/game windows do not overlap
     
  3. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    You can cast a ray through the camera as described here:
    https://docs.unity3d.com/Manual/CameraRays.html

    You can get all objects (instead of the first) that the ray hits by using RaycastAll instead:
    https://docs.unity3d.com/ScriptReference/Physics.RaycastAll.html
    Note that the order is not guaranteed.

    You can then make a script run in editor mode by adding the [ExecuteInEditorMode] attribute:
    https://docs.unity3d.com/ScriptReference/ExecuteInEditMode.html

    Hope this helps :)

    Edit: To reply to palex-nx, you can get the mouse position by getting Event.current.mousePosition in OnSceneGui(). If i remember correctly, OnScenGui is basically your Update() equivalent for custom editors. And while i'm at it, you may wanna create the script as a custom editor instead of a Monobehavior, depending on if it's only used in SceneView.
     
    Last edited: Nov 21, 2019
  4. chambino

    chambino

    Joined:
    Jun 4, 2018
    Posts:
    12
    @Yoreki I've actually seen all those. As you can see from the script linked above. The problem isn't that I can't raycast through all. You can do that with RaycastAll. The problem is getting the Ray from scene camera based on mouse position.
     
  5. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    Have you tried the following to get the ray?
    Code (CSharp):
    1. Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
     
  6. PabloIH

    PabloIH

    Joined:
    Sep 20, 2014
    Posts:
    12
    I've tried many solutions. This one works, but not in all scenarios. I'm not sure what is going on but depending on the PC (maybe resolution) the ray is not sent properly.

    In my PC its fov and resolution independent but we had to revert this because was not consistent across different people.

    Also there is a weird consisten 45 pixels offset between the cursor and the actual click in the screen. If anyone has any extra clues about this would be very appreciated.

    This includes what I tried for debug purposes:

    Code (CSharp):
    1. Ray camRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
    2.  
    3.         // For debug purposes
    4.         Debug.DrawRay(camRay.origin, camRay.direction * 50, Color.blue, 15);
    5.         if (Physics.Raycast(camRay, out var hitDebug, float.MaxValue, -1, QueryTriggerInteraction.Ignore))
    6.         {
    7.             Debug.DrawLine(hitDebug.point - Vector3.forward * 1f, hitDebug.point + Vector3.forward * 1f, Color.red, 10);
    8.             Debug.DrawLine(hitDebug.point - Vector3.right * 1f, hitDebug.point + Vector3.right * 1f, Color.red, 10);
    9.             Debug.DrawLine(hitDebug.point - Vector3.up * 1f, hitDebug.point + Vector3.up * 1f, Color.red, 10);
    10.         }
     
  7. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    First, to be clear, HandleUtility.GUIPointToWorldRay is an editor only thing.

    Second, regarding the offset, it is because of the ribbon above the scene view, and I've seen weird ways people try to get rid of it, over the years, which is unnecessary. This should be sorted out if you capture your mouse inside the scene view callback.

    Refer to this utility class I shared recently (specifically onSceneGui handler in UserScript class). It does mouse capturing as a side-thing, just to show off some features.

    Also this line of code to hook up the handler
    Code (csharp):
    1. SceneView.duringSceneGui += onSceneGui;
    I've made an array of very luxurious custom editors in the last 5 years. This is the staple way I'm always using to get the mouse cursor inside the scene.
     
    Last edited: Jun 13, 2023
  8. SachinGanesh

    SachinGanesh

    Joined:
    Jun 28, 2015
    Posts:
    19
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. public class SpawnSphereOnHit : MonoBehaviour
    5. {
    6.     [MenuItem("Tools/Enable Spawn Sphere On Hit")]
    7.     private static void EnableSpawnSphereOnHit()
    8.     {
    9.         SceneView.duringSceneGui += OnSceneGUI;
    10.     }
    11.  
    12.     [MenuItem("Tools/Disable Spawn Sphere On Hit")]
    13.     private static void DisableSpawnSphereOnHit()
    14.     {
    15.         SceneView.duringSceneGui -= OnSceneGUI;
    16.     }
    17.  
    18.     private static void OnSceneGUI(SceneView sceneView)
    19.     {
    20.         if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
    21.         {
    22.             Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
    23.             RaycastHit hit;
    24.  
    25.             if (Physics.Raycast(ray, out hit))
    26.             {
    27.                 Debug.Log("Hit object name: " + hit.collider.gameObject.name);
    28.  
    29.                 GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    30.                 sphere.transform.position = hit.point;
    31.                 sphere.transform.parent = hit.collider.transform;
    32.             }
    33.             else
    34.             {
    35.                 Debug.Log("No object hit.");
    36.             }
    37.         }
    38.     }
    39. }
    40.