Search Unity

Blocking Physics Raycasts with the UI?

Discussion in 'UGUI & TextMesh Pro' started by douglasg14b, Feb 23, 2015.

  1. douglasg14b

    douglasg14b

    Joined:
    Oct 2, 2014
    Posts:
    34
    I use raycasts to determine hit objects and object selection in our game. I want these to be blocked by UI elements. Before I had a crude form of that where I just excluded rects of the screen, though with a non-rectangle shaped UI that's pretty difficult.

    I want to have physics raycasts NOT go through UI objects, can this be done? My initial thought it adding colliders to the UI objects, though I'm not sure if the colliders will scale with elements based on screen size.

    Note: Canvas Group does not apply to physics.raycast
     
  2. Ramcat

    Ramcat

    Joined:
    Aug 16, 2014
    Posts:
    95
    efge likes this.
  3. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
    FYI its worded like that as it will return true if its over any EvenSystem controlled element. So if you have a physics raycaster and the mouse is over a physics collider it will be true.
     
  4. Ramcat

    Ramcat

    Joined:
    Aug 16, 2014
    Posts:
    95
    Ooh, I'm worried that my suggestion won't work for him as he is using physics raycasts. Is there anyway in code to detect the new UI and no other systems?
     
  5. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    @phil-Unity This question has come up a few times.
    Is there anyway to block normal raycasting through the UI canvas or UI object?

    So preventing Physics.Raycast from passing through a Canvas?
     
  6. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
    No there is no way to do that unfortunately just with the extra check
     
  7. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Fair enough @phil-Unity Still need to come up with an answer to that, either with layers or (as some have found) adding UI scripts to 3D objects
     
  8. chin13577

    chin13577

    Joined:
    May 8, 2017
    Posts:
    17
  9. WesleyRaymundo

    WesleyRaymundo

    Joined:
    Mar 7, 2015
    Posts:
    4
    A workaround is to create a CustomInputModule to get buttons' PointerEventData, there you find pointerCurrentRaycast who tells you which BaseRaycaster was used in it - so you just check it.

    Here's a CustomStandaloneInputModule
    Code (CSharp):
    1. using UnityEngine.EventSystems;
    2.  
    3. /*  /class CustomStandaloneInputModule
    4. *  /brief A StandaloneInputModule with access to buttons' PointerEventData and RaycasterModule checking
    5. */
    6. public class CustomStandaloneInputModule : StandaloneInputModule
    7. {
    8.     /// <summary>
    9.     /// Returns current PointerEventData
    10.     /// </summary>
    11.     public PointerEventData GetPointerData(int pointerId = kMouseLeftId)
    12.     {
    13.         PointerEventData pointerData;
    14.  
    15.         m_PointerData.TryGetValue(pointerId, out pointerData);
    16.         if (pointerData == null) pointerData = new PointerEventData(EventSystem.current);
    17.  
    18.         return pointerData;      
    19.     }
    20.  
    21.     /// <summary>
    22.     /// Returns true if current raycast has hit an game object using Raycaster T
    23.     /// </summary>
    24.     public bool IsPointerOverGameObject<T>(int pointerId = kMouseLeftId, bool includeDerived = false) where T : BaseRaycaster
    25.     {
    26.         if(IsPointerOverGameObject(pointerId))
    27.         {
    28.             PointerEventData pointerEventData;
    29.             if (m_PointerData.TryGetValue(pointerId, out pointerEventData))
    30.             {
    31.                 if (includeDerived)
    32.                 {
    33.                     return pointerEventData.pointerCurrentRaycast.module is T;
    34.                 }
    35.                 else
    36.                 {
    37.                     return pointerEventData.pointerCurrentRaycast.module.GetType() == typeof(T);
    38.                 }
    39.             }
    40.         }
    41.         return false;
    42.     }
    43. }
    Usage example:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.EventSystems;
    4.  
    5. public class MoveControl : MonoBehaviour
    6. {
    7.     CustomStandaloneInputModule inputModule;
    8.  
    9.     private void Awake()
    10.     {
    11.         inputModule = FindObjectOfType<CustomStandaloneInputModule>();
    12.     }
    13.  
    14.     private void Update()
    15.     {
    16.         if (inputModule.IsPointerOverGameObject<PhysicsRaycaster>())
    17.         {
    18.             print("Over 3D Object!");
    19.         }
    20.         else if (inputModule.IsPointerOverGameObject<Physics2DRaycaster>())
    21.         {
    22.             print("Over 2D Object!");
    23.         }
    24.         else if (inputModule.IsPointerOverGameObject<GraphicRaycaster>())
    25.         {
    26.             print("Over UI Object!");
    27.         }
    28.     }  
    29. }
     
    Alemo, jvella_bhvr, Avard and 3 others like this.
  10. devpros

    devpros

    Joined:
    Jan 26, 2017
    Posts:
    4
    For me, in the case of having a Physics raycaster attached to the camera the most simple and cleanest solution to prevent the raycaster from firing trough canvas (as it will fire in the case of having a physics raycaster on camera) was to simply check the eventsystem for a selected UI piece.
    Code (CSharp):
    1. EventSystem.current.currentSelectedGameObject != null
     
  11. hottabych

    hottabych

    Joined:
    Apr 18, 2015
    Posts:
    107
    Unfortunately, for me it's worked only if I use GraphicRaycaster.
    Problems began when I add PhysicsRaycaster to the camera.
    Now IsPointerOverGameObject() always returns true, if pointer over UI or physic objects.
     
    DFKChris likes this.
  12. jfa257

    jfa257

    Joined:
    Jul 17, 2013
    Posts:
    9
    Sorry for resurrecting, just want to post what worked for me. I'm using both physic and graphic raycasters.


    Code (CSharp):
    1. RaycastHit theHit;
    2.  
    3. if(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out theHit, Mathf.Infinity)){
    4.  
    5. // success on raycastHit stored on theHit object
    6.  
    7.      if(  theHit.collider.tag == "expectedTag" && !EventSystem.current.IsPointerOverGameObject())
    8.        {
    9.           // will only get here if theHit object is being raycasted and no UIElement (on the UI layer) is             being touched by the mouse pointer
    10.        }
    11. }
    12.  
    Note that EventSystem.current.IsPointerOverGameObject() is a Method, is the most recommended option IMO
     
    Recluse, deivid-01, Babiole and 7 others like this.
  13. zhanxuzhao

    zhanxuzhao

    Joined:
    Jul 10, 2017
    Posts:
    1
    1. Add a button at the bottom of the canvas, uncheck image to make the button invisible;
    2. In Update method, check `EventSystem.current.currentSelectedGameObject != null`
    done
    upload_2021-5-13_7-27-27.png
    upload_2021-5-13_7-33-27.png
     

    Attached Files:

    Scorpin and Antimon13 like this.
  14. MarkSharpe

    MarkSharpe

    Joined:
    Feb 3, 2021
    Posts:
    27
    I am having one heck of a time getting my XR rig to move from scene to scene with working UI in each. I have made a prefab which includes the XR Rig, Event System with XRUI input module, as well as the XR interaction module. The prefab has this script attached.
    public class DontDestroy : MonoBehaviour
    {
    public static DontDestroy instance;
    void Start()
    {
    if (instance == null)
    {
    instance = this;
    DontDestroyOnLoad(this);
    }
    else
    {
    Destroy(gameObject);
    }
    }
    }
    I can use the UI I have attached to my wrists to move from scene to scene. However, the XR Raycast Interactor raycasts will not move anywhere but within the canvas and whenever I return to Scene(0) from scene (1) the entire rig shuts down leaving only the camera mobile. Here's a vid of what it looks like:
     
  15. Keywee123

    Keywee123

    Joined:
    Dec 15, 2021
    Posts:
    2
    Thank you ,Thats what I was looking for
     
  16. JFR

    JFR

    Joined:
    Feb 21, 2014
    Posts:
    65
    Same here, infinite thanks, in my case I only had to add && !EventSystem.current.IsPointerOverGameObject() to my check. Most simple solution, no lengthy code to write.
     
  17. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    this worked for me, using a physics raycast.

     
    Arknoid likes this.
  18. DucaDiMonteSberna

    DucaDiMonteSberna

    Joined:
    Jan 18, 2018
    Posts:
    79
    Code (CSharp):
    1. private bool DefineOnUI()
    2.     {
    3.         //Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    4.         if (EventSystem.current.IsPointerOverGameObject())
    5.         {
    6.             Debug.Log("Clicked on the UI");
    7.             return true;
    8.         }
    9.         else
    10.         {
    11.             return false;
    12.         }
    13.     }
    for future reference