version 2.0.0

This commit is contained in:
srl87
2023-09-14 18:17:47 +08:00
parent 13e9d00b37
commit ca21423a06
953 changed files with 125887 additions and 21229 deletions

View File

@@ -0,0 +1,820 @@
// "VIVE SDK
// © 2020 HTC Corporation. All Rights Reserved.
//
// Unless otherwise required by copyright law and practice,
// upon the execution of HTC SDK license agreement,
// HTC grants you access to and use of the VIVE SDK(s).
// You shall fully comply with all of HTCs SDK license agreement terms and
// conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You."
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine;
using System.Runtime.InteropServices;
using System;
using System.Linq;
using UnityEngine.XR;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.XR.OpenXR.Features;
#endif
namespace VIVE.OpenXR.Hand
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "VIVE XR Hand Tracking",
BuildTargetGroups = new[] { BuildTargetGroup.Android , BuildTargetGroup.Standalone },
Company = "HTC",
Desc = "Support the Hand Tracking extension.",
DocumentationLink = "..\\Documentation",
OpenxrExtensionStrings = kOpenxrExtensionString,
Version = "4.0.0",
FeatureId = featureId)]
#endif
public class ViveHandTracking : OpenXRFeature
{
const string LOG_TAG = "VIVE.OpenXR.Hand.ViveHandTracking";
void DEBUG(string msg) { Debug.Log(LOG_TAG + " " + msg); }
void WARNING(string msg) { Debug.LogWarning(LOG_TAG + " " + msg); }
void ERROR(string msg) { Debug.LogError(LOG_TAG + " " + msg); }
/// <summary>
/// OpenXR specification <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_hand_tracking">12.29 XR_EXT_hand_tracking</see>.
/// </summary>
public const string kOpenxrExtensionString = "XR_EXT_hand_tracking";
/// <summary>
/// The feature id string. This is used to give the feature a well known id for reference.
/// </summary>
public const string featureId = "vive.openxr.feature.hand.tracking";
#region OpenXR Life Cycle
private bool m_XrInstanceCreated = false;
private XrInstance m_XrInstance = 0;
/// <summary>
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateInstance">xrCreateInstance</see> is done.
/// </summary>
/// <param name="xrInstance">The created instance.</param>
/// <returns>True for valid <see cref="XrInstance">XrInstance</see></returns>
protected override bool OnInstanceCreate(ulong xrInstance)
{
if (!OpenXRRuntime.IsExtensionEnabled(kOpenxrExtensionString))
{
WARNING("OnInstanceCreate() " + kOpenxrExtensionString + " is NOT enabled.");
return false;
}
m_XrInstanceCreated = true;
m_XrInstance = xrInstance;
DEBUG("OnInstanceCreate() " + m_XrInstance);
return GetXrFunctionDelegates(m_XrInstance);
}
/// <summary>
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrDestroyInstance">xrDestroyInstance</see> is done.
/// </summary>
/// <param name="xrInstance">The instance to destroy.</param>
protected override void OnInstanceDestroy(ulong xrInstance)
{
m_XrInstanceCreated = false;
m_XrInstance = 0;
DEBUG("OnInstanceDestroy() " + xrInstance);
}
private XrSystemId m_XrSystemId = 0;
/// <summary>
/// Called when the <see cref="XrSystemId">XrSystemId</see> retrieved by <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrGetSystem">xrGetSystem</see> is changed.
/// </summary>
/// <param name="xrSystem">The system id.</param>
protected override void OnSystemChange(ulong xrSystem)
{
m_XrSystemId = xrSystem;
DEBUG("OnSystemChange() " + m_XrSystemId);
}
private bool m_XrSessionCreated = false;
private XrSession m_XrSession = 0;
private bool hasReferenceSpaceLocal = false, hasReferenceSpaceStage = false;
private XrSpace m_ReferenceSpaceLocal = 0, m_ReferenceSpaceStage = 0;
private bool hasLeftHandTracker = false, hasRightHandTracker = false;
private XrHandTrackerEXT leftHandTracker = 0, rightHandTracker = 0;
/// <summary>
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateSession">xrCreateSession</see> is done.
/// </summary>
/// <param name="xrSession">The created session ID.</param>
protected override void OnSessionCreate(ulong xrSession)
{
m_XrSession = xrSession;
m_XrSessionCreated = true;
DEBUG("OnSessionCreate() " + m_XrSession);
// Enumerate supported reference space types and create the XrSpace.
XrReferenceSpaceType[] spaces = new XrReferenceSpaceType[Enum.GetNames(typeof(XrReferenceSpaceType)).Count()];
UInt32 spaceCountOutput;
#pragma warning disable 0618
if (EnumerateReferenceSpaces(
spaceCapacityInput: 0,
spaceCountOutput: out spaceCountOutput,
spaces: out spaces[0]) == XrResult.XR_SUCCESS)
#pragma warning restore 0618
{
DEBUG("OnSessionCreate() spaceCountOutput: " + spaceCountOutput);
Array.Resize(ref spaces, (int)spaceCountOutput);
#pragma warning disable 0618
if (EnumerateReferenceSpaces(
spaceCapacityInput: spaceCountOutput,
spaceCountOutput: out spaceCountOutput,
spaces: out spaces[0]) == XrResult.XR_SUCCESS)
#pragma warning restore 0618
{
XrReferenceSpaceCreateInfo createInfo;
/// Create m_ReferenceSpaceLocal
if (IsReferenceSpaceTypeSupported(spaceCountOutput, spaces, XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_LOCAL))
{
createInfo.type = XrStructureType.XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
createInfo.next = IntPtr.Zero;
createInfo.referenceSpaceType = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_LOCAL;//referenceSpaceType;
createInfo.poseInReferenceSpace.orientation = new XrQuaternionf(0, 0, 0, 1);
createInfo.poseInReferenceSpace.position = new XrVector3f(0, 0, 0);
#pragma warning disable 0618
if (CreateReferenceSpace(
createInfo: ref createInfo,
space: out m_ReferenceSpaceLocal) == XrResult.XR_SUCCESS)
#pragma warning restore 0618
{
hasReferenceSpaceLocal = true;
DEBUG("OnSessionCreate() CreateReferenceSpace LOCAL: " + m_ReferenceSpaceLocal);
}
else
{
ERROR("OnSessionCreate() CreateReferenceSpace LOCAL failed.");
}
}
/// Create m_ReferenceSpaceStage
if (IsReferenceSpaceTypeSupported(spaceCountOutput, spaces, XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_STAGE))
{
createInfo.type = XrStructureType.XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
createInfo.next = IntPtr.Zero;
createInfo.referenceSpaceType = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_STAGE;
createInfo.poseInReferenceSpace.orientation = new XrQuaternionf(0, 0, 0, 1);
createInfo.poseInReferenceSpace.position = new XrVector3f(0, 0, 0);
#pragma warning disable 0618
if (CreateReferenceSpace(
createInfo: ref createInfo,
space: out m_ReferenceSpaceStage) == XrResult.XR_SUCCESS)
#pragma warning restore 0618
{
hasReferenceSpaceStage = true;
DEBUG("OnSessionCreate() CreateReferenceSpace STAGE: " + m_ReferenceSpaceStage);
}
else
{
ERROR("OnSessionCreate() CreateReferenceSpace STAGE failed.");
}
}
}
else
{
ERROR("OnSessionCreate() EnumerateReferenceSpaces(" + spaceCountOutput + ") failed.");
}
}
else
{
ERROR("OnSessionCreate() EnumerateReferenceSpaces(0) failed.");
}
{ // left hand tracker
if (CreateHandTrackers(true, out XrHandTrackerEXT value))
{
hasLeftHandTracker = true;
leftHandTracker = value;
DEBUG("OnSessionCreate() leftHandTracker " + leftHandTracker);
}
}
{ // right hand tracker
if (CreateHandTrackers(false, out XrHandTrackerEXT value))
{
hasRightHandTracker = true;
rightHandTracker = value;
DEBUG("OnSessionCreate() rightHandTracker " + rightHandTracker);
}
}
}
/// <summary>
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrDestroySession">xrDestroySession</see> is done.
/// </summary>
/// <param name="xrSession">The session ID to destroy.</param>
protected override void OnSessionDestroy(ulong xrSession)
{
DEBUG("OnSessionDestroy() " + xrSession);
// Reference Space is binding with xrSession so we destroy the xrSpace when xrSession is destroyed.
if (hasReferenceSpaceLocal)
{
#pragma warning disable 0618
if (DestroySpace(m_ReferenceSpaceLocal) == XrResult.XR_SUCCESS)
#pragma warning restore 0618
{
DEBUG("OnSessionDestroy() DestroySpace LOCAL " + m_ReferenceSpaceLocal);
m_ReferenceSpaceLocal = 0;
}
else
{
ERROR("OnSessionDestroy() DestroySpace LOCAL " + m_ReferenceSpaceLocal + " failed.");
}
hasReferenceSpaceLocal = false;
}
if (hasReferenceSpaceStage)
{
#pragma warning disable 0618
if (DestroySpace(m_ReferenceSpaceStage) == XrResult.XR_SUCCESS)
#pragma warning restore 0618
{
DEBUG("OnSessionDestroy() DestroySpace STAGE " + m_ReferenceSpaceStage);
m_ReferenceSpaceStage = 0;
}
else
{
ERROR("OnSessionDestroy() DestroySpace STAGE " + m_ReferenceSpaceStage + " failed.");
}
hasReferenceSpaceStage = false;
}
// Hand Tracking is binding with xrSession so we destroy the hand trackers when xrSession is destroyed.
if (hasLeftHandTracker)
{
if (DestroyHandTrackerEXT(leftHandTracker) == XrResult.XR_SUCCESS)
{
DEBUG("OnSessionDestroy() Left DestroyHandTrackerEXT " + leftHandTracker);
}
else
{
ERROR("OnSessionDestroy() Left DestroyHandTrackerEXT " + leftHandTracker + " failed.");
}
hasLeftHandTracker = false;
}
if (hasRightHandTracker)
{
if (DestroyHandTrackerEXT(rightHandTracker) == XrResult.XR_SUCCESS)
{
DEBUG("OnSessionDestroy() Right DestroyHandTrackerEXT " + rightHandTracker);
}
else
{
ERROR("OnSessionDestroy() Right DestroyHandTrackerEXT " + rightHandTracker + " failed.");
}
hasRightHandTracker = false;
}
m_XrSession = 0;
m_XrSessionCreated = false;
}
#endregion
#region OpenXR function delegates
/// xrGetInstanceProcAddr
OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddr;
/// xrGetSystemProperties
OpenXRHelper.xrGetSystemPropertiesDelegate xrGetSystemProperties;
/// <summary>
/// An application can call GetSystemProperties to retrieve information about the system such as vendor ID, system name, and graphics and tracking properties.
/// </summary>
/// <param name="properties">Points to an instance of the XrSystemProperties structure, that will be filled with returned information.</param>
/// <returns>XR_SUCCESS for success.</returns>
[Obsolete("This function will become private in next release")]
public XrResult GetSystemProperties(ref XrSystemProperties properties)
{
if (!m_XrSessionCreated)
{
ERROR("GetSystemProperties() XR_ERROR_SESSION_LOST.");
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
ERROR("GetSystemProperties() XR_ERROR_INSTANCE_LOST.");
return XrResult.XR_ERROR_INSTANCE_LOST;
}
return xrGetSystemProperties(m_XrInstance, m_XrSystemId, ref properties);
}
/// xrEnumerateReferenceSpaces
OpenXRHelper.xrEnumerateReferenceSpacesDelegate xrEnumerateReferenceSpaces;
/// <summary>
/// Enumerates the set of reference space types that this runtime supports for a given session. Runtimes must always return identical buffer contents from this enumeration for the lifetime of the session.
/// </summary>
/// <param name="spaceCapacityInput">The capacity of the spaces array, or 0 to indicate a request to retrieve the required capacity.</param>
/// <param name="spaceCountOutput">A pointer to the count of spaces written, or a pointer to the required capacity in the case that spaceCapacityInput is insufficient.</param>
/// <param name="spaces">A pointer to an application-allocated array that will be filled with the enumerant of each supported reference space. It can be NULL if spaceCapacityInput is 0.</param>
/// <returns>XR_SUCCESS for success.</returns>
[Obsolete("This function will become private in next release")]
public XrResult EnumerateReferenceSpaces(UInt32 spaceCapacityInput, out UInt32 spaceCountOutput, out XrReferenceSpaceType spaces)
{
if (!m_XrSessionCreated)
{
ERROR("EnumerateReferenceSpaces() XR_ERROR_SESSION_LOST.");
spaceCountOutput = 0;
spaces = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT;
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
ERROR("EnumerateReferenceSpaces() XR_ERROR_SESSION_LOST.");
spaceCountOutput = 0;
spaces = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT;
return XrResult.XR_ERROR_INSTANCE_LOST;
}
return xrEnumerateReferenceSpaces(m_XrSession, spaceCapacityInput, out spaceCountOutput, out spaces);
}
/// xrCreateReferenceSpace
OpenXRHelper.xrCreateReferenceSpaceDelegate xrCreateReferenceSpace;
/// <summary>
/// Creates an <see cref="XrSpace">XrSpace</see> handle based on a chosen reference space. Application can provide an <see cref="XrPosef">XrPosef</see> to define the position and orientation of the new spaces origin within the natural reference frame of the reference space.
/// </summary>
/// <param name="createInfo">The XrReferenceSpaceCreateInfo used to specify the space.</param>
/// <param name="space">The returned XrSpace handle.</param>
/// <returns>XR_SUCCESS for success.</returns>
[Obsolete("This function will become private in next release")]
public XrResult CreateReferenceSpace(ref XrReferenceSpaceCreateInfo createInfo, out XrSpace space)
{
if (!m_XrSessionCreated)
{
ERROR("CreateReferenceSpace() XR_ERROR_SESSION_LOST.");
space = 0;
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
ERROR("CreateReferenceSpace() XR_ERROR_INSTANCE_LOST.");
space = 0;
return XrResult.XR_ERROR_INSTANCE_LOST;
}
return xrCreateReferenceSpace(m_XrSession, ref createInfo, out space);
}
/// xrDestroySpace
OpenXRHelper.xrDestroySpaceDelegate xrDestroySpace;
/// <summary>
/// <see cref="XrSpace">XrSpace</see> handles are destroyed using DestroySpace. The runtime may still use this space if there are active dependencies (e.g, compositions in progress).
/// </summary>
/// <param name="space">Must be a valid XrSpace handle.</param>
/// <returns>XR_SUCCESS for success.</returns>
[Obsolete("This function will become private in next release")]
public XrResult DestroySpace(XrSpace space)
{
if (!m_XrSessionCreated)
{
ERROR("DestroySpace() XR_ERROR_SESSION_LOST.");
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
ERROR("DestroySpace() XR_ERROR_INSTANCE_LOST.");
return XrResult.XR_ERROR_INSTANCE_LOST;
}
return xrDestroySpace(space);
}
/// xrCreateHandTrackerEXT
ViveHandTrackingHelper.xrCreateHandTrackerEXTDelegate xrCreateHandTrackerEXT;
/// <summary>
/// An application can create an <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> handle using CreateHandTrackerEXT function.
/// </summary>
/// <param name="createInfo">The XrHandTrackerCreateInfoEXT used to specify the hand tracker.</param>
/// <param name="handTracker">The returned XrHandTrackerEXT handle.</param>
/// <returns>XR_SUCCESS for success.</returns>
public XrResult CreateHandTrackerEXT(ref XrHandTrackerCreateInfoEXT createInfo, out XrHandTrackerEXT handTracker)
{
if (!m_XrSessionCreated)
{
ERROR("CreateHandTrackerEXT() XR_ERROR_SESSION_LOST.");
handTracker = 0;
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
ERROR("CreateHandTrackerEXT() XR_ERROR_INSTANCE_LOST.");
handTracker = 0;
return XrResult.XR_ERROR_INSTANCE_LOST;
}
if (createInfo.hand == XrHandEXT.XR_HAND_LEFT_EXT && hasLeftHandTracker)
{
DEBUG("CreateHandTrackerEXT() Left tracker " + leftHandTracker + " already created.");
handTracker = leftHandTracker;
return XrResult.XR_SUCCESS;
}
if (createInfo.hand == XrHandEXT.XR_HAND_RIGHT_EXT && hasRightHandTracker)
{
DEBUG("CreateHandTrackerEXT() Right tracker " + rightHandTracker + " already created.");
handTracker = rightHandTracker;
return XrResult.XR_SUCCESS;
}
return xrCreateHandTrackerEXT(m_XrSession, ref createInfo, out handTracker);
}
/// xrDestroyHandTrackerEXT
ViveHandTrackingHelper.xrDestroyHandTrackerEXTDelegate xrDestroyHandTrackerEXT;
/// <summary>
/// Releases the handTracker and the underlying resources when finished with hand tracking experiences.
/// </summary>
/// <param name="handTracker">An XrHandTrackerEXT previously created by <see cref="CreateHandTrackerEXT">CreateHandTrackerEXT</see>.</param>
/// <returns>XR_SUCCESS for success.</returns>
public XrResult DestroyHandTrackerEXT(XrHandTrackerEXT handTracker)
{
if (!m_XrSessionCreated)
{
ERROR("DestroyHandTrackerEXT() XR_ERROR_SESSION_LOST.");
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
ERROR("DestroyHandTrackerEXT() XR_ERROR_INSTANCE_LOST.");
return XrResult.XR_ERROR_INSTANCE_LOST;
}
return xrDestroyHandTrackerEXT(handTracker);
}
/// xrLocateHandJointsEXT
ViveHandTrackingHelper.xrLocateHandJointsEXTDelegate xrLocateHandJointsEXT;
/// <summary>
/// The LocateHandJointsEXT function locates an array of hand joints to a base space at given time.
/// </summary>
/// <param name="handTracker">An <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> previously created by <see cref="ViveHandTracking.CreateHandTrackerEXT(ref XrHandTrackerCreateInfoEXT, out XrHandTrackerEXT)">CreateHandTrackerEXT</see>.</param>
/// <param name="locateInfo">A pointer to <see cref="XrHandJointsLocateInfoEXT">XrHandJointsLocateInfoEXT</see> describing information to locate hand joints.</param>
/// <param name="locations">A pointer to <see cref="XrHandJointLocationsEXT">XrHandJointLocationsEXT</see> receiving the returned hand joint locations.</param>
/// <returns></returns>
public XrResult LocateHandJointsEXT(XrHandTrackerEXT handTracker, XrHandJointsLocateInfoEXT locateInfo, ref XrHandJointLocationsEXT locations)
{
if (!m_XrSessionCreated)
{
ERROR("LocateHandJointsEXT() XR_ERROR_SESSION_LOST.");
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
ERROR("LocateHandJointsEXT() XR_ERROR_INSTANCE_LOST.");
return XrResult.XR_ERROR_INSTANCE_LOST;
}
return xrLocateHandJointsEXT(handTracker, locateInfo, ref locations);
}
private bool GetXrFunctionDelegates(XrInstance xrInstance)
{
/// xrGetInstanceProcAddr
if (xrGetInstanceProcAddr != null && xrGetInstanceProcAddr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrGetInstanceProcAddr.");
XrGetInstanceProcAddr = Marshal.GetDelegateForFunctionPointer(
xrGetInstanceProcAddr,
typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate)) as OpenXRHelper.xrGetInstanceProcAddrDelegate;
}
else
{
ERROR("xrGetInstanceProcAddr");
return false;
}
IntPtr funcPtr = IntPtr.Zero;
/// xrGetSystemProperties
if (XrGetInstanceProcAddr(xrInstance, "xrGetSystemProperties", out funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrGetSystemProperties.");
xrGetSystemProperties = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(OpenXRHelper.xrGetSystemPropertiesDelegate)) as OpenXRHelper.xrGetSystemPropertiesDelegate;
}
}
else
{
ERROR("xrGetSystemProperties");
return false;
}
/// xrEnumerateReferenceSpaces
if (XrGetInstanceProcAddr(xrInstance, "xrEnumerateReferenceSpaces", out funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrEnumerateReferenceSpaces.");
xrEnumerateReferenceSpaces = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(OpenXRHelper.xrEnumerateReferenceSpacesDelegate)) as OpenXRHelper.xrEnumerateReferenceSpacesDelegate;
}
}
else
{
ERROR("xrEnumerateReferenceSpaces");
return false;
}
/// xrCreateReferenceSpace
if (XrGetInstanceProcAddr(xrInstance, "xrCreateReferenceSpace", out funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrCreateReferenceSpace.");
xrCreateReferenceSpace = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(OpenXRHelper.xrCreateReferenceSpaceDelegate)) as OpenXRHelper.xrCreateReferenceSpaceDelegate;
}
}
else
{
ERROR("xrCreateReferenceSpace");
return false;
}
/// xrDestroySpace
if (XrGetInstanceProcAddr(xrInstance, "xrDestroySpace", out funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrDestroySpace.");
xrDestroySpace = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(OpenXRHelper.xrDestroySpaceDelegate)) as OpenXRHelper.xrDestroySpaceDelegate;
}
}
else
{
ERROR("xrDestroySpace");
return false;
}
/// xrCreateHandTrackerEXT
if (XrGetInstanceProcAddr(xrInstance, "xrCreateHandTrackerEXT", out funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrCreateHandTrackerEXT.");
xrCreateHandTrackerEXT = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(ViveHandTrackingHelper.xrCreateHandTrackerEXTDelegate)) as ViveHandTrackingHelper.xrCreateHandTrackerEXTDelegate;
}
}
else
{
ERROR("xrCreateHandTrackerEXT");
return false;
}
/// xrDestroyHandTrackerEXT
if (XrGetInstanceProcAddr(xrInstance, "xrDestroyHandTrackerEXT", out funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrDestroyHandTrackerEXT.");
xrDestroyHandTrackerEXT = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(ViveHandTrackingHelper.xrDestroyHandTrackerEXTDelegate)) as ViveHandTrackingHelper.xrDestroyHandTrackerEXTDelegate;
}
}
else
{
ERROR("xrDestroyHandTrackerEXT");
return false;
}
/// xrLocateHandJointsEXT
if (XrGetInstanceProcAddr(xrInstance, "xrLocateHandJointsEXT", out funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrLocateHandJointsEXT.");
xrLocateHandJointsEXT = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(ViveHandTrackingHelper.xrLocateHandJointsEXTDelegate)) as ViveHandTrackingHelper.xrLocateHandJointsEXTDelegate;
}
}
else
{
ERROR("xrLocateHandJointsEXT");
return false;
}
return true;
}
#endregion
static List<XRInputSubsystem> s_InputSubsystems = new List<XRInputSubsystem>();
/// <summary>
/// Retrieves the current tracking origin in Unity XR.
/// </summary>
/// <returns>The tracking origin in <see href="https://docs.unity3d.com/ScriptReference/XR.TrackingOriginModeFlags.html">TrackingOriginModeFlags</see></returns>
public TrackingOriginModeFlags GetTrackingOriginMode()
{
XRInputSubsystem subsystem = null;
SubsystemManager.GetInstances(s_InputSubsystems);
if (s_InputSubsystems.Count > 0)
{
subsystem = s_InputSubsystems[0];
}
if (subsystem != null)
{
return subsystem.GetTrackingOriginMode();
}
return TrackingOriginModeFlags.Unknown;
}
private bool IsReferenceSpaceTypeSupported(UInt32 spaceCountOutput, XrReferenceSpaceType[] spaces, XrReferenceSpaceType space)
{
bool support = false;
for (int i = 0; i < spaceCountOutput; i++)
{
DEBUG("IsReferenceSpaceTypeSupported() supported space[" + i + "]: " + spaces[i]);
if (spaces[i] == space) { support = true; }
}
return support;
}
XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties;
XrSystemProperties systemProperties;
private bool IsHandTrackingSupported()
{
bool ret = false;
if (!m_XrSessionCreated)
{
ERROR("IsHandTrackingSupported() session is not created.");
return ret;
}
handTrackingSystemProperties.type = XrStructureType.XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT;
systemProperties.type = XrStructureType.XR_TYPE_SYSTEM_PROPERTIES;
systemProperties.next = Marshal.AllocHGlobal(Marshal.SizeOf(handTrackingSystemProperties));
long offset = 0;
if (IntPtr.Size == 4)
offset = systemProperties.next.ToInt32();
else
offset = systemProperties.next.ToInt64();
IntPtr sys_hand_tracking_prop_ptr = new IntPtr(offset);
Marshal.StructureToPtr(handTrackingSystemProperties, sys_hand_tracking_prop_ptr, false);
#pragma warning disable 0618
if (GetSystemProperties(ref systemProperties) == XrResult.XR_SUCCESS)
#pragma warning restore 0618
{
if (IntPtr.Size == 4)
offset = systemProperties.next.ToInt32();
else
offset = systemProperties.next.ToInt64();
sys_hand_tracking_prop_ptr = new IntPtr(offset);
handTrackingSystemProperties = (XrSystemHandTrackingPropertiesEXT)Marshal.PtrToStructure(sys_hand_tracking_prop_ptr, typeof(XrSystemHandTrackingPropertiesEXT));
DEBUG("IsHandTrackingSupported() XrSystemHandTrackingPropertiesEXT.supportsHandTracking: " + handTrackingSystemProperties.supportsHandTracking);
ret = handTrackingSystemProperties.supportsHandTracking > 0;
}
else
{
ERROR("IsHandTrackingSupported() GetSystemProperties failed.");
}
Marshal.FreeHGlobal(systemProperties.next);
return ret;
}
private bool CreateHandTrackers(bool isLeft, out XrHandTrackerEXT handTracker)
{
if (!IsHandTrackingSupported())
{
ERROR("CreateHandTrackers() " + (isLeft ? "Left" : "Right") + " hand tracking is NOT supported.");
handTracker = 0;
return false;
}
XrHandTrackerCreateInfoEXT createInfo;
createInfo.type = XrStructureType.XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT;
createInfo.next = IntPtr.Zero;
createInfo.hand = isLeft ? XrHandEXT.XR_HAND_LEFT_EXT : XrHandEXT.XR_HAND_RIGHT_EXT;
createInfo.handJointSet = XrHandJointSetEXT.XR_HAND_JOINT_SET_DEFAULT_EXT;
var ret = CreateHandTrackerEXT(ref createInfo, out handTracker);
DEBUG("CreateHandTrackers() " + (isLeft ? "Left" : "Right") + " CreateHandTrackerEXT = " + ret);
return ret == XrResult.XR_SUCCESS;
}
private XrHandJointLocationEXT[] jointLocationsL = new XrHandJointLocationEXT[(int)XrHandJointEXT.XR_HAND_JOINT_MAX_ENUM_EXT];
private XrHandJointLocationEXT[] jointLocationsR = new XrHandJointLocationEXT[(int)XrHandJointEXT.XR_HAND_JOINT_MAX_ENUM_EXT];
private XrHandJointLocationsEXT locations = new XrHandJointLocationsEXT(XrStructureType.XR_TYPE_HAND_JOINT_LOCATIONS_EXT, IntPtr.Zero, false, 0, IntPtr.Zero);
public bool GetHandTrackingSpace(out XrSpace space)
{
space = 0;
TrackingOriginModeFlags origin = GetTrackingOriginMode();
if (origin == TrackingOriginModeFlags.Unknown || origin == TrackingOriginModeFlags.Unbounded) { return false; }
space = (origin == TrackingOriginModeFlags.Device ? m_ReferenceSpaceLocal : m_ReferenceSpaceStage);
return true;
}
/// <summary>
/// Retrieves the <see cref="XrHandJointLocationEXT"> XrHandJointLocationEXT </see> data.
/// </summary>
/// <param name="isLeft">Left or right hand.</param>
/// <param name="handJointLocation">Output parameter to retrieve <see cref="XrHandJointLocationEXT"> XrHandJointLocationEXT </see> data.</param>
/// <returns>True for valid data.</returns>
public bool GetJointLocations(bool isLeft, out XrHandJointLocationEXT[] handJointLocation)
{
bool ret = false;
handJointLocation = isLeft ? jointLocationsL : jointLocationsR;
if (isLeft && !hasLeftHandTracker) { return ret; }
if (!isLeft && !hasRightHandTracker) { return ret; }
TrackingOriginModeFlags origin = GetTrackingOriginMode();
if (origin == TrackingOriginModeFlags.Unknown || origin == TrackingOriginModeFlags.Unbounded) { return ret; }
XrSpace baseSpace = (origin == TrackingOriginModeFlags.Device ? m_ReferenceSpaceLocal : m_ReferenceSpaceStage);
/// Configures XrHandJointsLocateInfoEXT
XrHandJointsLocateInfoEXT locateInfo = new XrHandJointsLocateInfoEXT(
in_type: XrStructureType.XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT,
in_next: IntPtr.Zero,
in_baseSpace: baseSpace,
in_time: 1);//
/// Configures XrHandJointLocationsEXT
locations.type = XrStructureType.XR_TYPE_HAND_JOINT_LOCATIONS_EXT;
locations.next = IntPtr.Zero;
locations.isActive = false;
locations.jointCount = (uint)(isLeft ? jointLocationsL.Length : jointLocationsR.Length);
XrHandJointLocationEXT joint_location_ext_type = default(XrHandJointLocationEXT);
int jointLocationsLength = isLeft ? jointLocationsL.Length : jointLocationsR.Length;
locations.jointLocations = Marshal.AllocHGlobal(Marshal.SizeOf(joint_location_ext_type) * jointLocationsLength);
long offset = 0;
/*if (IntPtr.Size == 4)
offset = locations.jointLocations.ToInt32();
else
offset = locations.jointLocations.ToInt64();
for (int i = 0; i < jointLocationsLength; i++)
{
IntPtr joint_location_ext_ptr = new IntPtr(offset);
if (isLeft)
Marshal.StructureToPtr(jointLocationsL[i], joint_location_ext_ptr, false);
else
Marshal.StructureToPtr(jointLocationsR[i], joint_location_ext_ptr, false);
offset += Marshal.SizeOf(joint_location_ext_type);
}*/
if (LocateHandJointsEXT(
handTracker: (isLeft ? leftHandTracker : rightHandTracker),
locateInfo: locateInfo,
locations: ref locations) == XrResult.XR_SUCCESS)
{
if (locations.isActive)
{
if (IntPtr.Size == 4)
offset = locations.jointLocations.ToInt32();
else
offset = locations.jointLocations.ToInt64();
for (int i = 0; i < locations.jointCount; i++)
{
IntPtr joint_location_ext_ptr = new IntPtr(offset);
if (isLeft)
jointLocationsL[i] = (XrHandJointLocationEXT)Marshal.PtrToStructure(joint_location_ext_ptr, typeof(XrHandJointLocationEXT));
else
jointLocationsR[i] = (XrHandJointLocationEXT)Marshal.PtrToStructure(joint_location_ext_ptr, typeof(XrHandJointLocationEXT));
offset += Marshal.SizeOf(joint_location_ext_type);
}
// ToDo: locationFlags?
handJointLocation = isLeft ? jointLocationsL : jointLocationsR;
ret = true;
}
}
Marshal.FreeHGlobal(locations.jointLocations);
return ret;
}
}
}