version 2.5.1
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68f6a3e78d49e1143a9aa0a111a04a0a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ce39c25a1e4a794c807d9f723d37804
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user