Raycast against UI in world space

How do I cast a ray from the mouse position to the world and check if I hit a UI element in world space

I need to detect which UI element was clicked and adding an OnClick() event to each element is NOT and option.

Some type of raycast seems to be my best option but I have no Idea where to start.

I’ve already tried EventSystem.current.RaycastAll() but it does not give information on clicks

Thanks

To use ray cast you should have collider on object.

Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);

This is how you can get ray from mouse position

Now for click detection on world space UI, make sure that the “GraphicsRaycaster” is attached to canvas.

Implement “IPointerClickHandler” interface and write code to interface method.

public class NewBehaviourScript : MonoBehaviour,IPointerClickHandler
{   
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("Clicked" + gameObject.name);        
    }
}

Attach this monobehaviour to UI element

If you want to use physics raycast to detect click on UI element then you should attach collider to ui element

Here is a quick way, so you don’t need to attach a script on every world UI elements you have.

  • Add a new Layer, you can name it something like ‘World UI’
    -On your World Canvas (the canvas having a world space render type), set its Layer to ‘World UI’ or the layer you just created.

  • attach this script on the world canvas or at any game object, empty or not

    using UnityEngine;
    using System.Collections;
    using UnityEngine.EventSystems;
    using System.Collections.Generic;

    public class UIWorldDetect : MonoBehaviour {

     void Update () {
     	RaycastWorldUI();
     }
    
     void RaycastWorldUI(){
     	if(Input.GetMouseButtonDown(0)){
     		PointerEventData pointerData = new PointerEventData(EventSystem.current);
    
     		pointerData.position = Input.mousePosition;
    
     		List<RaycastResult> results = new List<RaycastResult>();
     		EventSystem.current.RaycastAll(pointerData, results);
    
     		if (results.Count > 0) {
                             //WorldUI is my layer name
     			if (results[0].gameObject.layer == LayerMask.NameToLayer("WorldUI")){ 
     				string dbg = "Root Element: {0} 
    

GrandChild Element: {1}";
Debug.Log(string.Format(dbg, results[results.Count-1].gameObject.name,results[0].gameObject.name));
//Debug.Log("Root Element: "+results[results.Count-1].gameObject.name);
//Debug.Log("GrandChild Element: "+results[0].gameObject.name);
results.Clear();
}
}
}
}
}

Mark’s answer above didn’t work for me. I’m developing an AR/VR game and my primary use of UI raycasting is to detect whether the user (camera) is facing the canvas at a given frame.

I looked up the [Unity UI repository][1] and stripped out the part that’s doing the raycasting:

void Update()
{
	IsFocused = false; // Member property... change this to whatever you want

	Vector2 center = _camera.ViewportToScreenPoint(Vector2.one / 2); // Center of camera
	var graphics = GraphicRegistry.GetGraphicsForCanvas(_canvas); // All Graphics in canvas

	for (var i = 0; i < graphics.Count; i++)
	{
		var t = graphics*.rectTransform; // Get the Graphic's RectTransform*
  •   	Debug.Log($"name: {t.name}"); // Show their names if you want*
    
  •   	// Check if the RectTransform "contains" the center of camera == is "looked at" now*
    
  •   	IsFocused |= RectTransformUtility.RectangleContainsScreenPoint(t, center, _camera);*
    
  •   }*
    
  •   //Debug.Log(IsFocused); // Should be true if any Graphics were "looked at"*
    
  • }*
    …which works for me. IsFocused in the code above will be true if the camera is looking at one or more Graphic components in the canvas (i.e. Image, RawImage, Text, etc…)
    The key APIs in this code are
    - GraphicRegistry.GetGraphicsForCanvas() and
    - RectTransformUtility.RectangleContainsScreenPoint().
    By using these functions properly you can check if your canvas “contains” any screen-space points in your camera. You can also apply these functions to the canvas itself’s RectTransform for better performance if your UI components will sit exactly within the canvas.
    Note that this code does not take account of objects occluding the canvas from the camera – the code wil always say “true” even if the canvas may be practically invisible from user. You’ll need to revisit the Unity UI repository above and see how the official API (is trying to) solve the situation if you need to test such occlusions.
    Hoping that this will help someone else.
    [1]: https://bitbucket.org/Unity-Technologies/ui/src/4f3cf8d16c1d8c6e681541a292855792e50b392e/UnityEngine.UI/UI/Core/GraphicRaycaster.cs?at=5.2&fileviewer=file-view-default

or set your canvas to world space…