add package files

This commit is contained in:
VR164000
2023-06-15 09:52:08 +08:00
parent 06d41412be
commit a0b3b91879
382 changed files with 44971 additions and 0 deletions

View File

@@ -0,0 +1,293 @@
using System;
using UnityEngine;
using UnityEngine.XR.OpenXR;
namespace VIVE.HandTracking
{
public static class HandManager
{
private class HandData
{
public bool isStarted;
public XrHandEXT hand;
public ulong trackerHandle;
public bool isActive;
public int jointUpdatedFrame = -1;
public XrHandJointLocationEXT[] joints = new XrHandJointLocationEXT[(int)XrHandJointEXT.XR_HAND_JOINT_MAX_ENUM_EXT];
public XrHandJointVelocityEXT[] velocities = new XrHandJointVelocityEXT[(int)XrHandJointEXT.XR_HAND_JOINT_MAX_ENUM_EXT];
public bool isCreated { get { return trackerHandle != default; } }
public void ClearJoints()
{
Array.Clear(joints, 0, joints.Length);
Array.Clear(velocities, 0, velocities.Length);
}
}
private static HandTracking_OpenXR_API feature;
private static bool isInitialized;
private static bool isSystemSupported;
private static ulong refSpace;
private static HandData leftHandData = new HandData() { hand = XrHandEXT.XR_HAND_LEFT_EXT };
private static HandData rightHandData = new HandData() { hand = XrHandEXT.XR_HAND_RIGHT_EXT };
private static bool isRefSpaceCreated { get { return refSpace != default; } }
private static HandData GetHandData(bool isLeft)
{
return isLeft ? leftHandData : rightHandData;
}
public static bool Initialize()
{
if (!isInitialized)
{
if (feature == null)
{
feature = OpenXRSettings.Instance.GetFeature<HandTracking_OpenXR_API>();
if (feature != null)
{
// FIXME: Assume featuer instance won't be destroied and created to a new one
feature.onSessionCreate += OnFeatureSessionCreate;
feature.onSessionDestroy += OnFeatureSessionDestroy;
feature.onSystemChange += OnFeatureSystemChange;
}
}
if (feature != null && feature.IsEnabledAndInitialized)
{
UpdateSystemSupported();
isInitialized = true;
}
}
return isInitialized;
}
private static void OnFeatureSessionCreate(ulong xrSession)
{
TryCreateHandTracker(leftHandData);
TryCreateHandTracker(rightHandData);
}
private static void OnFeatureSessionDestroy(ulong xrSession)
{
DestroyHandTracker(leftHandData);
DestroyHandTracker(rightHandData);
DestroyRefSpace();
}
private static void OnFeatureSystemChange(ulong systemId)
{
UpdateSystemSupported();
}
private static void UpdateSystemSupported()
{
if (feature == null || !feature.IsEnabledAndInitialized)
{
isSystemSupported = false;
}
else
{
isSystemSupported = feature.SystemSupportsHandTracking(out var result);
if (!isSystemSupported)
{
if (result != XrResult.XR_SUCCESS)
{
Debug.LogWarning("Fail SystemSupportsHandTracking: " + result);
}
else
{
Debug.LogWarning("Hand tracking not supported by the system");
}
}
}
}
private static bool TryCreateHandTracker(HandData handData)
{
if (!handData.isStarted) { return false; }
if (!Initialize()) { return false; }
if (!isSystemSupported) { return false; }
if (!feature.IsSessionCreated) { return false; }
if (!handData.isCreated)
{
if (!feature.TryCreateHandTracker(handData.hand, out handData.trackerHandle, out var result))
{
handData.trackerHandle = default;
Debug.LogWarning("Fail CreateHandTracker: " + result);
}
}
return handData.isCreated;
}
private static void DestroyHandTracker(HandData handData)
{
if (!handData.isCreated) { return; }
if (!Initialize()) { return; }
feature.TryDestroyHandTracker(handData.trackerHandle, out _);
handData.trackerHandle = default;
handData.ClearJoints();
}
private static bool InitializeRefSpace()
{
if (!Initialize()) { return false; }
if (!isSystemSupported) { return false; }
if (!feature.IsSessionCreated) { return false; }
if (!isRefSpaceCreated)
{
const XrReferenceSpaceType preferSpaceType = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_STAGE;
XrReferenceSpaceType spaceType;
if (!feature.TryGetSupportedReferenceSpaceType(preferSpaceType, out spaceType, out var result))
{
Debug.LogWarning("Fail GetSupportedReferenceSpaceType: " + result);
}
else
{
if (!feature.TryCreateReferenceSpace(
spaceType,
new XrVector3f(0f, 0f, 0f),
new XrQuaternionf(0f, 0f, 0f, 1f),
out refSpace,
out result))
{
refSpace = default;
Debug.LogWarning("Fail CreateReferenceSpace: " + result);
}
}
}
return isRefSpaceCreated;
}
private static void DestroyRefSpace()
{
if (!isRefSpaceCreated) { return; }
if (Initialize())
{
if (!feature.TryDestroyReferenceSpace(refSpace, out var result))
{
Debug.LogWarning("Fail DestroyReferenceSpace: " + result);
}
}
refSpace = default;
}
public static void StartFrameWork(bool isLeft)
{
var handData = GetHandData(isLeft);
handData.isStarted = true;
TryCreateHandTracker(handData);
}
public static void StopFrameWork(bool isLeft)
{
var handData = GetHandData(isLeft);
handData.isStarted = false;
DestroyHandTracker(handData);
}
public static bool GetJointLocation(bool isleft, out XrHandJointLocationEXT[] joints, bool forceUpdate = false)
{
var handData = GetHandData(isleft);
if (handData.isCreated)
{
if (forceUpdate || handData.jointUpdatedFrame != Time.frameCount)
{
handData.jointUpdatedFrame = Time.frameCount;
if (InitializeRefSpace())
{
if (!feature.TryLocateHandJoints(
handData.trackerHandle,
refSpace,
out handData.isActive,
handData.joints,
out var result))
{
handData.isActive = false;
Debug.LogWarning("Fail LocateHandJoints: " + result);
}
}
}
}
joints = handData.joints;
return handData.isActive;
}
public static bool GetJointLocation(bool isleft, out XrHandJointLocationEXT[] joints, ref XrHandJointsMotionRangeEXT type, bool forceUpdate = false)
{
var handData = GetHandData(isleft);
if (handData.isCreated)
{
if (forceUpdate || handData.jointUpdatedFrame != Time.frameCount)
{
handData.jointUpdatedFrame = Time.frameCount;
if (InitializeRefSpace())
{
if (!feature.TryLocateHandJoints(
handData.trackerHandle,
refSpace,
ref type,
out handData.isActive,
handData.joints,
out var result))
{
handData.isActive = false;
Debug.LogWarning("Fail LocateHandJoints: " + result);
}
}
}
}
joints = handData.joints;
return handData.isActive;
}
public static bool GetJointLocation(bool isleft, out XrHandJointLocationEXT[] joints, out XrHandJointVelocityEXT[] velocities, bool forceUpdate = false)
{
var handData = GetHandData(isleft);
if (handData.isCreated)
{
if (forceUpdate || handData.jointUpdatedFrame != Time.frameCount)
{
handData.jointUpdatedFrame = Time.frameCount;
if (InitializeRefSpace())
{
if (!feature.TryLocateHandJoints(
handData.trackerHandle,
refSpace,
out handData.isActive,
handData.joints,
handData.velocities,
out var result))
{
handData.isActive = false;
Debug.LogWarning("Fail LocateHandJoints: " + result);
}
}
}
}
joints = handData.joints;
velocities = handData.velocities;
return handData.isActive;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ffbd7154b240117469bbc995d51d58a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,429 @@
using System;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine.XR.OpenXR.Features;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace VIVE
{
namespace HandTracking
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "Hand Tracking",
BuildTargetGroups = new[] { BuildTargetGroup.Standalone },
Company = "HTC",
Desc = "Hand Tracking OpenXR Feature",
DocumentationLink = "https://developer.vive.com/resources/openxr/openxr-pcvr/tutorials/unity/how-integrate-hand-tracking-data-your-hand-model/",
OpenxrExtensionStrings = "XR_EXT_hand_tracking",
Version = "0.0.1",
FeatureId = featureId)]
#endif
public class HandTracking_OpenXR_API : OpenXRFeature
{
/// <summary>
/// The feature id string. This is used to give the feature a well known id for reference.
/// </summary>
public const string featureId = "com.company.openxr.handtracking.feature";
private IntPtr oldxrGetInstanceProcAddr;
private IntPtr oldWaitFrame;
private ulong m_xrInstance;
private ulong m_xrSession;
private ulong m_systemId;
private XrFrameWaitInfo m_frameWaitInfo;
private XrFrameState m_frameState;
[Obsolete] public ulong m_space;
[Obsolete] public XrSystemProperties systemProperties;
[Obsolete] public ulong m_leftHandle;
[Obsolete] public ulong m_rightHandle;
public bool IsInitialized { get { return m_xrGetSystemProperties != null; } }
public bool IsEnabledAndInitialized { get { return enabled && IsInitialized; } }
public bool IsSessionCreated { get { return XrSession != default; } }
public ulong XrInstance { get { return m_xrInstance; } }
public ulong XrSession { get { return m_xrSession; } }
public ulong SystemId { get { return m_systemId; } }
public event Action<ulong> onSessionCreate;
public event Action<ulong> onSessionDestroy;
public event Action<ulong> onSystemChange;
protected override IntPtr HookGetInstanceProcAddr(IntPtr func)
{
UnityEngine.Debug.Log("EXT: registering our own xrGetInstanceProcAddr");
oldxrGetInstanceProcAddr = func;
m_intercept_xrWaitFrame_xrGetInstanceProcAddr = intercept_xrWaitFrame_xrGetInstanceProcAddr;
return Marshal.GetFunctionPointerForDelegate(m_intercept_xrWaitFrame_xrGetInstanceProcAddr);
}
private int intercept_xrWaitFrame_xrGetInstanceProcAddr(ulong instance, string name, out IntPtr function)
{
if (oldxrGetInstanceProcAddr == null || oldxrGetInstanceProcAddr == IntPtr.Zero)
{
UnityEngine.Debug.LogError("oldxrGetInstanceProcAddr is null");
function = IntPtr.Zero;
return -1;
}
// Get delegate of old xrGetInstanceProcAddr.
var xrGetProc = Marshal.GetDelegateForFunctionPointer<xrGetInstanceProcDelegate>(oldxrGetInstanceProcAddr);
int result = xrGetProc(instance, name,out function);
if(name == "xrWaitFrame")
{
oldWaitFrame = function;
m_intercept_xrWaitFrame = intercepted_xrWaitFrame;
function = Marshal.GetFunctionPointerForDelegate(m_intercept_xrWaitFrame); ;
UnityEngine.Debug.Log("Getting xrWaitFrame func");
}
return result;
}
private int intercepted_xrWaitFrame(ulong session,ref XrFrameWaitInfo frameWaitInfo, ref XrFrameState frameState)
{
// Get delegate of old xrWaitFrame.
var xrWaitFrame = Marshal.GetDelegateForFunctionPointer<xrWaitFrameDelegate>(oldWaitFrame);
int res = xrWaitFrame(session, ref frameWaitInfo, ref frameState);
m_frameWaitInfo = frameWaitInfo;
m_frameState = frameState;
return res;
}
/// <inheritdoc />
protected override bool OnInstanceCreate(ulong xrInstance)
{
UnityEngine.Debug.Log($"OnInstanceCreate({xrInstance:X})");
m_xrInstance = xrInstance;
return GetXrFunctionDelegates(xrInstance);
}
/// <inheritdoc />
protected override void OnInstanceDestroy(ulong xrInstance)
{
UnityEngine.Debug.Log($"OnInstanceDestroy({xrInstance:X})");
m_xrInstance = default;
//ClearXrFunctionDelegates();
}
/// <inheritdoc />
protected override void OnSessionCreate(ulong xrSession)
{
UnityEngine.Debug.Log($"OnSessionCreate({xrSession:X})");
m_xrSession = xrSession;
try { onSessionCreate?.Invoke(xrSession); }
catch (Exception e) { UnityEngine.Debug.LogError(e); }
}
/// <inheritdoc />
protected override void OnSystemChange(ulong xrSystem)
{
UnityEngine.Debug.Log($"OnSystemChange({xrSystem:X})");
m_systemId = xrSystem;
try { onSystemChange?.Invoke(xrSystem); }
catch (Exception e) { UnityEngine.Debug.LogError(e); }
}
/// <inheritdoc />
protected override void OnSessionDestroy(ulong xrSession)
{
UnityEngine.Debug.Log($"OnSessionDestroy({xrSession:X})");
m_xrSession = default;
try { onSessionDestroy?.Invoke(xrSession); }
catch (Exception e) { UnityEngine.Debug.LogError(e); }
}
/// <summary>Return true if the result equals zero. </summary>
private bool GetXrFunctionDelegates(ulong xrInstance)
{
if (xrGetInstanceProcAddr == null || xrGetInstanceProcAddr == IntPtr.Zero)
{
UnityEngine.Debug.LogError("xrGetInstanceProcAddr is null");
return false;
}
// Get delegate of xrGetInstanceProcAddr.
var xrGetProc = Marshal.GetDelegateForFunctionPointer<xrGetInstanceProcDelegate>(xrGetInstanceProcAddr);
if (!MarshelFunc(xrInstance, xrGetProc, "xrGetSystemProperties", ref m_xrGetSystemProperties)) { return false; }
if (!MarshelFunc(xrInstance, xrGetProc, "xrEnumerateReferenceSpaces", ref m_xrEnumerateReferenceSpaces)) { return false; }
if (!MarshelFunc(xrInstance, xrGetProc, "xrEnumerateReferenceSpaces", ref m_xrEnumerateReferenceSpaces2)) { return false; }
if (!MarshelFunc(xrInstance, xrGetProc, "xrCreateReferenceSpace", ref m_xrCreateReferenceSpace)) { return false; }
if (!MarshelFunc(xrInstance, xrGetProc, "xrDestroySpace", ref m_xrDestroySpace)) { return false; }
if (!MarshelFunc(xrInstance, xrGetProc, "xrCreateHandTrackerEXT", ref m_xrCreateHandTrackerEXT)) { return false; }
if (!MarshelFunc(xrInstance, xrGetProc, "xrDestroyHandTrackerEXT", ref m_xrDestroyHandTrackerEXT)) { return false; }
if (!MarshelFunc(xrInstance, xrGetProc, "xrLocateHandJointsEXT", ref m_xrLocateHandJointsEXT)) { return false; }
return true;
}
private void ClearXrFunctionDelegates()
{
m_xrGetSystemProperties = null;
m_xrEnumerateReferenceSpaces = null;
m_xrEnumerateReferenceSpaces2 = null;
m_xrCreateReferenceSpace = null;
m_xrDestroySpace = null;
m_xrCreateHandTrackerEXT = null;
m_xrDestroyHandTrackerEXT = null;
m_xrLocateHandJointsEXT = null;
}
private static bool MarshelFunc<T>(ulong instance, xrGetInstanceProcDelegate instanceProc, string funcName, ref T func, bool verbose = true)
where T : Delegate
{
if (instanceProc(instance, funcName, out var fp) != 0)
{
if (verbose)
{
UnityEngine.Debug.LogError("Fail getting function " + funcName);
}
return false;
}
func = Marshal.GetDelegateForFunctionPointer<T>(fp);
return true;
}
private xrGetInstanceProcDelegate m_intercept_xrWaitFrame_xrGetInstanceProcAddr;
private delegate int xrGetSystemPropertiesDelegate(ulong instance, ulong systemId, ref XrSystemProperties properties);
private xrGetSystemPropertiesDelegate m_xrGetSystemProperties;
public int xrGetSystemProperties(ref XrSystemProperties properties) =>
m_xrGetSystemProperties(XrInstance, SystemId, ref properties);
public int xrGetSystemProperties(ulong instance, ulong systemId, ref XrSystemProperties properties) =>
m_xrGetSystemProperties(instance, systemId, ref properties);
private delegate int xrWaitFrameDelegate(ulong session,ref XrFrameWaitInfo frameWaitInfo, ref XrFrameState frameState);
private xrWaitFrameDelegate m_intercept_xrWaitFrame;
#region space
private delegate int xrEnumerateReferenceSpacesDelegate(ulong session, int spaceCapacityInput, out int spaceCountOutput, out XrReferenceSpaceType spaces);
private xrEnumerateReferenceSpacesDelegate m_xrEnumerateReferenceSpaces;
public int xrEnumerateReferenceSpaces(int spaceCapacityInput, out int spaceCountOutput, out XrReferenceSpaceType spaces) =>
m_xrEnumerateReferenceSpaces(XrSession, spaceCapacityInput, out spaceCountOutput, out spaces);
private delegate int xrEnumerateReferenceSpacesDelegate2(ulong session, int spaceCapacityInput, out int spaceCountOutput, IntPtr spaces);
private xrEnumerateReferenceSpacesDelegate2 m_xrEnumerateReferenceSpaces2;
public int xrEnumerateReferenceSpaces(ulong session, int spaceCapacityInput, out int spaceCountOutput, IntPtr spaces) =>
m_xrEnumerateReferenceSpaces2(session, spaceCapacityInput, out spaceCountOutput, spaces);
private delegate int xrCreateReferenceSpaceDelegate(ulong session, ref XrReferenceSpaceCreateInfo createInfo, out ulong space);
private xrCreateReferenceSpaceDelegate m_xrCreateReferenceSpace;
public int xrCreateReferenceSpace(ref XrReferenceSpaceCreateInfo createInfo, out ulong space) =>
m_xrCreateReferenceSpace(XrSession, ref createInfo, out space);
public int xrCreateReferenceSpace(ulong session, ref XrReferenceSpaceCreateInfo createInfo, out ulong space) =>
m_xrCreateReferenceSpace(session, ref createInfo, out space);
private delegate int xrDestroySpaceDelegate(ulong space);
private xrDestroySpaceDelegate m_xrDestroySpace;
public int xrDestroySpace(ulong space) =>
m_xrDestroySpace(space);
#endregion
private delegate int xrCreateHandTrackerEXTDelegate(ulong session, XrHandTrackerCreateInfoEXT createInfo, out ulong handTracker);
private xrCreateHandTrackerEXTDelegate m_xrCreateHandTrackerEXT;
public int xrCreateHandTrackerEXT(XrHandTrackerCreateInfoEXT createInfo, out ulong handle) =>
m_xrCreateHandTrackerEXT(XrSession, createInfo, out handle);
public int xrCreateHandTrackerEXT(ulong session, XrHandTrackerCreateInfoEXT createInfo, out ulong handle) =>
m_xrCreateHandTrackerEXT(session, createInfo, out handle);
private delegate int xrDestroyHandTrackerEXTDelegate(ulong handTracker);
private xrDestroyHandTrackerEXTDelegate m_xrDestroyHandTrackerEXT;
public int xrDestroyHandTrackerEXT(ulong handle) =>
m_xrDestroyHandTrackerEXT(handle);
private delegate int xrLocateHandJointsEXTDelegate(ulong handTracker,ref XrHandJointsLocateInfoEXT locateInfo, ref XrHandJointLocationsEXT locations);
private xrLocateHandJointsEXTDelegate m_xrLocateHandJointsEXT;
public int xrLocateHandJointsEXT(ulong handTracker,ref XrHandJointsLocateInfoEXT locateInfo, ref XrHandJointLocationsEXT locations) =>
m_xrLocateHandJointsEXT(handTracker,ref locateInfo, ref locations);
public unsafe bool SystemSupportsHandTracking(out XrResult result)
{
var handTrackingSystemProp = new XrSystemHandTrackingPropertiesEXT()
{
type = XrStructureType.XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT,
next = IntPtr.Zero,
};
var systemProp = new XrSystemProperties()
{
type = XrStructureType.XR_TYPE_SYSTEM_PROPERTIES,
next = (IntPtr)(&handTrackingSystemProp),
};
result = (XrResult)xrGetSystemProperties(XrInstance, SystemId, ref systemProp);
return result == XrResult.XR_SUCCESS && handTrackingSystemProp.supportsHandTracking != 0u;
}
public bool TryGetSupportedReferenceSpaceTypeCount(out int count, out XrResult result)
{
result = (XrResult)m_xrEnumerateReferenceSpaces2(XrSession, 0, out count, IntPtr.Zero);
return result == XrResult.XR_SUCCESS;
}
public bool TryGetSupportedReferenceSpaceTypes(XrReferenceSpaceType[] spaces, out XrResult result)
{
if (spaces == null || spaces.Length == 0)
{
result = default;
return true;
}
result = (XrResult)m_xrEnumerateReferenceSpaces2(XrSession, spaces.Length, out _, ArrayPtr(spaces));
return result == XrResult.XR_SUCCESS;
}
public bool TryGetSupportedReferenceSpaceType(XrReferenceSpaceType preferType, out XrReferenceSpaceType supportedType, out XrResult result)
{
supportedType = default;
if (!TryGetSupportedReferenceSpaceTypeCount(out var count, out result)) { return false; }
if (count == 0) { return false; } // FIXME: error code?
var spaces = new XrReferenceSpaceType[count];
if (!TryGetSupportedReferenceSpaceTypes(spaces, out result)) { return false; }
for (int i = 0; i < count; ++i)
{
supportedType = spaces[i];
if (supportedType == preferType) { break; }
}
return true;
}
public bool TryCreateReferenceSpace(XrReferenceSpaceType refSpaceType, XrVector3f position, XrQuaternionf orientation, out ulong handle, out XrResult result)
{
var createInfo = new XrReferenceSpaceCreateInfo()
{
type = XrStructureType.XR_TYPE_REFERENCE_SPACE_CREATE_INFO,
next = IntPtr.Zero,
referencespacetype = refSpaceType,
poseInReferenceSpace = new XrPosef()
{
position = position,
orientation = orientation,
},
};
result = (XrResult)xrCreateReferenceSpace(XrSession, ref createInfo, out handle);
return result == XrResult.XR_SUCCESS;
}
public bool TryDestroyReferenceSpace(ulong handle, out XrResult result)
{
result = (XrResult)xrDestroySpace(handle);
return result == XrResult.XR_SUCCESS;
}
public bool TryCreateHandTracker(XrHandEXT hand, out ulong handle, out XrResult result, XrHandJointSetEXT jointSet = XrHandJointSetEXT.XR_HAND_JOINT_SET_DEFAULT_EXT)
{
var createInfo = new XrHandTrackerCreateInfoEXT()
{
type = XrStructureType.XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT,
next = IntPtr.Zero,
hand = hand,
handJointSet = XrHandJointSetEXT.XR_HAND_JOINT_SET_DEFAULT_EXT,
};
result = (XrResult)xrCreateHandTrackerEXT(XrSession, createInfo, out handle);
return result == XrResult.XR_SUCCESS;
}
public bool TryDestroyHandTracker(ulong handle, out XrResult result)
{
result = (XrResult)xrDestroyHandTrackerEXT(handle);
return result == XrResult.XR_SUCCESS;
}
public bool TryLocateHandJoints(ulong handle, ulong space, out bool isActive, XrHandJointLocationEXT[] locationArray, out XrResult result)
{
return TryLocateHandJoints(handle, space, out isActive, locationArray, null, out result);
}
public bool TryLocateHandJoints(ulong handle, ulong space, out bool isActive, XrHandJointLocationEXT[] locationArray, XrHandJointVelocityEXT[] velocityArray, out XrResult result)
{
return TryLocateHandJoints(handle, space, IntPtr.Zero, out isActive, locationArray, velocityArray, out result);
}
public bool TryLocateHandJoints(ulong handle, ulong space, ref XrHandJointsMotionRangeEXT motionRange, out bool isActive, XrHandJointLocationEXT[] locationArray, out XrResult result)
{
return TryLocateHandJoints(handle, space, ref motionRange, out isActive, locationArray, null, out result);
}
public unsafe bool TryLocateHandJoints(ulong handle, ulong space, ref XrHandJointsMotionRangeEXT motionRange, out bool isActive, XrHandJointLocationEXT[] locationArray, XrHandJointVelocityEXT[] velocityArray, out XrResult result)
{
var motionRangeInfo = new XrHandJointsMotionRangeInfoEXT()
{
type = XrStructureType.XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT,
next = IntPtr.Zero,
handJointsMotionRange = motionRange,
};
bool res = TryLocateHandJoints(handle, space, (IntPtr)(&motionRangeInfo), out isActive, locationArray, velocityArray, out result);
motionRange = motionRangeInfo.handJointsMotionRange;
return res;
}
private unsafe bool TryLocateHandJoints(ulong handle, ulong space, IntPtr motionRangeInfo, out bool isActive, XrHandJointLocationEXT[] locationArray, XrHandJointVelocityEXT[] velocityArray, out XrResult result)
{
var locateInfo = new XrHandJointsLocateInfoEXT()
{
type = XrStructureType.XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT,
next = motionRangeInfo,
baseSpace = space,
time = m_frameState.predictedDisplayTime, //An arbitrary number greater than 0
};
var locVelocitiesPtr = IntPtr.Zero;
if (velocityArray != null)
{
var locVelocities = new XrHandJointVelocitiesEXT()
{
type = XrStructureType.XR_TYPE_HAND_JOINT_VELOCITIES_EXT,
next = IntPtr.Zero,
jointCount = (uint)velocityArray.Length,
jointVelocities = ArrayPtr(velocityArray)
};
locVelocitiesPtr = (IntPtr)(&locVelocities);
}
var locations = new XrHandJointLocationsEXT()
{
type = XrStructureType.XR_TYPE_HAND_JOINT_LOCATIONS_EXT,
next = locVelocitiesPtr,
jointCount = locationArray == null ? 0 : locationArray.Length,
jointLocations = ArrayPtr(locationArray),
};
result = (XrResult)xrLocateHandJointsEXT(handle,ref locateInfo, ref locations);
isActive = locations.isActive != 0u;
return result == XrResult.XR_SUCCESS;
}
private unsafe static IntPtr ArrayPtr(XrReferenceSpaceType[] array)
{
if (array == null) { return IntPtr.Zero; }
fixed (XrReferenceSpaceType* p = array) { return (IntPtr)p; }
}
private unsafe static IntPtr ArrayPtr(XrHandJointLocationEXT[] array)
{
if (array == null) { return IntPtr.Zero; }
fixed (XrHandJointLocationEXT* p = array) { return (IntPtr)p; }
}
private unsafe static IntPtr ArrayPtr(XrHandJointVelocityEXT[] array)
{
if (array == null) { return IntPtr.Zero; }
fixed (XrHandJointVelocityEXT* p = array) { return (IntPtr)p; }
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38169f0e301608a469f311ebb2233162
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: