213 lines
8.7 KiB
C#
213 lines
8.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Unity.Collections;
|
|
using UnityEngine.XR.ARSubsystems;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace UnityEngine.XR.ARFoundation
|
|
{
|
|
/// <summary>
|
|
/// The manager for the human body subsystem.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Related information: <a href="xref:arfoundation-body-tracking">Body tracking</a>
|
|
/// </remarks>
|
|
[DisallowMultipleComponent]
|
|
[DefaultExecutionOrder(ARUpdateOrder.k_HumanBodyManager)]
|
|
[AddComponentMenu("XR/AR Foundation/AR Human Body Manager")]
|
|
[HelpURL("features/body-tracking")]
|
|
public sealed class ARHumanBodyManager :
|
|
ARTrackableManager<XRHumanBodySubsystem, XRHumanBodySubsystemDescriptor, XRHumanBodySubsystem.Provider, XRHumanBody, ARHumanBody>
|
|
{
|
|
[SerializeField, FormerlySerializedAs("m_HumanBodyPose2DEstimationEnabled")]
|
|
[Tooltip("Whether to estimate the 2D pose for any human bodies detected.")]
|
|
bool m_Pose2D = true;
|
|
|
|
/// <summary>
|
|
/// Whether 2D human pose estimation is enabled. While
|
|
/// <see cref="pose2DRequested"/> tells you whether 2D pose
|
|
/// estimation has been requested, this property tells you
|
|
/// whether 2D pose estimation is currently active in the subsystem.
|
|
/// </summary>
|
|
public bool pose2DEnabled => subsystem?.pose2DEnabled ?? false;
|
|
|
|
/// <summary>
|
|
/// Whether 2D human pose estimation is requested.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if 2D human pose estimation is requested. Otherwise, <c>false</c>.
|
|
/// </value>
|
|
public bool pose2DRequested
|
|
{
|
|
get => subsystem?.pose2DRequested ?? m_Pose2D;
|
|
set
|
|
{
|
|
m_Pose2D = value;
|
|
if (enabled && subsystem != null)
|
|
{
|
|
subsystem.pose2DRequested = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializeField, FormerlySerializedAs("m_HumanBodyPose3DEstimationEnabled")]
|
|
[Tooltip("Whether to estimate the 3D pose for any human bodies detected.")]
|
|
bool m_Pose3D = true;
|
|
|
|
/// <summary>
|
|
/// Whether 3D human pose estimation is requested.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if 3D human pose estimation is requested. Otherwise, <c>false</c>.
|
|
/// </value>
|
|
public bool pose3DRequested
|
|
{
|
|
get => subsystem?.pose3DRequested ?? m_Pose3D;
|
|
set
|
|
{
|
|
m_Pose3D = value;
|
|
if (enabled && subsystem != null)
|
|
{
|
|
subsystem.pose3DRequested = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Whether 3D human pose estimation is enabled.
|
|
/// </summary>
|
|
public bool pose3DEnabled => subsystem?.pose3DEnabled ?? false;
|
|
|
|
[SerializeField, FormerlySerializedAs("m_HumanBodyPose3DScaleEstimationEnabled")]
|
|
[Tooltip("Whether to estimate the 3D pose for any human bodies detected.")]
|
|
bool m_Pose3DScaleEstimation = false;
|
|
|
|
/// <summary>
|
|
/// Whether 3D human body scale estimation is requested.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if 3D human body scale estimation is requested. Otherwise, <c>false</c>.
|
|
/// </value>
|
|
public bool pose3DScaleEstimationRequested
|
|
{
|
|
get => subsystem?.pose3DScaleEstimationRequested ?? m_Pose3DScaleEstimation;
|
|
set
|
|
{
|
|
m_Pose3DScaleEstimation = value;
|
|
if (enabled && subsystem != null)
|
|
{
|
|
subsystem.pose3DScaleEstimationRequested = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Whether 3D human body scale estimation is enabled.
|
|
/// </summary>
|
|
public bool pose3DScaleEstimationEnabled => subsystem?.pose3DScaleEstimationEnabled ?? false;
|
|
|
|
/// <summary>
|
|
/// The Prefab object to instantiate at the location of the human body origin.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The Prefab object to instantiate at the location of the human body origin.
|
|
/// </value>
|
|
public GameObject humanBodyPrefab { get => m_HumanBodyPrefab; set => m_HumanBodyPrefab = value; }
|
|
|
|
[SerializeField]
|
|
[Tooltip("The prefab to instantiate at the origin for the detected human body if human body pose estimation is enabled.")]
|
|
GameObject m_HumanBodyPrefab;
|
|
|
|
/// <summary>
|
|
/// The name for any generated GameObjects.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The name for any generated GameObjects.
|
|
/// </value>
|
|
protected override string gameObjectName => "ARHumanBody";
|
|
|
|
/// <summary>
|
|
/// The event that is fired when a change to the detected human bodies is reported.
|
|
/// </summary>
|
|
[Obsolete("humanBodiesChanged has been deprecated in AR Foundation version 6.0. Use trackablesChanged instead.", false)]
|
|
public event Action<ARHumanBodiesChangedEventArgs> humanBodiesChanged;
|
|
|
|
/// <summary>
|
|
/// Gets the Prefab object to instantiate at the location of the trackable.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A GameObject to instantiate at the location of the trackable, or <c>null</c>.
|
|
/// </returns>
|
|
protected override GameObject GetPrefab() => m_HumanBodyPrefab;
|
|
|
|
/// <summary>
|
|
/// Get the human body matching the trackable identifier.
|
|
/// </summary>
|
|
/// <param name="trackableId">The trackable identifier for querying a human body trackable.</param>
|
|
/// <returns>
|
|
/// The human body trackable, if found. Otherwise, <c>null</c>.
|
|
/// </returns>
|
|
public ARHumanBody GetHumanBody(TrackableId trackableId) => m_Trackables.TryGetValue(trackableId, out ARHumanBody humanBody) ? humanBody : null;
|
|
|
|
/// <summary>
|
|
/// Gets the human body pose 2D joints for the current frame.
|
|
/// </summary>
|
|
/// <param name="allocator">The allocator to use for the returned array memory.</param>
|
|
/// <returns>
|
|
/// The array of body pose 2D joints.
|
|
/// </returns>
|
|
/// <remarks>
|
|
/// The returned array might be empty if the system is not enabled for human body pose 2D or if the system
|
|
/// does not detect a human in the camera image.
|
|
/// </remarks>
|
|
/// <exception cref="System.NotSupportedException">Thrown if the implementation does not support human body
|
|
/// pose 2D.</exception>
|
|
public NativeArray<XRHumanBodyPose2DJoint> GetHumanBodyPose2DJoints(Allocator allocator)
|
|
=> ((subsystem == null) ? new NativeArray<XRHumanBodyPose2DJoint>(0, allocator)
|
|
: subsystem.GetHumanBodyPose2DJoints(allocator));
|
|
|
|
/// <summary>
|
|
/// Callback before the subsystem is started (but after it is created).
|
|
/// </summary>
|
|
protected override void OnBeforeStart()
|
|
{
|
|
subsystem.pose2DRequested = m_Pose2D;
|
|
subsystem.pose3DRequested = m_Pose3D;
|
|
subsystem.pose3DScaleEstimationRequested = m_Pose3DScaleEstimation;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Callback as the manager is being destroyed.
|
|
/// </summary>
|
|
protected override void OnDestroy()
|
|
{
|
|
base.OnDestroy();
|
|
m_Trackables.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Callback after the session relative data has been set to update the skeleton for the human body.
|
|
/// </summary>
|
|
/// <param name="arBody">The human body trackable being updated.</param>
|
|
/// <param name="xrBody">The raw human body data from the subsystem.</param>
|
|
protected override void OnAfterSetSessionRelativeData(ARHumanBody arBody, XRHumanBody xrBody)
|
|
=> arBody.UpdateSkeleton(subsystem);
|
|
|
|
/// <summary>
|
|
/// Callback when the trackable deltas are being reported.
|
|
/// </summary>
|
|
/// <param name="added">The list of human bodies added to the set of trackables.</param>
|
|
/// <param name="updated">The list of human bodies updated in the set of trackables.</param>
|
|
/// <param name="removed">The list of human bodies removed to the set of trackables.</param>
|
|
[Obsolete("OnTrackablesChanged() has been deprecated in AR Foundation version 6.0.", false)]
|
|
protected override void OnTrackablesChanged(List<ARHumanBody> added, List<ARHumanBody> updated, List<ARHumanBody> removed)
|
|
{
|
|
if (humanBodiesChanged != null)
|
|
{
|
|
using (new ScopedProfiler("OnHumanBodiesChanged"))
|
|
humanBodiesChanged?.Invoke(new ARHumanBodiesChangedEventArgs(added, updated, removed));
|
|
}
|
|
}
|
|
}
|
|
}
|