Hi guys!
I am new here
I am spawning a vehicle on a plane, and trying to figure out on what plane it was spawned and saving its boundaries. e.g. lowest and highest x,y and z coordinates of the plane the vehicle was spawned on.
I am attaching my code. I will appreciate your help very much!
P.S. I am also including my code achieving the behavior I am looking for with AR Foundation and ARCore (Commented out).
using System.Collections.Generic;
using Niantic.ARDK.AR;
using Niantic.ARDK.AR.ARSessionEventArgs;
using Niantic.ARDK.AR.HitTest;
using Niantic.ARDK.External;
using Niantic.ARDK.Utilities;
using Niantic.ARDK.Utilities.Input.Legacy;
using UnityEngine;
using UniRx;
using TMPro;
///
/// Responsible for placing the object on a plane
///
public class PlacementOnPlane : MonoBehaviour
{
///
/// The camera used to render the scene. Used to get the center of the screen.
///
public Camera Camera = null;
/// The types of hit test results to filter against when performing a hit test.
[EnumFlagAttribute]
public ARHitTestResultType HitTestType = ARHitTestResultType.ExistingPlane;
/// Internal reference to the session, used to get the current frame to hit test against.
private IARSession _session;
/// <summary>
/// Minimum boundary of the spawned plane
/// </summary>
public Vector3 MinBounds { get; private set; }
/// <summary>
/// Maximum boundary of the spawned plane
/// </summary>
public Vector3 MaxBounds { get; private set; }
/// <summary>
/// Bool reactive property that checks if we would like to place the object
/// todo: Change to false
/// </summary>
public ReactiveProperty<bool> IsReadyToPlace { get; private set; } =
new ReactiveProperty<bool>(true);
/// <summary>
/// The object we will spawn
/// </summary>
[SerializeField] private AffectedObject _objectToSpawn;
/// <summary>
/// Prints values to the canvas.
/// </summary>
public TextMeshProUGUI DebugText = null;
private void Start()
{
ARSessionFactory.SessionInitialized += OnAnyARSessionDidInitialize;
}
private void OnAnyARSessionDidInitialize(AnyARSessionInitializedArgs args)
{
_session = args.Session;
}
private void Update()
{
if (_session == null)
{
return;
}
if (PlatformAgnosticInput.touchCount <= 0)
{
return;
}
var touch = PlatformAgnosticInput.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
TouchBegan(touch);
}
}
private void TouchBegan(Touch touch)
{
var currentFrame = _session.CurrentFrame;
if (currentFrame == null)
{
return;
}
if (touch.IsTouchOverUIObject())
{
Debug.Log("Pressed on UI");
return;
}
var results = currentFrame.HitTest
(
Camera.pixelWidth,
Camera.pixelHeight,
touch.position,
HitTestType
);
int count = results.Count;
Debug.Log("Hit test results: " + count);
if (count <= 0)
{
Debug.LogWarning("Non-Positive hits");
return;
}
// Get the closest result
var result = results[0];
Debug.Log($"{result.GetType()}");
var hitPosition = result.WorldTransform.ToPosition();
if (!_objectToSpawn.gameObject.activeSelf)
{
_objectToSpawn.Spawn();
//todo: Find the plane on which the raycast was hit, to set _spawnedPlane
/**
// Set _spawnedPlane to the plane that was hit
_spawnedPlane = _hits[0].trackable as ARPlane;
// Calculate and set _minBounds and _maxBounds based on the boundaries of the spawned plane
CalculatePlaneBounds(_spawnedPlane);
*/
_objectToSpawn.transform.position = hitPosition;
ObjectPositionPrinter();
SetObjectPlacingMode();
}
/**
// Raycast hit a plane, spawn the object at the hit position
Pose hitPose = _hits[0].pose;
if (!_objectToSpawn.gameObject.activeSelf)
{
_objectToSpawn.Spawn();
// Set _spawnedPlane to the plane that was hit
_spawnedPlane = _hits[0].trackable as ARPlane;
// Calculate and set _minBounds and _maxBounds based on the boundaries of the spawned plane
CalculatePlaneBounds(_spawnedPlane);
_objectToSpawn.transform.position = hitPose.position;
ObjectPositionPrinter();
SetObjectPlacingMode();
}
*/
}
/// <summary>
/// Responsible for determining if we can place an object
/// </summary>
public void SetObjectPlacingMode()
{
if (IsReadyToPlace.Value)
{
IsReadyToPlace.Value = false;
}
else
{
if (_objectToSpawn.gameObject.activeSelf)
{
_objectToSpawn.Dispose();
}
IsReadyToPlace.Value = true;
}
}
/// <summary>
/// Printing the position of the object.
/// </summary>
private void ObjectPositionPrinter()
{
if (_objectToSpawn.gameObject.activeSelf)
{
DebugText.text = $"{_objectToSpawn.transform.position}";
}
else
{
DebugText.text = $"Still null.";
}
DebugText.text = $"Object position: {_objectToSpawn.transform.position}\n " +
$"Min X:{MinBounds.x}. Max X:{MaxBounds.x} MinZ:{MinBounds.z} MaxZ:{MaxBounds.z}";
}
/// <summary>
/// Calculate the boundaries of the spawned plane
/// </summary>
//private void CalculatePlaneBounds(ARPlane plane)
//{
// // Get the center of the plane
// Vector3 center = plane.center;
// // Get the extents of the plane (half of its size in each dimension)
// Vector2 extents = plane.extents;
// // Calculate the minimum and maximum bounds of the plane
// MinBounds = center - new Vector3(extents.x, 0, extents.y);
// MaxBounds = center + new Vector3(extents.x, 0, extents.y);
//}
}
/**
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using TMPro;
using UniRx;
///
/// Responsible for placing the object on a plane
///
public class PlacementOnPlane : MonoBehaviour
{
///
/// The object we will spawn
///
[SerializeField] private AffectedObject _objectToSpawn;
/// <summary>
/// Reference to the raycast manager
/// </summary>
private ARRaycastManager _raycastManager;
/// <summary>
/// Data Structure of the AR Raycast Hits
/// </summary>
private List<ARRaycastHit> _hits = new List<ARRaycastHit>();
/// <summary>
/// Bool reactive property that checks if we would like to place the object
/// </summary>
public ReactiveProperty<bool> IsReadyToPlace { get; private set; } =
new ReactiveProperty<bool>(false);
/// <summary>
/// Prints values to the canvas.
/// </summary>
public TextMeshProUGUI DebugText = null;
/// <summary>
/// Store the reference to the plane where the vehicle was spawned
/// </summary>
private ARPlane _spawnedPlane;
/// <summary>
/// Minimum boundary of the spawned plane
/// </summary>
public Vector3 MinBounds { get; private set; }
/// <summary>
/// Maximum boundary of the spawned plane
/// </summary>
public Vector3 MaxBounds { get; private set; }
private void Awake()
{
_raycastManager = GetComponent<ARRaycastManager>();
}
/// <summary>
/// Implementing the main AR logic
/// </summary>
void Update()
{
if ((Input.touchCount > 0) && (IsReadyToPlace.Value))
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
if (_raycastManager.Raycast(touch.position, _hits, TrackableType.PlaneWithinPolygon))
{
// Raycast hit a plane, spawn the object at the hit position
Pose hitPose = _hits[0].pose;
if (!_objectToSpawn.gameObject.activeSelf)
{
_objectToSpawn.Spawn();
// Set _spawnedPlane to the plane that was hit
_spawnedPlane = _hits[0].trackable as ARPlane;
// Calculate and set _minBounds and _maxBounds based on the boundaries of the spawned plane
CalculatePlaneBounds(_spawnedPlane);
_objectToSpawn.transform.position = hitPose.position;
ObjectPositionPrinter();
SetObjectPlacingMode();
}
}
}
}
}
/// <summary>
/// Calculate the boundaries of the spawned plane
/// </summary>
private void CalculatePlaneBounds(ARPlane plane)
{
// Get the center of the plane
Vector3 center = plane.center;
// Get the extents of the plane (half of its size in each dimension)
Vector2 extents = plane.extents;
// Calculate the minimum and maximum bounds of the plane
MinBounds = center - new Vector3(extents.x, 0, extents.y);
MaxBounds = center + new Vector3(extents.x, 0, extents.y);
}
/// <summary>
/// Printing the position of the object.
/// </summary>
private void ObjectPositionPrinter()
{
if (_objectToSpawn.gameObject.activeSelf)
{
DebugText.text = $"{_objectToSpawn.transform.position}";
}
else
{
DebugText.text = $"Still null.";
}
DebugText.text = $"Object position: {_objectToSpawn.transform.position}\n " +
$"Min X:{MinBounds.x}. Max X:{MaxBounds.x} MinZ:{MinBounds.z} MaxZ:{MaxBounds.z}";
}
/// <summary>
/// Responsible for determining if we can place an object
/// </summary>
public void SetObjectPlacingMode()
{
if (IsReadyToPlace.Value)
{
IsReadyToPlace.Value = false;
}
else
{
if (_objectToSpawn.gameObject.activeSelf)
{
_objectToSpawn.Dispose();
}
IsReadyToPlace.Value = true;
}
}
}
*/