This repository has been archived on 2025-04-28. You can view files and clone it, but cannot push or open issues or pull requests.
ARPlusSystem/ARPlusSystem-250418/Library/PackageCache/com.unity.xr.arfoundation@4.../Runtime/AR/ARPlane.cs

231 lines
8.0 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.XR.ARSubsystems;
namespace UnityEngine.XR.ARFoundation
{
/// <summary>
/// Represents a plane (that is, a flat surface) detected by an AR device.
/// </summary>
/// <remarks>
/// Generated by the <see cref="ARPlaneManager"/> when an AR device detects
/// a plane in the environment.
/// </remarks>
[DefaultExecutionOrder(ARUpdateOrder.k_Plane)]
[DisallowMultipleComponent]
[HelpURL(HelpUrls.ApiWithNamespace + nameof(ARPlane) + ".html")]
public sealed class ARPlane : ARTrackable<BoundedPlane, ARPlane>
{
[SerializeField]
[Tooltip("The largest value by which a plane's vertex may change before the boundaryChanged event is invoked. Units are in meters.")]
float m_VertexChangedThreshold = 0.01f;
/// <summary>
/// The largest value by which a plane's vertex could change before the mesh is regenerated. Units are in meters.
/// </summary>
public float vertexChangedThreshold
{
get => m_VertexChangedThreshold;
set => m_VertexChangedThreshold = Mathf.Max(0f, value);
}
/// <summary>
/// Invoked when any vertex in the plane's boundary changes by more than <see cref="vertexChangedThreshold"/>.
/// </summary>
public event Action<ARPlaneBoundaryChangedEventArgs> boundaryChanged;
/// <summary>
/// Gets the normal to this plane in world space.
/// </summary>
public Vector3 normal => transform.up;
/// <summary>
/// The <see cref="ARPlane"/> which has subsumed this plane, or <c>null</c>
/// if this plane has not been subsumed.
/// </summary>
public ARPlane subsumedBy { get; internal set; }
/// <summary>
/// The alignment of this plane.
/// </summary>
public PlaneAlignment alignment => sessionRelativeData.alignment;
/// <summary>
/// The classification of this plane.
/// </summary>
public PlaneClassification classification { get { return sessionRelativeData.classification; } }
/// <summary>
/// The 2D center point, in plane space
/// </summary>
public Vector2 centerInPlaneSpace => sessionRelativeData.center;
/// <summary>
/// The 3D center point, in Unity world space.
/// </summary>
public Vector3 center => transform.TransformPoint(new Vector3(centerInPlaneSpace.x, 0, centerInPlaneSpace.y));
/// <summary>
/// The physical extents (half dimensions) of the plane in meters.
/// </summary>
public Vector2 extents => sessionRelativeData.extents;
/// <summary>
/// The physical size (dimensions) of the plane in meters.
/// </summary>
public Vector2 size => sessionRelativeData.size;
/// <summary>
/// Get the infinite plane associated with this <see cref="ARPlane"/>.
/// </summary>
public Plane infinitePlane => new Plane(normal, transform.position);
/// <summary>
/// Get a native pointer associated with this plane.
/// </summary>
/// <remarks>
/// The data pointed to by this member is implementation defined.
/// The lifetime of the pointed to object is also
/// implementation defined, but should be valid at least until the next
/// <see cref="ARSession"/> update.
/// </remarks>
public IntPtr nativePtr => sessionRelativeData.nativePtr;
/// <summary>
/// The plane's boundary points, in plane space, that is, relative to this <see cref="ARPlane"/>'s
/// local position and rotation.
/// </summary>
public unsafe NativeArray<Vector2> boundary
{
get
{
if (!m_Boundary.IsCreated)
return default(NativeArray<Vector2>);
var boundary = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<Vector2>(
m_Boundary.GetUnsafePtr(),
m_Boundary.Length,
Allocator.None);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(
ref boundary,
NativeArrayUnsafeUtility.GetAtomicSafetyHandle(m_Boundary));
#endif
return boundary;
}
}
internal void UpdateBoundary(XRPlaneSubsystem subsystem)
{
// subsystem cannot be null here
if (subsystem.subsystemDescriptor.supportsBoundaryVertices)
{
subsystem.GetBoundary(trackableId, Allocator.Persistent, ref m_Boundary);
}
else
{
if (!m_Boundary.IsCreated)
{
m_Boundary = new NativeArray<Vector2>(4, Allocator.Persistent);
}
else if (m_Boundary.Length != 4)
{
m_Boundary.Dispose();
m_Boundary = new NativeArray<Vector2>(4, Allocator.Persistent);
}
var extents = sessionRelativeData.extents;
m_Boundary[0] = new Vector2(-extents.x, -extents.y);
m_Boundary[1] = new Vector2(-extents.x, extents.y);
m_Boundary[2] = new Vector2( extents.x, extents.y);
m_Boundary[3] = new Vector2( extents.x, -extents.y);
}
if (boundaryChanged != null)
CheckForBoundaryChanges();
}
void OnValidate()
{
vertexChangedThreshold = Mathf.Max(0f, vertexChangedThreshold);
}
void OnDestroy()
{
if (m_OldBoundary.IsCreated)
m_OldBoundary.Dispose();
if (m_Boundary.IsCreated)
m_Boundary.Dispose();
}
void CheckForBoundaryChanges()
{
if (m_Boundary.Length != m_OldBoundary.Length)
{
CopyBoundaryAndSetChangedFlag();
}
else if (vertexChangedThreshold == 0f)
{
// Don't need to check each vertex because it will always
// be "different" if threshold is zero.
CopyBoundaryAndSetChangedFlag();
}
else
{
// Counts are the same; check each vertex
var thresholdSquared = vertexChangedThreshold * vertexChangedThreshold;
for (int i = 0; i < m_Boundary.Length; ++i)
{
var diffSquared = (m_Boundary[i] - m_OldBoundary[i]).sqrMagnitude;
if (diffSquared > thresholdSquared)
{
CopyBoundaryAndSetChangedFlag();
break;
}
}
}
}
void CopyBoundaryAndSetChangedFlag()
{
// Copy new boundary
if (m_OldBoundary.IsCreated)
{
// If the lengths are different, then we need
// to reallocate, but otherwise, we can reuse
if (m_OldBoundary.Length != m_Boundary.Length)
{
m_OldBoundary.Dispose();
m_OldBoundary = new NativeArray<Vector2>(m_Boundary.Length, Allocator.Persistent);
}
}
else
{
m_OldBoundary = new NativeArray<Vector2>(m_Boundary.Length, Allocator.Persistent);
}
m_OldBoundary.CopyFrom(m_Boundary);
m_HasBoundaryChanged = true;
}
void Update()
{
if (m_HasBoundaryChanged && (boundaryChanged != null))
{
m_HasBoundaryChanged = false;
boundaryChanged(new ARPlaneBoundaryChangedEventArgs(this));
}
}
NativeArray<Vector2> m_Boundary;
NativeArray<Vector2> m_OldBoundary;
bool m_HasBoundaryChanged;
}
}