622 lines
27 KiB
C#
622 lines
27 KiB
C#
#if !PICO_OPENXR_SDK
|
||
/*******************************************************************************
|
||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||
|
||
NOTICE:All information contained herein is, and remains the property of
|
||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||
covered by patents, patents in process, and are protected by trade secret or
|
||
copyright law. Dissemination of this information or reproduction of this
|
||
material is strictly forbidden unless prior written permission is obtained from
|
||
PICO Technology Co., Ltd.
|
||
*******************************************************************************/
|
||
|
||
using Unity.Collections;
|
||
using UnityEngine;
|
||
using UnityEngine.Scripting;
|
||
using System.Runtime.CompilerServices;
|
||
using UnityEngine.XR.Management;
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.XR;
|
||
using System.Collections.Generic;
|
||
using UnityEngine.InputSystem.Controls;
|
||
using UnityEngine.InputSystem.Layouts;
|
||
using UnityEngine.InputSystem.XR;
|
||
|
||
|
||
#if XR_HANDS
|
||
using UnityEngine.XR.Hands;
|
||
using UnityEngine.XR.Hands.ProviderImplementation;
|
||
|
||
|
||
namespace Unity.XR.PXR
|
||
{
|
||
[Preserve]
|
||
/// <summary>
|
||
/// Implement Unity XRHandSubSystem
|
||
/// Reference: https://docs.unity3d.com/Packages/com.unity.xr.hands@1.1/manual/implement-a-provider.html
|
||
/// </summary>
|
||
public class PXR_HandSubSystem : XRHandSubsystem
|
||
{
|
||
XRHandProviderUtility.SubsystemUpdater m_Updater;
|
||
|
||
// This method registers the subsystem descriptor with the SubsystemManager
|
||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||
static void RegisterDescriptor()
|
||
{
|
||
var handsSubsystemCinfo = new XRHandSubsystemDescriptor.Cinfo
|
||
{
|
||
id = "PICO Hands",
|
||
providerType = typeof(PXRHandSubsystemProvider),
|
||
subsystemTypeOverride = typeof(PXR_HandSubSystem)
|
||
};
|
||
XRHandSubsystemDescriptor.Register(handsSubsystemCinfo);
|
||
}
|
||
|
||
protected override void OnCreate()
|
||
{
|
||
base.OnCreate();
|
||
m_Updater = new XRHandProviderUtility.SubsystemUpdater(this);
|
||
}
|
||
|
||
protected override void OnStart()
|
||
{
|
||
Debug.Log("PXR_HandSubSystem Start");
|
||
m_Updater.Start();
|
||
base.OnStart();
|
||
}
|
||
|
||
protected override void OnStop()
|
||
{
|
||
m_Updater.Stop();
|
||
base.OnStop();
|
||
}
|
||
|
||
protected override void OnDestroy()
|
||
{
|
||
m_Updater.Destroy();
|
||
m_Updater = null;
|
||
base.OnDestroy();
|
||
}
|
||
|
||
class PXRHandSubsystemProvider : XRHandSubsystemProvider
|
||
{
|
||
|
||
HandJointLocations jointLocations = new HandJointLocations();
|
||
readonly HandLocationStatus AllStatus = HandLocationStatus.PositionTracked | HandLocationStatus.PositionValid |
|
||
HandLocationStatus.OrientationTracked | HandLocationStatus.OrientationValid;
|
||
|
||
bool isValid = false;
|
||
|
||
public override void Start()
|
||
{
|
||
CreateHands();
|
||
}
|
||
|
||
public override void Stop()
|
||
{
|
||
DestroyHands();
|
||
}
|
||
|
||
public override void Destroy()
|
||
{
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// Mapping the PICO Joint Index To Unity Joint Index
|
||
/// </summary>
|
||
static int[] pxrJointIndexToUnityJointIndexMapping;
|
||
|
||
static void Initialize()
|
||
{
|
||
if (pxrJointIndexToUnityJointIndexMapping == null)
|
||
{
|
||
pxrJointIndexToUnityJointIndexMapping = new int[(int)HandJoint.JointMax];
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointPalm] = XRHandJointID.Palm.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointWrist] = XRHandJointID.Wrist.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbMetacarpal] = XRHandJointID.ThumbMetacarpal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbProximal] = XRHandJointID.ThumbProximal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbDistal] = XRHandJointID.ThumbDistal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbTip] = XRHandJointID.ThumbTip.ToIndex();
|
||
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexMetacarpal] = XRHandJointID.IndexMetacarpal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexProximal] = XRHandJointID.IndexProximal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexIntermediate] = XRHandJointID.IndexIntermediate.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexDistal] = XRHandJointID.IndexDistal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexTip] = XRHandJointID.IndexTip.ToIndex();
|
||
|
||
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleMetacarpal] = XRHandJointID.MiddleMetacarpal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleProximal] = XRHandJointID.MiddleProximal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleIntermediate] = XRHandJointID.MiddleIntermediate.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleDistal] = XRHandJointID.MiddleDistal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleTip] = XRHandJointID.MiddleTip.ToIndex();
|
||
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingMetacarpal] = XRHandJointID.RingMetacarpal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingProximal] = XRHandJointID.RingProximal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingIntermediate] = XRHandJointID.RingIntermediate.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingDistal] = XRHandJointID.RingDistal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingTip] = XRHandJointID.RingTip.ToIndex();
|
||
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleMetacarpal] = XRHandJointID.LittleMetacarpal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleProximal] = XRHandJointID.LittleProximal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleIntermediate] = XRHandJointID.LittleIntermediate.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleDistal] = XRHandJointID.LittleDistal.ToIndex();
|
||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleTip] = XRHandJointID.LittleTip.ToIndex();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets the layout of hand joints for this provider, by having the
|
||
/// provider mark each index corresponding to a <see cref="XRHandJointID"/>
|
||
/// get marked as <see langword="true"/> if the provider attempts to track
|
||
/// that joint.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// Called once on creation so that before the subsystem is even started,
|
||
/// so the user can immediately create a valid hierarchical structure as
|
||
/// soon as they get a reference to the subsystem without even needing to
|
||
/// start it.
|
||
/// </remarks>
|
||
/// <param name="handJointsInLayout">
|
||
/// Each index corresponds to a <see cref="XRHandJointID"/>. For each
|
||
/// joint that the provider will attempt to track, mark that spot as
|
||
/// <see langword="true"/> by calling <c>.ToIndex()</c> on that ID.
|
||
/// </param>
|
||
public override void GetHandLayout(NativeArray<bool> handJointsInLayout)
|
||
{
|
||
|
||
Initialize();
|
||
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;
|
||
|
||
isValid = true;
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// Attempts to retrieve current hand-tracking data from the provider.
|
||
/// </summary>
|
||
public override UpdateSuccessFlags TryUpdateHands(
|
||
UpdateType updateType,
|
||
ref Pose leftHandRootPose,
|
||
NativeArray<XRHandJoint> leftHandJoints,
|
||
ref Pose rightHandRootPose,
|
||
NativeArray<XRHandJoint> rightHandJoints)
|
||
{
|
||
if (!isValid)
|
||
return UpdateSuccessFlags.None;
|
||
|
||
UpdateSuccessFlags ret = UpdateSuccessFlags.None;
|
||
|
||
const int handRootIndex = (int)HandJoint.JointWrist;
|
||
if (PXR_HandTracking.GetJointLocations(HandType.HandLeft, ref jointLocations))
|
||
{
|
||
if (jointLocations.isActive != 0U)
|
||
{
|
||
for (int index = 0, jointCount = (int)jointLocations.jointCount; index < jointCount; ++index)
|
||
{
|
||
ref HandJointLocation joint = ref jointLocations.jointLocations[index];
|
||
int unityHandJointIndex = pxrJointIndexToUnityJointIndexMapping[index];
|
||
|
||
leftHandJoints[unityHandJointIndex] = CreateXRHandJoint(Handedness.Left, unityHandJointIndex, joint);
|
||
|
||
if (index == handRootIndex)
|
||
{
|
||
leftHandRootPose = PXRPosefToUnityPose(joint.pose);
|
||
ret |= UpdateSuccessFlags.LeftHandRootPose;
|
||
}
|
||
}
|
||
#if UNITY_EDITOR
|
||
ret |= UpdateSuccessFlags.LeftHandJoints;
|
||
#else
|
||
if (PicoAimHand.left.UpdateHand(HandType.HandLeft, (ret & UpdateSuccessFlags.LeftHandRootPose) != 0))
|
||
{
|
||
ret |= UpdateSuccessFlags.LeftHandJoints;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
if (PXR_HandTracking.GetJointLocations(HandType.HandRight, ref jointLocations))
|
||
{
|
||
if (jointLocations.isActive != 0U)
|
||
{
|
||
for (int index = 0, jointCount = (int)jointLocations.jointCount; index < jointCount; ++index)
|
||
{
|
||
ref HandJointLocation joint = ref jointLocations.jointLocations[index];
|
||
int unityHandJointIndex = pxrJointIndexToUnityJointIndexMapping[index];
|
||
rightHandJoints[unityHandJointIndex] = CreateXRHandJoint(Handedness.Right, unityHandJointIndex, joint);
|
||
|
||
if (index == handRootIndex)
|
||
{
|
||
rightHandRootPose = PXRPosefToUnityPose(joint.pose);
|
||
ret |= UpdateSuccessFlags.RightHandRootPose;
|
||
}
|
||
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
ret |= UpdateSuccessFlags.RightHandJoints;
|
||
#else
|
||
if (PicoAimHand.right.UpdateHand(HandType.HandRight, (ret & UpdateSuccessFlags.RightHandRootPose) != 0))
|
||
{
|
||
ret |= UpdateSuccessFlags.RightHandJoints;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
void CreateHands()
|
||
{
|
||
if (PicoAimHand.left == null)
|
||
PicoAimHand.left = PicoAimHand.CreateHand(InputDeviceCharacteristics.Left);
|
||
|
||
if (PicoAimHand.right == null)
|
||
PicoAimHand.right = PicoAimHand.CreateHand(InputDeviceCharacteristics.Right);
|
||
}
|
||
|
||
void DestroyHands()
|
||
{
|
||
if (PicoAimHand.left != null)
|
||
{
|
||
InputSystem.RemoveDevice(PicoAimHand.left);
|
||
PicoAimHand.left = null;
|
||
}
|
||
|
||
if (PicoAimHand.right != null)
|
||
{
|
||
InputSystem.RemoveDevice(PicoAimHand.right);
|
||
PicoAimHand.right = null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Create Unity XRHandJoint From PXR HandJointLocation
|
||
/// </summary>
|
||
/// <param name="handedness"></param>
|
||
/// <param name="unityHandJointIndex"></param>
|
||
/// <param name="joint"></param>
|
||
/// <returns></returns>
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
XRHandJoint CreateXRHandJoint(Handedness handedness, int unityHandJointIndex, in HandJointLocation joint)
|
||
{
|
||
|
||
Pose pose = Pose.identity;
|
||
XRHandJointTrackingState state = XRHandJointTrackingState.None;
|
||
if ((joint.locationStatus & AllStatus) == AllStatus)
|
||
{
|
||
state = (XRHandJointTrackingState.Pose | XRHandJointTrackingState.Radius);
|
||
pose = PXRPosefToUnityPose(joint.pose);
|
||
}
|
||
return XRHandProviderUtility.CreateJoint(handedness,
|
||
state,
|
||
XRHandJointIDUtility.FromIndex(unityHandJointIndex),
|
||
pose, joint.radius
|
||
);
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// PXR's Posef to Unity'Pose
|
||
/// </summary>
|
||
/// <param name="pxrPose"></param>
|
||
/// <returns></returns>
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
Pose PXRPosefToUnityPose(in Posef pxrPose)
|
||
{
|
||
Vector3 position = pxrPose.Position.ToVector3();
|
||
Quaternion orientation = pxrPose.Orientation.ToQuat();
|
||
return new Pose(position, orientation);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
/// <remarks>
|
||
/// The <see cref="TrackedDevice.devicePosition"/> and
|
||
/// <see cref="TrackedDevice.deviceRotation"/> inherited from <see cref="TrackedDevice"/>
|
||
/// represent the aim pose. You can use these values to discover the target for pinch gestures,
|
||
/// when appropriate.
|
||
///
|
||
/// Use the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin) in the scene to position and orient
|
||
/// the device properly. If you are using this data to set the Transform of a GameObject in
|
||
/// the scene hierarchy, you can set the local position and rotation of the Transform and make
|
||
/// it a child of the <c>CameraOffset</c> object below the <c>XROrigin</c>. Otherwise, you can use the
|
||
/// Transform of the <c>CameraOffset</c> to transform the data into world space.
|
||
/// </remarks>
|
||
#if UNITY_EDITOR
|
||
[UnityEditor.InitializeOnLoad]
|
||
#endif
|
||
[Preserve, InputControlLayout(displayName = "Pico Aim Hand", commonUsages = new[] { "LeftHand", "RightHand" })]
|
||
public partial class PicoAimHand : TrackedDevice
|
||
{
|
||
/// <summary>
|
||
/// The left-hand <see cref="InputDevice"/> that contains
|
||
/// <see cref="InputControl"/>s that surface data in the Pico Hand
|
||
/// Tracking Aim extension.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// It is recommended that you treat this as read-only, and do not set
|
||
/// it yourself. It will be set for you if hand-tracking has been
|
||
/// enabled and if you are running with either the OpenXR or Oculus
|
||
/// plug-in.
|
||
/// </remarks>
|
||
public static PicoAimHand left { get; set; }
|
||
|
||
/// <summary>
|
||
/// The right-hand <see cref="InputDevice"/> that contains
|
||
/// <see cref="InputControl"/>s that surface data in the Pico Hand
|
||
/// Tracking Aim extension.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// It is recommended that you treat this as read-only, and do not set
|
||
/// it yourself. It will be set for you if hand-tracking has been
|
||
/// enabled and if you are running with either the OpenXR or Oculus
|
||
/// plug-in.
|
||
/// </remarks>
|
||
public static PicoAimHand right { get; set; }
|
||
|
||
/// <summary>
|
||
/// The pinch amount required to register as being pressed for the
|
||
/// purposes of <see cref="indexPressed"/>, <see cref="middlePressed"/>,
|
||
/// <see cref="ringPressed"/>, and <see cref="littlePressed"/>.
|
||
/// </summary>
|
||
public const float pressThreshold = 0.8f;
|
||
|
||
/// <summary>
|
||
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl)
|
||
/// that represents whether the pinch between the index finger and
|
||
/// the thumb is mostly pressed (greater than a threshold of <c>0.8</c>
|
||
/// contained in <see cref="pressThreshold"/>).
|
||
/// </summary>
|
||
[Preserve, InputControl(offset = 0)]
|
||
public ButtonControl indexPressed { get; private set; }
|
||
|
||
/// <summary>
|
||
/// Cast the result of reading this to <see cref="PicoAimFlags"/> to examine the value.
|
||
/// </summary>
|
||
[Preserve, InputControl]
|
||
public IntegerControl aimFlags { get; private set; }
|
||
|
||
/// <summary>
|
||
/// An [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl)
|
||
/// that represents the pinch strength between the index finger and
|
||
/// the thumb.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// A value of <c>0</c> denotes no pinch at all, while a value of
|
||
/// <c>1</c> denotes a full pinch.
|
||
/// </remarks>
|
||
[Preserve, InputControl]
|
||
public AxisControl pinchStrengthIndex { get; private set; }
|
||
|
||
/// <summary>
|
||
/// Perform final initialization tasks after the control hierarchy has been put into place.
|
||
/// </summary>
|
||
protected override void FinishSetup()
|
||
{
|
||
base.FinishSetup();
|
||
|
||
indexPressed = GetChildControl<ButtonControl>(nameof(indexPressed));
|
||
aimFlags = GetChildControl<IntegerControl>(nameof(aimFlags));
|
||
pinchStrengthIndex = GetChildControl<AxisControl>(nameof(pinchStrengthIndex));
|
||
|
||
var deviceDescriptor = XRDeviceDescriptor.FromJson(description.capabilities);
|
||
if (deviceDescriptor != null)
|
||
{
|
||
if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Left) != 0)
|
||
InputSystem.SetDeviceUsage(this, UnityEngine.InputSystem.CommonUsages.LeftHand);
|
||
else if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Right) != 0)
|
||
InputSystem.SetDeviceUsage(this, UnityEngine.InputSystem.CommonUsages.RightHand);
|
||
}
|
||
PXR_Plugin.System.FocusStateAcquired += OnFocusStateAcquired;
|
||
}
|
||
|
||
private void OnFocusStateAcquired()
|
||
{
|
||
m_WasTracked = false;
|
||
}
|
||
|
||
protected override void OnRemoved()
|
||
{
|
||
PXR_Plugin.System.FocusStateAcquired -= OnFocusStateAcquired;
|
||
base.OnRemoved();
|
||
}
|
||
/// <summary>
|
||
/// Creates a <see cref="PicoAimHand"/> and adds it to the Input System.
|
||
/// </summary>
|
||
/// <param name="extraCharacteristics">
|
||
/// Additional characteristics to build the hand device with besides
|
||
/// <see cref="InputDeviceCharacteristics.HandTracking"/> and <see cref="InputDeviceCharacteristics.TrackedDevice"/>.
|
||
/// </param>
|
||
/// <returns>
|
||
/// A <see cref="PicoAimHand"/> retrieved from
|
||
/// <see cref="InputSystem.AddDevice(InputDeviceDescription)"/>.
|
||
/// </returns>
|
||
/// <remarks>
|
||
/// It is recommended that you do not call this yourself. It will be
|
||
/// called for you at the appropriate time if hand-tracking has been
|
||
/// enabled and if you are running with either the OpenXR or Oculus
|
||
/// plug-in.
|
||
/// </remarks>
|
||
public static PicoAimHand CreateHand(InputDeviceCharacteristics extraCharacteristics)
|
||
{
|
||
var desc = new InputDeviceDescription
|
||
{
|
||
product = k_PicoAimHandDeviceProductName,
|
||
capabilities = new XRDeviceDescriptor
|
||
{
|
||
characteristics = InputDeviceCharacteristics.HandTracking | InputDeviceCharacteristics.TrackedDevice | extraCharacteristics,
|
||
inputFeatures = new List<XRFeatureDescriptor>
|
||
{
|
||
new XRFeatureDescriptor
|
||
{
|
||
name = "index_pressed",
|
||
featureType = FeatureType.Binary
|
||
},
|
||
new XRFeatureDescriptor
|
||
{
|
||
name = "aim_flags",
|
||
featureType = FeatureType.DiscreteStates
|
||
},
|
||
new XRFeatureDescriptor
|
||
{
|
||
name = "aim_pose_position",
|
||
featureType = FeatureType.Axis3D
|
||
},
|
||
new XRFeatureDescriptor
|
||
{
|
||
name = "aim_pose_rotation",
|
||
featureType = FeatureType.Rotation
|
||
},
|
||
new XRFeatureDescriptor
|
||
{
|
||
name = "pinch_strength_index",
|
||
featureType = FeatureType.Axis1D
|
||
}
|
||
}
|
||
}.ToJson()
|
||
};
|
||
return InputSystem.AddDevice(desc) as PicoAimHand;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Queues update events in the Input System based on the supplied hand.
|
||
/// It is not recommended that you call this directly. This will be called
|
||
/// for you when appropriate.
|
||
/// </summary>
|
||
/// <param name="isHandRootTracked">
|
||
/// Whether the hand root pose is valid.
|
||
/// </param>
|
||
/// <param name="aimFlags">
|
||
/// The aim flags to update in the Input System.
|
||
/// </param>
|
||
/// <param name="aimPose">
|
||
/// The aim pose to update in the Input System. Used if the hand root is tracked.
|
||
/// </param>
|
||
/// <param name="pinchIndex">
|
||
/// The pinch strength for the index finger to update in the Input System.
|
||
/// </param>
|
||
public void UpdateHand(bool isHandRootTracked, HandAimStatus aimFlags, Posef aimPose, float pinchIndex)
|
||
{
|
||
if (aimFlags != m_PreviousFlags)
|
||
{
|
||
InputSystem.QueueDeltaStateEvent(this.aimFlags, (int)aimFlags);
|
||
m_PreviousFlags = aimFlags;
|
||
}
|
||
|
||
bool isIndexPressed = pinchIndex > pressThreshold;
|
||
if (isIndexPressed != m_WasIndexPressed)
|
||
{
|
||
InputSystem.QueueDeltaStateEvent(indexPressed, isIndexPressed);
|
||
m_WasIndexPressed = isIndexPressed;
|
||
}
|
||
|
||
InputSystem.QueueDeltaStateEvent(pinchStrengthIndex, pinchIndex);
|
||
|
||
if ((aimFlags & HandAimStatus.AimComputed) == 0)
|
||
{
|
||
if (m_WasTracked)
|
||
{
|
||
InputSystem.QueueDeltaStateEvent(isTracked, false);
|
||
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.None);
|
||
m_WasTracked = false;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
if (isHandRootTracked)
|
||
{
|
||
InputSystem.QueueDeltaStateEvent(devicePosition, aimPose.Position.ToVector3());
|
||
InputSystem.QueueDeltaStateEvent(deviceRotation, aimPose.Orientation.ToQuat());
|
||
|
||
if (!m_WasTracked)
|
||
{
|
||
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.Position | InputTrackingState.Rotation);
|
||
InputSystem.QueueDeltaStateEvent(isTracked, true);
|
||
}
|
||
|
||
m_WasTracked = true;
|
||
}
|
||
else if (m_WasTracked)
|
||
{
|
||
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.None);
|
||
InputSystem.QueueDeltaStateEvent(isTracked, false);
|
||
m_WasTracked = false;
|
||
}
|
||
}
|
||
|
||
internal bool UpdateHand(HandType handType, bool isHandRootTracked)
|
||
{
|
||
|
||
HandAimState handAimState = new HandAimState();
|
||
PXR_HandTracking.GetAimState(handType, ref handAimState);
|
||
|
||
UpdateHand(
|
||
isHandRootTracked,
|
||
handAimState.aimStatus,
|
||
handAimState.aimRayPose,
|
||
handAimState.touchStrengthRay);
|
||
|
||
return (handAimState.aimStatus&HandAimStatus.AimComputed) != 0;
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
static PicoAimHand() => RegisterLayout();
|
||
#endif
|
||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||
static void RegisterLayout()
|
||
{
|
||
InputSystem.RegisterLayout<PicoAimHand>(
|
||
matches: new InputDeviceMatcher()
|
||
.WithProduct(k_PicoAimHandDeviceProductName));
|
||
}
|
||
|
||
const string k_PicoAimHandDeviceProductName = "Pico Aim Hand Tracking";
|
||
|
||
HandAimStatus m_PreviousFlags;
|
||
bool m_WasTracked;
|
||
bool m_WasIndexPressed;
|
||
}
|
||
}
|
||
|
||
#endif //XR_HANDS
|
||
#endif |