Files
adriadri6972 d3d9c5f833 upload project
2025-07-31 15:21:08 +02:00

140 lines
5.4 KiB
C#

using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.XR.ARSubsystems;
namespace UnityEngine.XR.ARFoundation
{
/// <summary>
/// Represents a face detected by an AR device.
/// </summary>
/// <remarks>
/// Generated by the <see cref="ARFaceManager"/> when an AR device detects
/// a face in the environment.
/// </remarks>
[DisallowMultipleComponent]
[DefaultExecutionOrder(ARUpdateOrder.k_Face)]
[HelpURL(typeof(ARFace))]
public sealed class ARFace : ARTrackable<XRFace, ARFace>
{
/// <summary>
/// Invoked when the face is updated. If face meshes are supported, there will be
/// updated <see cref="vertices"/>, <see cref="normals"/>, <see cref="indices"/>, and
/// <see cref="uvs"/>.
/// </summary>
public event Action<ARFaceUpdatedEventArgs> updated;
/// <summary>
/// The vertices representing the face mesh. Check for existence with <c>vertices.IsCreated</c>.
/// This array is parallel to <see cref="normals"/> and <see cref="uvs"/>. Vertices are
/// provided in face space, that is, relative to this <see cref="ARFace"/>'s local
/// position and rotation.
/// </summary>
public NativeArray<Vector3> vertices => GetUndisposable(m_FaceMesh.vertices);
/// <summary>
/// The normals representing the face mesh. Check for existence with <c>normals.IsCreated</c>.
/// This array is parallel to <see cref="vertices"/> and <see cref="uvs"/>.
/// </summary>
public unsafe NativeArray<Vector3> normals => GetUndisposable(m_FaceMesh.normals);
/// <summary>
/// The indices defining the triangles of the face mesh. Check for existence with <c>indices.IsCreated</c>.
/// The are three times as many indices as triangles, so this will always be a multiple of 3.
/// </summary>
public NativeArray<int> indices => GetUndisposable(m_FaceMesh.indices);
/// <summary>
/// The texture coordinates representing the face mesh. Check for existence with <c>uvs.IsCreated</c>.
/// This array is parallel to <see cref="vertices"/> and <see cref="normals"/>.
/// </summary>
public NativeArray<Vector2> uvs => GetUndisposable(m_FaceMesh.uvs);
/// <summary>
/// The [transform](https://docs.unity3d.com/ScriptReference/Transform.html) of the left eye of the face, or `null` if there is no data for the left eye.
/// </summary>
public Transform leftEye { get; private set; }
/// <summary>
/// The [transform](https://docs.unity3d.com/ScriptReference/Transform.html) of the right eye of the face, or `null` if there is no data for the right eye.
/// </summary>
public Transform rightEye { get; private set; }
/// <summary>
/// The [transform](https://docs.unity3d.com/ScriptReference/Transform.html) representing the point where the eyes are fixated or `null` if there is no fixation data.
/// </summary>
public Transform fixationPoint { get; private set; }
void Update()
{
if (m_Updated && updated != null)
{
updated(new ARFaceUpdatedEventArgs(this));
m_Updated = false;
}
}
void OnDestroy()
{
m_FaceMesh.Dispose();
}
// Creates an alias to the same array, but the caller cannot Dispose it.
internal static unsafe NativeArray<T> GetUndisposable<T>(NativeArray<T> disposable) where T : struct
{
if (!disposable.IsCreated)
return default;
var undisposable = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<T>(
disposable.GetUnsafePtr(),
disposable.Length,
Allocator.None);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(
ref undisposable,
NativeArrayUnsafeUtility.GetAtomicSafetyHandle(disposable));
#endif
return undisposable;
}
internal void UpdateMesh(XRFaceSubsystem subsystem)
{
subsystem.GetFaceMesh(sessionRelativeData.trackableId, Allocator.Persistent, ref m_FaceMesh);
m_Updated = true;
}
internal void UpdateEyes()
{
Transform CreateGameObject(string nameOfNewGameObject)
{
var newTransform = new GameObject(nameOfNewGameObject).transform;
newTransform.SetParent(transform, worldPositionStays: false);
return newTransform;
}
if (leftEye == null && rightEye == null && fixationPoint == null)
{
leftEye = CreateGameObject("Left eye");
rightEye = CreateGameObject("Right eye");
fixationPoint = CreateGameObject("Fixation point");
}
UpdateTransformFromPose(leftEye, sessionRelativeData.leftEyePose);
UpdateTransformFromPose(rightEye, sessionRelativeData.rightEyePose);
fixationPoint.localPosition = sessionRelativeData.fixationPoint;
}
static void UpdateTransformFromPose(Transform eyeTransform, Pose eyePose)
{
eyeTransform.localPosition = eyePose.position;
eyeTransform.localRotation = eyePose.rotation;
}
XRFaceMesh m_FaceMesh;
bool m_Updated;
}
}