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