Search Unity

Resolved AR Foundation, never blocking raycaster on UI

Discussion in 'AR' started by reddogg, Oct 12, 2020.

  1. reddogg

    reddogg

    Joined:
    Jun 17, 2013
    Posts:
    11
    Good morning, I have a problem with the UI of my app.
    The interface has some buttons, when I click on the buttons they work correctly, but if the button is in front of the detected AR plane raycast radius is not blocked, so a touch on the AR plane is detected and then the AR object is moved to that point.
    I've tried several solutions including UI detection via Event Systems but nothing seems to work.
    Does anyone else have the same problem? Some ideas on how to solve?

    TankYou
    cheers
     
    makaka-org likes this.
  2. Alexis-Dev

    Alexis-Dev

    Joined:
    Apr 16, 2019
    Posts:
    121
    Hi,

    You need to create your own ARRayCast.

    I implemente a class with a function to know if I have a raycast on UI first:

    Code (CSharp):
    1. public class PointerOverUI
    2.     {
    3.         public static bool IsPointerOverUIObject(Vector2 touchPosition)
    4.         {
    5.             PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
    6.             pointerEventData.position = touchPosition;
    7.             List<RaycastResult> raycastResults = new List<RaycastResult>();
    8.  
    9.             EventSystem.current.RaycastAll(pointerEventData, raycastResults);
    10.  
    11.             return raycastResults.Count > 0;
    12.         }
    13.     }
    And when I want to launch a raycast, I call this function:

    Code (CSharp):
    1.         private bool PhysicRayCastBlockedByUi(Vector2 touchPosition, out RaycastHit hit)
    2.         {
    3.             if (PointerOverUI.IsPointerOverUIObject(touchPosition))
    4.             {
    5.                 hit = new RaycastHit();
    6.                 return false;
    7.             }
    8.          
    9.             return Physics.Raycast(ScreenPointToRayFromArCamera(touchPosition), out hit, Mathf.Infinity, _layerMask);
    10.         }    
    _layerMask can be erase if you don't need to raycast on specific layer.

    If it's false, I have an UI element in front of me object.
    else I do a Raycast in my scene and I save raycast hit.
    (this is a part of me work to show you the begining)

    Best,
    Alexis
     
    SBA_Unity and makaka-org like this.
  3. reddogg

    reddogg

    Joined:
    Jun 17, 2013
    Posts:
    11
    Hi Alexis, thank you for the help but I still have the problem.
    I'm at the beginning of programming knowledge, so I understand your suggestion but it's not clear to me where the code should be inserted.
    I'm using the "PlaceOnPlane" script that's in the "arfoundation-samples" collection https://github.com/Unity-Technologies/arfoundation-samples
    I tried to modify it by entering the code that you suggest but without success, I still can't block rays on UI elements, it's evident that i don't do things in the correct way.
    if I don't ask too much, can you help me? I think working on that script can be very useful for many users.

    Tankyou

    Best,
    Fred
     
    makaka-org likes this.
  4. Alexis-Dev

    Alexis-Dev

    Joined:
    Apr 16, 2019
    Posts:
    121
    Hello,

    First, create a new file and copy/past PointerOverUI class.

    And modify PlaceOnPlane file like that:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.XR.ARFoundation;
    4. using UnityEngine.XR.ARSubsystems;
    5.  
    6. namespace UnityEngine.XR.ARFoundation.Samples
    7. {
    8.     /// <summary>
    9.     /// Listens for touch events and performs an AR raycast from the screen touch point.
    10.     /// AR raycasts will only hit detected trackables like feature points and planes.
    11.     ///
    12.     /// If a raycast hits a trackable, the <see cref="placedPrefab"/> is instantiated
    13.     /// and moved to the hit position.
    14.     /// </summary>
    15.     [RequireComponent(typeof(ARRaycastManager))]
    16.     public class PlaceOnPlane : MonoBehaviour
    17.     {
    18.         [SerializeField]
    19.         [Tooltip("Instantiates this prefab on a plane at the touch location.")]
    20.         GameObject m_PlacedPrefab;
    21.  
    22.         /// <summary>
    23.         /// The prefab to instantiate on touch.
    24.         /// </summary>
    25.         public GameObject placedPrefab
    26.         {
    27.             get { return m_PlacedPrefab; }
    28.             set { m_PlacedPrefab = value; }
    29.         }
    30.  
    31.         /// <summary>
    32.         /// The object instantiated as a result of a successful raycast intersection with a plane.
    33.         /// </summary>
    34.         public GameObject spawnedObject { get; private set; }
    35.  
    36.         void Awake()
    37.         {
    38.             m_RaycastManager = GetComponent<ARRaycastManager>();
    39.         }
    40.  
    41.         bool TryGetTouchPosition(out Vector2 touchPosition)
    42.         {
    43.             if (Input.touchCount > 0)
    44.             {
    45.                 touchPosition = Input.GetTouch(0).position;
    46.                 return true;
    47.             }
    48.  
    49.             touchPosition = default;
    50.             return false;
    51.         }
    52.  
    53.         void Update()
    54.         {
    55.             if (!TryGetTouchPosition(out Vector2 touchPosition))
    56.                 return;
    57.  
    58.             if (PhysicRayCastBlockedByUi(touchPosition))
    59.             {
    60.                 // Raycast hits are sorted by distance, so the first one
    61.                 // will be the closest hit.
    62.                 var hitPose = s_Hits[0].pose;
    63.  
    64.                 if (spawnedObject == null)
    65.                 {
    66.                     spawnedObject = Instantiate(m_PlacedPrefab, hitPose.position, hitPose.rotation);
    67.                 }
    68.                 else
    69.                 {
    70.                     spawnedObject.transform.position = hitPose.position;
    71.                 }
    72.             }
    73.         }
    74.  
    75.         static List<ARRaycastHit> s_Hits = new List<ARRaycastHit>();
    76.  
    77.         ARRaycastManager m_RaycastManager;
    78.  
    79.        private bool PhysicRayCastBlockedByUi(Vector2 touchPosition)
    80.        {
    81.                if (PointerOverUI.IsPointerOverUIObject(touchPosition))
    82.                {
    83.                      return false;
    84.                }
    85.  
    86.                return m_RaycastManager.Raycast(touchPosition, s_Hits, TrackableType.PlaneWithinPolygon);
    87.        }
    88.     }
    89. }
    I just add a function (PhysicRayCastBlockedByUi) and change condition in update function.
    It's will work (I didn't test it in unity before send this answer).

    Best,
    Alexis
     
    Jerome_Cornu and makaka-org like this.
  5. makaka-org

    makaka-org

    Joined:
    Dec 1, 2013
    Posts:
    1,026