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

GraphicRaycaster raycast not hitting UI elements

Discussion in 'UGUI & TextMesh Pro' started by fendercodes, Oct 27, 2020.

  1. fendercodes

    fendercodes

    Joined:
    Feb 4, 2019
    Posts:
    191
    I have a second camera rendering a canvas to a texture. However, I cannot interact with UI elements in the canvas. Any ideas?

    Here is a screenshot of how its setup with a debug ray (red) showing that it is casting at a UI button.

    Screenshot 2020-10-27 at 19.55.21.png

    There is a custom GraphicRaycaster script on the canvas that is creating the debug ray you see in red above. Here is the script:

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using UnityEngine.EventSystems;
    5.  
    6. public class SmartphoneGraphicRaycaster : GraphicRaycaster
    7. {
    8.     public Camera screenCamera;
    9.  
    10.     // Called by Unity when a Raycaster should raycast because it extends BaseRaycaster.
    11.     public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
    12.     {
    13.         Ray ray = Camera.main.ScreenPointToRay(eventData.position);
    14.         RaycastHit hit;
    15.         if (Physics.Raycast(ray, out hit, 5f))
    16.         {
    17.             RaycastBeyondScreen(hit, resultAppendList);
    18.         }
    19.     }
    20.  
    21.     private void RaycastBeyondScreen(RaycastHit originHit, List<RaycastResult> resultAppendList)
    22.     {
    23.         // Figure out where the pointer would be in the second camera based on texture position or RenderTexture.
    24.         Vector3 virtualPos = new Vector3(originHit.textureCoord.x, originHit.textureCoord.y);
    25.         Ray ray = screenCamera.ViewportPointToRay(virtualPos);
    26.         Debug.DrawRay(ray.origin, ray.direction * 5, Color.red, 0.2f);
    27.  
    28.         RaycastHit hit;
    29.         if (Physics.Raycast(ray, out hit, 5f))
    30.         {
    31.             Debug.LogWarning(hit.collider.gameObject);
    32.             RaycastResult result = new RaycastResult
    33.             {
    34.                 gameObject = hit.collider.gameObject,
    35.                 module = this,
    36.                 distance = hit.distance,
    37.                 index = resultAppendList.Count,
    38.                 worldPosition = hit.point,
    39.                 worldNormal = hit.normal,
    40.             };
    41.             resultAppendList.Add(result);
    42.         }
    43.     }
    44. }
    The ray definitely seems to be casting in the right direction to where my mouse is on the render texture. So that's good. However, I have tried logging the raycast hits and it is always objects behind the UI in the game world. I also tried adding either a box or mesh collider to the button UI elements, but that didn't seem to help either. I've also ensured any other canvas is disabled in the scene.
     
    Santi0512 likes this.
  2. fendercodes

    fendercodes

    Joined:
    Feb 4, 2019
    Posts:
    191
    Is what I am trying to do even possible? o_O
     
  3. fendercodes

    fendercodes

    Joined:
    Feb 4, 2019
    Posts:
    191
    I tried another option but to no avail.
    Code (CSharp):
    1.     void FixedUpdate() {
    2.         if (CF2Input.GetMouseButtonDown(0)) {
    3.             Ray ray = Camera.main.ScreenPointToRay(CF2Input.mousePosition);
    4.             RaycastHit hit;
    5.             if (Physics.Raycast(ray, out hit, 5f))
    6.             {
    7.                 Debug.LogWarning("hit");
    8.                 RaycastBeyondScreen(hit);
    9.             }
    10.         }
    11.     }
    12.  
    13.     private void RaycastBeyondScreen(RaycastHit originHit) {
    14.         Vector3 virtualPos = new Vector3(originHit.textureCoord.x, originHit.textureCoord.y);
    15.         var data = new PointerEventData(eventSystem);
    16.         Ray ray = deviceCamera.ViewportPointToRay(virtualPos);
    17.         data.position = ray.origin;
    18.         List<RaycastResult> results = new List<RaycastResult>();
    19.         graphicRaycaster.Raycast(data, results);
    20.         foreach (RaycastResult result in results)
    21.         {
    22.             Debug.Log("Hit " + result.gameObject.name);
    23.         }
    24.     }
     
  4. fendercodes

    fendercodes

    Joined:
    Feb 4, 2019
    Posts:
    191
    So I figured out a method that works, although it's likely not be the most efficient. I removed the Graphic Raycaster and run this script, with references to the Button RectTransform components that I want to detect interaction with.

    Code (CSharp):
    1.     void FixedUpdate() {
    2.         if (CF2Input.GetMouseButtonDown(0)) {
    3.             Ray ray = Camera.main.ScreenPointToRay(CF2Input.mousePosition);
    4.             RaycastHit hit;
    5.             int layerMask = 1 << LayerMask.NameToLayer("Overlay");
    6.             if (Physics.Raycast(ray, out hit, 1f, layerMask))
    7.             {
    8.                 Vector2 pos = new Vector2(hit.textureCoord.x * deviceCamera.scaledPixelWidth, hit.textureCoord.y * deviceCamera.scaledPixelHeight);
    9.                 bool isInRect = RectTransformUtility.RectangleContainsScreenPoint(testRect, pos, deviceCamera);
    10.                 if (isInRect) testRect.GetComponent<Button>().onClick.Invoke();
    11.             }
    12.         }
    13.     }