Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.XR.Interaction.Toolkit.AR;
public class ARPlacementInteractableSingle : ARBaseGestureInteractable
[Tooltip("A GameObject to place when a raycast from a user touch hits a plane.")]
public GameObject placementPrefab;
[Tooltip("Callback event executed after object is placed.")]
private ARObjectPlacementEvent onObjectPlaced;
private GameObject placementObject;
private static List<ARRaycastHit> hits = new List<ARRaycastHit>();
private static GameObject trackablesObject;
protected override bool CanStartManipulationForGesture(TapGesture gesture)
if (gesture.StartPosition.IsPointOverUIObject())
return false;
// Allow for test planes
if (gesture.TargetObject == null || gesture.TargetObject.layer == 9)
return true;
return false;
protected override void OnEndManipulation(TapGesture gesture)
if(Input.touchCount == 0)
var touch = Input.GetTouch(0);
var touchPosition = touch.position;
bool isOverUI = touchPosition.IsPointOverUIObject();
if (gesture.WasCancelled)
// If gesture is targeting an existing object we are done.
// Allow for test planes
if (gesture.TargetObject != null && gesture.TargetObject.layer != 9)
//Checking if touch is over UI element
if (isOverUI)
Debug.Log("UI is touched");
// if (!isOverUI && GestureTransformationUtility.Raycast(gesture.StartPosition, hits, TrackableType.PlaneWithinPolygon))
// Raycast against the location the player touched to search for planes.
if (GestureTransformationUtility.Raycast(gesture.StartPosition, hits, TrackableType.PlaneWithinPolygon))
var hit = hits[0];
// Use hit pose and camera pose to check if hittest is from the
// back of the plane, if it is, no need to create the anchor.
if (Vector3.Dot(Camera.main.transform.position - hit.pose.position, hit.pose.rotation * Vector3.up) < 0)
//if(placementObject == null)
placementObject = Instantiate(placementPrefab, hit.pose.position, hit.pose.rotation);
// Create anchor to track reference point and set it as the parent of placementObject.
// TODO: this should update with a reference point for better tracking.
var anchorObject = new GameObject("PlacementAnchor");
anchorObject.transform.position = hit.pose.position;
anchorObject.transform.rotation = hit.pose.rotation;
placementObject.transform.parent = anchorObject.transform;
// Find trackables object in scene and use that as parent
if (trackablesObject == null)
trackablesObject = GameObject.Find("Trackables");
if (trackablesObject != null)
anchorObject.transform.parent = trackablesObject.transform;
onObjectPlaced?.Invoke(this, placementObject);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment