Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by ninjaboynaru · Jun 14, 2016 at 02:53 AM · uiraycastgraphicseventclick

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

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
4
Best Answer

Answer by MarkTerence · Jun 14, 2016 at 08:35 AM

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} \n 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();
                 } 
             }
         }
     }
 }




Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image ninjaboynaru · Jun 14, 2016 at 01:28 PM 0
Share

Ok, so this works really well but is there a global pointerData I can use ins$$anonymous$$d of me having to create one manually. It seems like that would make more sense?

avatar image MarkTerence ninjaboynaru · Jun 17, 2016 at 06:39 AM 0
Share

hmm. im not sure of how to make the PointerEventData global.

I updated the UIWorldDetect class a little, so i can call a function to tell whether if a UI element was clicked.

 using System.Collections;
 using UnityEngine.EventSystems;
 using System.Collections.Generic;
  
 public class UIWorldDetect : $$anonymous$$onoBehaviour {
     
     private static UIWorldDetect _instance;
     public static UIWorldDetect Instance{
         get{
             if(_instance==null){
                 _instance =  GameObject.FindObjectOfType<UIWorldDetect>();
             }
             return _instance;
         }
     }
  
     private PointerEventData pointerData; 
     private GameObject RootElementUI;
 
     //returns true if a ui elemend was clicked
     public bool isUIElementRaycasted(string gameObjectName){
         if(RootElementUI == null)
             return false;
         else{
             if(gameObjectName==RootElementUI.name){
                 RootElementUI = null;
                 return true;
             }
             else return false;
         }
     }
 
     void Update () {
         RaycastWorldUI();
     }
 
     void RaycastWorldUI(){
         if(Input.Get$$anonymous$$ouseButtonDown(0)){
             pointerData = new PointerEventData(EventSystem.current);
 
             pointerData.position = Input.mousePosition;
 
             List<RaycastResult> results = new List<RaycastResult>();
             EventSystem.current.RaycastAll(pointerData, results); 
             if (results.Count > 0) {
                 
                 if (results[0].gameObject.layer == Layer$$anonymous$$ask.NameToLayer("WorldUI_1")){ 
                      
                     string dbg = "Root Element: {0} \n GrandChild Element: {1}";
 
                     RootElementUI = results[results.Count-1].gameObject;
 
                     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();
                 } 
             }
         }
     }
 }
 

and tried it

 public class TestUIWorldHandler : $$anonymous$$onoBehaviour{
     void Update () {
         //isUIElementRaycasted("GameObjectName must be unique")
         if(UIWorldDetect.Instance.isUIElementRaycasted("Button")){
             Debug.Log("Press");
         } 
     }
 }

regarding on a global PointerEventData i found a rather old thread about it,

Global Pointer Events

avatar image
6

Answer by Brijs · Jun 14, 2016 at 07:13 AM

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

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image gregcodercw · Jan 16, 2018 at 10:31 PM 0
Share

This is exactly what I was looking for. Thank you!!

avatar image Arctic_Evolution · Jan 27, 2018 at 07:31 AM -1
Share

Best answer this one. People who post loads of code Like $$anonymous$$ark Terrence above, really only make it more difficult, for people grasping the basics, trying to sift through it all.

avatar image
-2

Answer by jister · Jul 08, 2017 at 10:17 AM

or set your canvas to world space...

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by ryo0ka · Apr 24, 2019 at 05:57 AM

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 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[i].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.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image hk0129 · Sep 16, 2020 at 08:49 PM 1
Share

Here's the new link if anyone wondering.

https://github.com/Unity-Technologies/uGUI/blob/2017.1/UnityEngine.UI/UI/Core/GraphicRaycaster.cs

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

84 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Interaction between commands waiting onMouseUp() 1 Answer

UI - How can I prevent a Rect Transform on a canvas from blocking clicks? 1 Answer

4.6 UI "image" is capturing clicks - how to prevent? 3 Answers

How to wait click on button in my MessageBox analogue? 1 Answer

Create UI raycast like a mouse Click 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges