using System.Runtime.InteropServices; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.Scripting; using UnityEngine.XR.ARSubsystems; namespace UnityEngine.XR.ARKit { /// /// Registration utility to register the ARKit human body subsystem. /// internal static class ARKitHumanBodyRegistration { /// /// Register the ARKit human body subsystem if iOS and not the editor. /// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Register() { #if UNITY_IOS && !UNITY_EDITOR const string k_SubsystemId = "ARKit-HumanBody"; XRHumanBodySubsystemCinfo humanBodySubsystemCinfo = new XRHumanBodySubsystemCinfo() { id = k_SubsystemId, implementationType = typeof(ARKitHumanBodySubsystem), supportsHumanBody2D = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodyPose2DEstimation(), supportsHumanBody3D = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodyPose3DEstimation(), supportsHumanBody3DScaleEstimation = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodyPose3DScaleEstimation(), supportsHumanStencilImage = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodySegmentationStencil(), supportsHumanDepthImage = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodySegmentationDepth(), }; if (!XRHumanBodySubsystem.Register(humanBodySubsystemCinfo)) { Debug.LogErrorFormat("Cannot register the {0} subsystem", k_SubsystemId); } #endif } /// /// Container to wrap the native ARKit human body APIs. /// static class NativeApi { [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodyPose2DEstimation(); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodyPose3DEstimation(); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodyPose3DScaleEstimation(); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodySegmentationStencil(); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodySegmentationDepth(); } } /// /// This subsystem provides implementing functionality for the XRHumanBodySubsystem class. /// [Preserve] class ARKitHumanBodySubsystem : XRHumanBodySubsystem { /// /// Create the implementation provider. /// /// /// The implementation provider. /// protected override Provider CreateProvider() { return new ARKitProvider(); } /// /// The implementation provider class. /// class ARKitProvider : XRHumanBodySubsystem.Provider { /// /// Construct the implementation provider. /// public ARKitProvider() => NativeApi.UnityARKit_HumanBodyProvider_Construct(); /// /// Start the provider. /// public override void Start() => NativeApi.UnityARKit_HumanBodyProvider_Start(); /// /// Stop the provider. /// public override void Stop() => NativeApi.UnityARKit_HumanBodyProvider_Stop(); /// /// Destroy the human body subsystem by first ensuring that the subsystem has been stopped and then /// destroying the provider. /// public override void Destroy() => NativeApi.UnityARKit_HumanBodyProvider_Destruct(); /// /// Sets whether human body pose 2D estimation is enabled. /// /// Whether the human body pose 2D estimation should be enabled. /// /// /// true if the human body pose 2D estimation is set to the given value. Otherwise, false. /// /// /// Current restrictions limit either human body pose estimation to be enabled or human segmentation images /// to be enabled. At this time, these features are mutually exclusive. /// public override bool TrySetHumanBodyPose2DEstimationEnabled(bool enabled) { return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanBodyPose2DEstimationEnabled(enabled); } /// /// Sets whether human body pose 3D estimation is enabled. /// /// Whether the human body pose 3D estimation should be enabled. /// /// /// true if the human body pose 3D estimation is set to the given value. Otherwise, false. /// /// /// Current restrictions limit either human body pose estimation to be enabled or human segmentation images /// to be enabled. At this time, these features are mutually exclusive. /// public override bool TrySetHumanBodyPose3DEstimationEnabled(bool enabled) { return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanBodyPose3DEstimationEnabled(enabled); } /// /// Sets whether 3D human body scale estimation is enabled. /// /// Whether the 3D human body scale estimation should be enabled. /// /// /// true if the 3D human body scale estimation is set to the given value. Otherwise, false. /// public override bool TrySetHumanBodyPose3DScaleEstimationEnabled(bool enabled) { return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanBodyPose3DScaleEstimationEnabled(enabled); } /// /// Set the human segmentation stencil mode. /// /// The mode for the human segmentation stencil. /// /// true if the method successfully set the human segmentation stencil mode. Otherwise, /// false. /// /// /// Current restrictions limit either human body pose estimation to be enabled or human segmentation images /// to be enabled. At this time, these features are mutually exclusive. /// public override bool TrySetHumanSegmentationStencilMode(HumanSegmentationMode humanSegmentationStencilMode) { return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanSegmentationStencilMode(humanSegmentationStencilMode); } /// /// Set the human segmentation depth mode. /// /// The mode for the human segmentation depth. /// /// true if the method successfully set the human segmentation depth mode. Otherwise, /// false. /// /// /// Current restrictions limit either human body pose estimation to be enabled or human segmentation images /// to be enabled. At this time, these features are mutually exclusive. /// public override bool TrySetHumanSegmentationDepthMode(HumanSegmentationMode humanSegmentationDepthMode) { return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanSegmentationDepthMode(humanSegmentationDepthMode); } /// /// Queries for the set of human body changes. /// /// The default human body. /// The memory allocator to use for the returns trackable changes. /// /// The set of human body changes. /// public override unsafe TrackableChanges GetChanges(XRHumanBody defaultHumanBody, Allocator allocator) { int numAddedHumanBodies; void* addedHumanBodiesPointer; int numUpdatedHumanBodies; void* updatedHumanBodiesPointer; int numRemovedHumanBodyIds; void* removedHumanBodyIdsPointer; int stride; var context = NativeApi.UnityARKit_HumanBodyProvider_AcquireChanges(out numAddedHumanBodies, out addedHumanBodiesPointer, out numUpdatedHumanBodies, out updatedHumanBodiesPointer, out numRemovedHumanBodyIds, out removedHumanBodyIdsPointer, out stride); try { // Wrap the navite pointers into a native array and then copy them into a separate native array enabled // with temporary allocations. return new TrackableChanges( addedHumanBodiesPointer, numAddedHumanBodies, updatedHumanBodiesPointer, numUpdatedHumanBodies, removedHumanBodyIdsPointer, numRemovedHumanBodyIds, defaultHumanBody, stride, allocator); } finally { NativeApi.UnityARKit_HumanBodyProvider_ReleaseChanges(context); } } /// /// Get the skeleton joints for the requested trackable identifier. /// /// The human body trackable identifier for which to query. /// The memory allocator to use for the returned arrays. /// The array of skeleton joints to update and returns. public override unsafe void GetSkeleton(TrackableId trackableId, Allocator allocator, ref NativeArray skeleton) { int numJoints; void* joints = NativeApi.UnityARKit_HumanBodyProvider_AcquireJoints(trackableId, out numJoints); try { if (joints == null) { numJoints = 0; } if (!skeleton.IsCreated || (skeleton.Length != numJoints)) { if (skeleton.IsCreated) { skeleton.Dispose(); } skeleton = new NativeArray(numJoints, allocator); } if (joints != null) { NativeArray tmp = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(joints, numJoints, Allocator.None); skeleton.CopyFrom(tmp); } } finally { NativeApi.UnityARKit_HumanBodyProvider_ReleaseJoints(joints); } } /// /// Get the human body pose 2D joints for the current frame. /// /// The default value for the human body pose 2D joint. /// The orientation of the device so that the joint positions may be /// adjusted as required. /// The allocator to use for the returned array memory. /// /// The array of human body pose 2D joints. /// /// /// The returned array may be empty if the system is not enabled or if the system does not detect a human /// body. /// public override unsafe NativeArray GetHumanBodyPose2DJoints(XRHumanBodyPose2DJoint defaultHumanBodyPose2DJoint, ScreenOrientation screenOrientation, Allocator allocator) { int length, elementSize; var joints = NativeApi.UnityARKit_HumanBodyProvider_AcquireHumanBodyPose2DJoints(screenOrientation, out length, out elementSize); try { var returnJoints = NativeCopyUtility.PtrToNativeArrayWithDefault(defaultHumanBodyPose2DJoint, joints, elementSize, length, allocator); return returnJoints; } finally { NativeApi.UnityARKit_HumanBodyProvider_ReleaseHumanBodyPose2DJoints(joints); } } /// /// Gets the human stencil texture descriptor. /// /// The human stencil texture descriptor to be populated, if /// available. /// /// true if the human stencil texture descriptor is available and is returned. Otherwise, /// false. /// public override bool TryGetHumanStencil(out XRTextureDescriptor humanStencilDescriptor) { return NativeApi.UnityARKit_HumanBodyProvider_TryGetHumanStencil(out humanStencilDescriptor); } /// /// Get the human depth texture descriptor. /// /// The human depth texture descriptor to be populated, if available /// /// /// true if the human depth texture descriptor is available and is returned. Otherwise, /// false. /// public override bool TryGetHumanDepth(out XRTextureDescriptor humanDepthDescriptor) { return NativeApi.UnityARKit_HumanBodyProvider_TryGetHumanDepth(out humanDepthDescriptor); } } /// /// Container to wrap the native ARKit human body APIs. /// static class NativeApi { [DllImport("__Internal")] public static extern void UnityARKit_HumanBodyProvider_Construct(); [DllImport("__Internal")] public static extern void UnityARKit_HumanBodyProvider_Start(); [DllImport("__Internal")] public static extern void UnityARKit_HumanBodyProvider_Stop(); [DllImport("__Internal")] public static extern void UnityARKit_HumanBodyProvider_Destruct(); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanBodyPose2DEstimationEnabled(bool enabled); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanBodyPose3DEstimationEnabled(bool enabled); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanBodyPose3DScaleEstimationEnabled(bool enabled); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanSegmentationStencilMode(HumanSegmentationMode humanSegmentationStencilMode); [DllImport("__Internal")] public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanSegmentationDepthMode(HumanSegmentationMode humanSegmentationDepthMode); [DllImport("__Internal")] public static extern unsafe void* UnityARKit_HumanBodyProvider_AcquireChanges(out int numAddedHumanBodies, out void* addedBodys, out int numUpdatedHumanBodies, out void* updatedBodys, out int numRemovedHumanBodyIds, out void* removedBodyIds, out int stride); [DllImport("__Internal")] public static extern unsafe void UnityARKit_HumanBodyProvider_ReleaseChanges(void* context); [DllImport("__Internal")] public static extern unsafe void* UnityARKit_HumanBodyProvider_AcquireJoints(TrackableId trackableId, out int numJoints); [DllImport("__Internal")] public static extern unsafe void UnityARKit_HumanBodyProvider_ReleaseJoints(void* joints); [DllImport("__Internal")] public static unsafe extern void* UnityARKit_HumanBodyProvider_AcquireHumanBodyPose2DJoints(ScreenOrientation screenOrientation, out int length, out int elementSize); [DllImport("__Internal")] public static unsafe extern void UnityARKit_HumanBodyProvider_ReleaseHumanBodyPose2DJoints(void* joints); [DllImport("__Internal")] public static unsafe extern bool UnityARKit_HumanBodyProvider_TryGetHumanStencil(out XRTextureDescriptor humanStencilDescriptor); [DllImport("__Internal")] public static unsafe extern bool UnityARKit_HumanBodyProvider_TryGetHumanDepth(out XRTextureDescriptor humanDepthDescriptor); } } }