version 2.5.1

This commit is contained in:
Sean Lu
2025-01-10 17:31:06 +08:00
parent 2554daa86e
commit 25a5fd2124
91 changed files with 16226 additions and 11225 deletions

View File

@@ -0,0 +1,458 @@
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.OpenXR;
using VIVE.OpenXR.Interaction;
#if UNITY_XR_HANDS
using UnityEngine.XR.Hands;
using UnityEngine.XR.Hands.ProviderImplementation;
namespace VIVE.OpenXR.Hand
{
public class ViveHandProvider : XRHandSubsystemProvider
{
#region Hand Interaction
private const string kFeatureAimPos = "PointerPosition";
private const string kFeatureAimRot = "PointerRotation";
private const string kFeatureAimValue = "PointerActivateValue";
private const string kFeatureGripPos = "DevicePosition";
private const string kFeatureGripRot = "DeviceRotation";
private const string kFeatureGripValue = "GraspValue";
private const string kFeaturePinchPos = "PinchPosition";
private const string kFeaturePinchRot = "PinchRotation";
private const string kFeaturePinchValue = "PinchValue";
private const string kFeaturePokePos = "PokePosition";
private const string kFeaturePokeRot = "PokeRotation";
private class HandDevice
{
public Pose aimPose => m_AimPose;
public Pose gripPose => m_GripPose;
public Pose pinchPose => m_PinchPose;
public Pose pokePose => m_PokePose;
public float aimActivateValue => m_AimActivateValue;
public float graspValue => m_GraspValue;
public float pinchValue => m_PinchValue;
private Pose m_AimPose = Pose.identity;
private Pose m_GripPose = Pose.identity;
private Pose m_PinchPose = Pose.identity;
private Pose m_PokePose = Pose.identity;
private float m_AimActivateValue = 0;
private float m_GraspValue = 0;
private float m_PinchValue = 0;
private InputDevice device = default(InputDevice);
private Dictionary<string, InputFeatureUsage<Vector3>> posUsageMapping = new Dictionary<string, InputFeatureUsage<Vector3>>();
private Dictionary<string, InputFeatureUsage<Quaternion>> rotUsageMapping = new Dictionary<string, InputFeatureUsage<Quaternion>>();
private Dictionary<string, InputFeatureUsage<float>> valueUsageMapping = new Dictionary<string, InputFeatureUsage<float>>();
public HandDevice(InputDevice device)
{
this.device = device;
List<InputFeatureUsage> inputFeatures = new List<InputFeatureUsage>();
device.TryGetFeatureUsages(inputFeatures);
for (int i = 0; i < inputFeatures.Count; i++)
{
InputFeatureUsage feature = inputFeatures[i];
switch (feature.name)
{
case kFeatureAimPos:
case kFeatureGripPos:
case kFeaturePinchPos:
case kFeaturePokePos:
posUsageMapping.Add(feature.name, feature.As<Vector3>());
break;
case kFeatureAimRot:
case kFeatureGripRot:
case kFeaturePinchRot:
case kFeaturePokeRot:
rotUsageMapping.Add(feature.name, feature.As<Quaternion>());
break;
case kFeatureAimValue:
case kFeatureGripValue:
case kFeaturePinchValue:
valueUsageMapping.Add(feature.name, feature.As<float>());
break;
default:
break;
}
}
}
public void UpdateInputValue()
{
UpdatePosition();
UpdateRotation();
UpdateValue();
}
private void UpdatePosition()
{
var enumerator = posUsageMapping.GetEnumerator();
while (enumerator.MoveNext())
{
var feature = enumerator.Current;
string featureName = feature.Key;
InputFeatureUsage<Vector3> featureUsage = feature.Value;
if (device.TryGetFeatureValue(featureUsage, out Vector3 position))
{
switch (featureName)
{
case kFeatureAimPos:
m_AimPose.position = position;
break;
case kFeatureGripPos:
m_GripPose.position = position;
break;
case kFeaturePinchPos:
m_PinchPose.position = position;
break;
case kFeaturePokePos:
m_PokePose.position = position;
break;
}
}
}
}
private void UpdateRotation()
{
var enumerator = rotUsageMapping.GetEnumerator();
while (enumerator.MoveNext())
{
var feature = enumerator.Current;
string featureName = feature.Key;
InputFeatureUsage<Quaternion> featureUsage = feature.Value;
if (device.TryGetFeatureValue(featureUsage, out Quaternion rotation))
{
switch (featureName)
{
case kFeatureAimRot:
m_AimPose.rotation = rotation;
break;
case kFeatureGripRot:
m_GripPose.rotation = rotation;
break;
case kFeaturePinchRot:
m_PinchPose.rotation = rotation;
break;
case kFeaturePokeRot:
m_PokePose.rotation = rotation;
break;
}
}
}
}
private void UpdateValue()
{
var enumerator = valueUsageMapping.GetEnumerator();
while (enumerator.MoveNext())
{
var feature = enumerator.Current;
string featureName = feature.Key;
InputFeatureUsage<float> featureUsage = feature.Value;
if (device.TryGetFeatureValue(featureUsage, out float value))
{
switch (featureName)
{
case kFeatureAimValue:
m_AimActivateValue = value;
break;
case kFeatureGripValue:
m_GraspValue = value;
break;
case kFeaturePinchValue:
m_PinchValue = value;
break;
}
}
}
}
}
private static HandDevice leftHandDevice = null;
private static HandDevice rightHandDevice = null;
private const string kInteractionDeviceName = "Vive Hand Interaction Ext OpenXR";
#endregion
private ViveHandTracking viveHand;
public override void Destroy() { }
public override void GetHandLayout(NativeArray<bool> handJointsInLayout)
{
handJointsInLayout[XRHandJointID.Palm.ToIndex()] = true;
handJointsInLayout[XRHandJointID.Wrist.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleTip.ToIndex()] = true;
}
public override void Start()
{
Initialize();
#if UNITY_XR_HANDS_1_5_0
InitHandInteractionDevices();
InputDevices.deviceConnected += DeviceConnected;
InputDevices.deviceDisconnected += DeviceDisconnected;
#endif
}
public override void Stop()
{
#if UNITY_XR_HANDS_1_5_0
InputDevices.deviceConnected -= DeviceConnected;
InputDevices.deviceDisconnected -= DeviceDisconnected;
#endif
}
public override XRHandSubsystem.UpdateSuccessFlags TryUpdateHands(XRHandSubsystem.UpdateType updateType, ref Pose leftHandRootPose, NativeArray<XRHandJoint> leftHandJoints, ref Pose rightHandRootPose, NativeArray<XRHandJoint> rightHandJoints)
{
XRHandSubsystem.UpdateSuccessFlags flags = XRHandSubsystem.UpdateSuccessFlags.None;
if (UpdateHand(true, ref leftHandRootPose, ref leftHandJoints))
{
flags |= XRHandSubsystem.UpdateSuccessFlags.LeftHandRootPose | XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints;
}
if (UpdateHand(false, ref rightHandRootPose, ref rightHandJoints))
{
flags |= XRHandSubsystem.UpdateSuccessFlags.RightHandRootPose | XRHandSubsystem.UpdateSuccessFlags.RightHandJoints;
}
#if UNITY_XR_HANDS_1_5_0
if (updateType == XRHandSubsystem.UpdateType.Dynamic && canSurfaceCommonPoseData)
{
UpdateHandInteraction();
}
#endif
return flags;
}
#if UNITY_XR_HANDS_1_5_0
public override bool canSurfaceCommonPoseData => HandInteractionSupport();
public override bool TryGetAimPose(Handedness handedness, out Pose aimPose)
{
aimPose = Pose.identity;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
aimPose = handDevice.aimPose;
return true;
}
return false;
}
public override bool TryGetAimActivateValue(Handedness handedness, out float aimActivateValue)
{
aimActivateValue = 0;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
aimActivateValue = handDevice.aimActivateValue;
return true;
}
return false;
}
public override bool TryGetGripPose(Handedness handedness, out Pose gripPose)
{
gripPose = Pose.identity;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
gripPose = handDevice.gripPose;
return true;
}
return false;
}
public override bool TryGetGraspValue(Handedness handedness, out float graspValue)
{
graspValue = 0;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
graspValue = handDevice.graspValue;
return true;
}
return false;
}
public override bool TryGetPinchPose(Handedness handedness, out Pose pinchPose)
{
pinchPose = Pose.identity;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
pinchPose = handDevice.pinchPose;
return true;
}
return false;
}
public override bool TryGetPinchValue(Handedness handedness, out float pinchValue)
{
pinchValue = 0;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
pinchValue = handDevice.pinchValue;
return true;
}
return false;
}
public override bool TryGetPokePose(Handedness handedness, out Pose pokePose)
{
pokePose = Pose.identity;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
pokePose = handDevice.pokePose;
return true;
}
return false;
}
private void DeviceConnected(InputDevice inputDevice)
{
if (inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Left) &&
inputDevice.name == kInteractionDeviceName)
{
leftHandDevice = new HandDevice(inputDevice);
}
if (inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Right) &&
inputDevice.name == kInteractionDeviceName)
{
rightHandDevice = new HandDevice(inputDevice);
}
}
private void DeviceDisconnected(InputDevice inputDevice)
{
if (inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Left) &&
inputDevice.name == kInteractionDeviceName)
{
leftHandDevice = default;
}
if (inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Right) &&
inputDevice.name == kInteractionDeviceName)
{
rightHandDevice = default;
}
}
private void InitHandInteractionDevices()
{
List<InputDevice> inputDevices = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.HeldInHand |
InputDeviceCharacteristics.HandTracking |
InputDeviceCharacteristics.TrackedDevice, inputDevices);
for (int i = 0; i < inputDevices.Count; i++)
{
InputDevice inputDevice = inputDevices[i];
DeviceConnected(inputDevice);
}
}
private void UpdateHandInteraction()
{
if (leftHandDevice != null)
{
leftHandDevice.UpdateInputValue();
}
if (rightHandDevice != null)
{
rightHandDevice.UpdateInputValue();
}
}
private HandDevice GetHandDevice(Handedness handedness) => handedness == Handedness.Left ? leftHandDevice : rightHandDevice;
private bool HandInteractionSupport()
{
ViveInteractions viveInteractions = OpenXRSettings.Instance.GetFeature<ViveInteractions>();
if (viveInteractions.enabled)
{
return viveInteractions.UseKhrHandInteraction();
}
return false;
}
#endif
private void Initialize()
{
viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
}
private bool UpdateHand(bool isLeft, ref Pose handRootPose, ref NativeArray<XRHandJoint> handJoints)
{
if (!viveHand) { return false; }
bool isValid = viveHand.GetJointLocations(isLeft, out XrHandJointLocationEXT[] viveJoints);
Handedness handedness = isLeft ? Handedness.Left : Handedness.Right;
XRHandJointTrackingState trackingState = XRHandJointTrackingState.None;
for (int jointIndex = XRHandJointID.BeginMarker.ToIndex(); jointIndex < XRHandJointID.EndMarker.ToIndex(); ++jointIndex)
{
XRHandJointID jointID = XRHandJointIDUtility.FromIndex(jointIndex);
int viveIndex = XRHandJointIDToIndex(jointID);
Pose pose = Pose.identity;
if (isValid)
{
pose.position = viveJoints[viveIndex].pose.position.ToUnityVector();
pose.rotation = viveJoints[viveIndex].pose.orientation.ToUnityQuaternion();
trackingState = XRHandJointTrackingState.Pose;
}
handJoints[jointIndex] = XRHandProviderUtility.CreateJoint(handedness, trackingState, jointID, pose);
}
handJoints[XRHandJointID.Wrist.ToIndex()].TryGetPose(out handRootPose);
return isValid;
}
private int XRHandJointIDToIndex(XRHandJointID id)
{
switch (id)
{
case XRHandJointID.Palm:
return 0;
case XRHandJointID.Wrist:
return 1;
default:
return (int)id - 1;
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,102 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using VIVE.OpenXR.Interaction;
#if UNITY_XR_HANDS
using UnityEngine.XR.Hands;
using UnityEngine.XR.Hands.ProviderImplementation;
namespace VIVE.OpenXR.Hand
{
public class ViveHandSubsystem : XRHandSubsystem
{
public const string featureId = "vive.openxr.feature.xrhandsubsystem";
private static XRHandSubsystem subsystem = null;
private XRHandProviderUtility.SubsystemUpdater subsystemUpdater = null;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void RegisterDescriptor()
{
if (!ViveHandTrackingSupport()) { return; }
bool handInteractionSupport = HandInteractionSupport();
var handsSubsystemCinfo = new XRHandSubsystemDescriptor.Cinfo
{
id = featureId,
providerType = typeof(ViveHandProvider),
subsystemTypeOverride = typeof(ViveHandSubsystem),
#if UNITY_XR_HANDS_1_5_0
supportsAimPose = handInteractionSupport,
supportsAimActivateValue = handInteractionSupport,
supportsGraspValue = handInteractionSupport,
supportsGripPose = handInteractionSupport,
supportsPinchPose = handInteractionSupport,
supportsPinchValue = handInteractionSupport,
supportsPokePose = handInteractionSupport,
#endif
};
XRHandSubsystemDescriptor.Register(handsSubsystemCinfo);
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void StartSubsystem()
{
List<XRHandSubsystemDescriptor> descriptors = new List<XRHandSubsystemDescriptor>();
if (subsystem == null || !subsystem.running)
{
descriptors.Clear();
SubsystemManager.GetSubsystemDescriptors(descriptors);
for (int i = 0; i < descriptors.Count; i++)
{
XRHandSubsystemDescriptor descriptor = descriptors[i];
if (descriptor.id == featureId)
{
subsystem = descriptor.Create();
subsystem.Start();
}
}
}
}
protected override void OnStart()
{
base.OnStart();
if (subsystemUpdater == null)
{
subsystemUpdater = new XRHandProviderUtility.SubsystemUpdater(subsystem);
}
subsystemUpdater.Start();
}
protected override void OnStop()
{
base.OnStop();
subsystemUpdater.Stop();
}
protected override void OnDestroy()
{
base.OnDestroy();
subsystemUpdater.Destroy();
subsystemUpdater = null;
}
private static bool ViveHandTrackingSupport()
{
ViveHandTracking viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
return viveHand.enabled;
}
private static bool HandInteractionSupport()
{
ViveInteractions viveInteractions = OpenXRSettings.Instance.GetFeature<ViveInteractions>();
if (viveInteractions.enabled)
{
return viveInteractions.UseKhrHandInteraction();
}
return false;
}
}
}
#endif

View File

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

View File

@@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using AOT;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.LowLevel;
@@ -63,48 +62,74 @@ namespace VIVE.OpenXR.Hand
private bool m_XrInstanceCreated = false;
private XrInstance m_XrInstance = 0;
private static IntPtr xrGetInstanceProcAddr_prev;
private static IntPtr WaitFrame_prev;
private static XrFrameWaitInfo m_frameWaitInfo;
private static XrFrameState m_frameState;
private static XrTime m_predictedDisplayTime;
private static XrDuration m_predictedDisplayDuration;
private static int sizeOfXrHandJointLocationEXT = Marshal.SizeOf(typeof(XrHandJointLocationEXT));
private static IntPtr handJointLocationsNativeBuffer = IntPtr.Zero;
private static byte[] handJointLocationsByteBuffer = null;
private static int handJointLocationsNativeBufferLength = 0; // Not byte size, it is the number of XrHandJointLocationEXT.
protected override IntPtr HookGetInstanceProcAddr(IntPtr func)
{
UnityEngine.Debug.Log("EXT: registering our own xrGetInstanceProcAddr");
xrGetInstanceProcAddr_prev = func;
return Marshal.GetFunctionPointerForDelegate(m_intercept_xrWaitFrame_xrGetInstanceProcAddr);
}
[MonoPInvokeCallback(typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate))]
private static XrResult intercept_xrWaitFrame_xrGetInstanceProcAddr(XrInstance instance, string name, out IntPtr function)
{
if (xrGetInstanceProcAddr_prev == null || xrGetInstanceProcAddr_prev == IntPtr.Zero)
ViveInterceptors.Instance.AddRequiredFunction("xrWaitFrame");
if (ViveInterceptors.Instance.BeforeOriginalWaitFrame == null)
{
UnityEngine.Debug.LogError("xrGetInstanceProcAddr_prev is null");
function = IntPtr.Zero;
return XrResult.XR_ERROR_VALIDATION_FAILURE;
ViveInterceptors.Instance.BeforeOriginalWaitFrame = new ViveInterceptors.DelegateXrWaitFrameInterceptor(BeforeWaitFrame);
}
else
{
ViveInterceptors.Instance.BeforeOriginalWaitFrame += BeforeWaitFrame;
}
// Get delegate of old xrGetInstanceProcAddr.
var xrGetProc = Marshal.GetDelegateForFunctionPointer<OpenXRHelper.xrGetInstanceProcAddrDelegate>(xrGetInstanceProcAddr_prev);
XrResult result = xrGetProc(instance, name, out function);
if (name == "xrWaitFrame")
if (ViveInterceptors.Instance.AfterOriginalWaitFrame == null)
{
WaitFrame_prev = function;
m_intercept_xrWaitFrame = intercepted_xrWaitFrame;
function = Marshal.GetFunctionPointerForDelegate(m_intercept_xrWaitFrame); ;
UnityEngine.Debug.Log("Getting xrWaitFrame func");
ViveInterceptors.Instance.AfterOriginalWaitFrame = new ViveInterceptors.DelegateXrWaitFrameInterceptor(AfterWaitFrame);
}
return result;
else
{
ViveInterceptors.Instance.AfterOriginalWaitFrame += AfterWaitFrame;
}
return ViveInterceptors.Instance.HookGetInstanceProcAddr(func);
}
[MonoPInvokeCallback(typeof(OpenXRHelper.xrWaitFrameDelegate))]
private static int intercepted_xrWaitFrame(ulong session, ref XrFrameWaitInfo frameWaitInfo, ref XrFrameState frameState)
private bool BeforeWaitFrame(XrSession session, ref ViveInterceptors.XrFrameWaitInfo frameWaitInfo, ref ViveInterceptors.XrFrameState frameState, ref XrResult result)
{
// Get delegate of prev xrWaitFrame.
var xrWaitFrame = Marshal.GetDelegateForFunctionPointer<OpenXRHelper.xrWaitFrameDelegate>(WaitFrame_prev);
int res = xrWaitFrame(session, ref frameWaitInfo, ref frameState);
m_frameWaitInfo = frameWaitInfo;
m_frameState = frameState;
return res;
ViveInterceptors.XrFrameState nextFrameState = new ViveInterceptors.XrFrameState
{
type = XrStructureType.XR_TYPE_PASSTHROUGH_HAND_TRACKER_FRAME_STATE_HTC,
next = frameState.next,
predictedDisplayPeriod = 0,
predictedDisplayTime = 0,
shouldRender = false
};
frameState.next = MemoryTools.ToIntPtr(nextFrameState);
return true;
}
private bool AfterWaitFrame(XrSession session, ref ViveInterceptors.XrFrameWaitInfo frameWaitInfo, ref ViveInterceptors.XrFrameState frameState, ref XrResult result)
{
m_predictedDisplayTime = frameState.predictedDisplayTime;
m_predictedDisplayDuration = frameState.predictedDisplayPeriod;
IntPtr next = frameState.next;
HashSet<IntPtr> visited = new HashSet<IntPtr>();
int iterationCount = 0;
int maxIterations = 10;
while (next != IntPtr.Zero && !visited.Contains(next))
{
if (iterationCount++ > maxIterations) { break; }
visited.Add(next);
ViveInterceptors.XrFrameState nextFrameState = Marshal.PtrToStructure<ViveInterceptors.XrFrameState>(next);
if (nextFrameState.type == XrStructureType.XR_TYPE_PASSTHROUGH_HAND_TRACKER_FRAME_STATE_HTC &&
nextFrameState.predictedDisplayTime != 0)
{
m_predictedDisplayTime = nextFrameState.predictedDisplayTime;
break;
}
next = nextFrameState.next;
}
return true;
}
/// <summary>
@@ -140,6 +165,14 @@ namespace VIVE.OpenXR.Hand
InputSystem.onAfterUpdate -= UpdateCallback;
}
sb.Clear().Append(LOG_TAG).Append("OnInstanceDestroy() ").Append(xrInstance); DEBUG(sb);
// release buffer
if (handJointLocationsNativeBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(handJointLocationsNativeBuffer);
handJointLocationsNativeBuffer = IntPtr.Zero;
handJointLocationsByteBuffer = null;
handJointLocationsNativeBufferLength = 0;
}
}
private XrSystemId m_XrSystemId = 0;
@@ -343,9 +376,6 @@ namespace VIVE.OpenXR.Hand
#endregion
#region OpenXR function delegates
private static readonly OpenXRHelper.xrGetInstanceProcAddrDelegate m_intercept_xrWaitFrame_xrGetInstanceProcAddr
= new OpenXRHelper.xrGetInstanceProcAddrDelegate(intercept_xrWaitFrame_xrGetInstanceProcAddr);
private static OpenXRHelper.xrWaitFrameDelegate m_intercept_xrWaitFrame;
/// xrGetInstanceProcAddr
OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddr;
@@ -681,7 +711,7 @@ namespace VIVE.OpenXR.Hand
{
XRInputSubsystem subsystem = null;
SubsystemManager.GetInstances(s_InputSubsystems);
SubsystemManager.GetSubsystems(s_InputSubsystems);
if (s_InputSubsystems.Count > 0)
{
subsystem = s_InputSubsystems[0];
@@ -795,7 +825,7 @@ namespace VIVE.OpenXR.Hand
return true;
}
private int lastUpdateFrameL = -1, lastUpdateFrameR = -1;
private int lastUpdateFrameL = -1, lastUpdateFrameR = -1, updateFrame = -1;
private void UpdateCallback()
{
// Only allow updating poses once at BeforeRender & Dynamic per frame.
@@ -805,6 +835,10 @@ namespace VIVE.OpenXR.Hand
lastUpdateFrameL = -1;
lastUpdateFrameR = -1;
}
if (InputState.currentUpdateType == InputUpdateType.BeforeRender)
{
updateFrame = Time.frameCount;
}
}
private bool AllowUpdate(bool isLeft)
{
@@ -832,90 +866,69 @@ namespace VIVE.OpenXR.Hand
public bool GetJointLocations(bool isLeft, out XrHandJointLocationEXT[] handJointLocation, out XrTime timestamp)
{
handJointLocation = isLeft ? jointLocationsL : jointLocationsR;
timestamp = m_frameState.predictedDisplayTime;
long displayTime = m_predictedDisplayTime;
if (Time.frameCount > updateFrame)
{
displayTime += m_predictedDisplayDuration;
}
timestamp = displayTime;
if (!AllowUpdate(isLeft)) { return true; }
bool ret = false;
if (isLeft && !hasLeftHandTracker) { return ret; }
if (!isLeft && !hasRightHandTracker) { return ret; }
OpenXRHelper.Trace.Begin("GetJointLocations");
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: m_frameState.predictedDisplayTime);
in_baseSpace: GetCurrentAppSpace(),
in_time: displayTime);
/// 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);
locations.jointCount = (uint)(handJointLocation.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);
int jointLocationsLength = handJointLocation.Length;
long offset = 0;
/*if (IntPtr.Size == 4)
offset = locations.jointLocations.ToInt32();
else
offset = locations.jointLocations.ToInt64();
for (int i = 0; i < jointLocationsLength; i++)
if (handJointLocationsNativeBuffer == null || handJointLocationsNativeBuffer == IntPtr.Zero)
{
IntPtr joint_location_ext_ptr = new IntPtr(offset);
int N = sizeOfXrHandJointLocationEXT * jointLocationsLength;
handJointLocationsNativeBuffer = Marshal.AllocHGlobal(N);
handJointLocationsByteBuffer = new byte[N];
handJointLocationsNativeBufferLength = jointLocationsLength;
DEBUG($"GetJointLocations() handJointLocationsNativeBuffer[{N}] is allocated.");
}
else if (handJointLocationsNativeBufferLength < jointLocationsLength)
{
Marshal.FreeHGlobal(handJointLocationsNativeBuffer);
int N = sizeOfXrHandJointLocationEXT * jointLocationsLength;
handJointLocationsNativeBuffer = Marshal.AllocHGlobal(N);
handJointLocationsByteBuffer = new byte[N];
handJointLocationsNativeBufferLength = jointLocationsLength;
DEBUG($"GetJointLocations() handJointLocationsNativeBuffer[{N}] is allocated.");
}
if (isLeft)
Marshal.StructureToPtr(jointLocationsL[i], joint_location_ext_ptr, false);
else
Marshal.StructureToPtr(jointLocationsR[i], joint_location_ext_ptr, false);
locations.jointLocations = handJointLocationsNativeBuffer;
offset += Marshal.SizeOf(joint_location_ext_type);
}*/
if (LocateHandJointsEXT(
var retX = LocateHandJointsEXT(
handTracker: (isLeft ? leftHandTracker : rightHandTracker),
locateInfo: locateInfo,
locations: ref locations) == XrResult.XR_SUCCESS)
locations: ref locations);
if (retX == XrResult.XR_SUCCESS)
{
timestamp = locateInfo.time;
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;
MemoryTools.CopyAllFromRawMemory(handJointLocation, handJointLocationsNativeBuffer);
ret = true;
}
}
Marshal.FreeHGlobal(locations.jointLocations);
OpenXRHelper.Trace.End();
return ret;
}
/// <summary>