version 2.0.0
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e96f290ae08cd3642932e5fd10d142e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 771c4b3ec0a607546b6188ee58213b92
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
# 12.67 XR_HTC_hand_interaction
|
||||
## Name String
|
||||
XR_HTC_hand_interaction
|
||||
## Revision
|
||||
1
|
||||
## Hand Interaction Profile
|
||||
### Interaction profile path:
|
||||
- /interaction_profiles/htc/hand_interaction
|
||||
|
||||
### Valid for user paths:
|
||||
- /user/hand_htc/left
|
||||
- /user/hand_htc/right
|
||||
|
||||
### Supported input source
|
||||
- <20>K/input/select/value
|
||||
- <20>K/input/aim/pose
|
||||
|
||||
The application should use <20>K/input/aim/pose path to aim at objects in the world and use <20>K/input/select/value path to decide user selection from pinch shape strength which the range of value is 0.0f to 1.0f, with 1.0f meaning pinch fingers touched.
|
||||
|
||||
## VIVE Plugin
|
||||
|
||||
After adding the "VIVE Focus3 Hand Interaction" to "Project Settings > XR Plugin-in Management > OpenXR > Android Tab > Interaction Profiles", you can use the following Input Action Pathes.
|
||||
|
||||
### Left Hand
|
||||
- <ViveHandInteraction>{LeftHand}/selectValue: Presents the left hand pinch strength.
|
||||
- <ViveHandInteraction>{LeftHand}/pointerPose: Presents the left hand pinch pose.
|
||||
|
||||
### Right Hand
|
||||
- <ViveHandInteraction>{RightHand}/selectValue: Presents the right hand pinch strength.
|
||||
- <ViveHandInteraction>{RightHand}/pointerPose: Presents the right hand pinch pose.
|
||||
|
||||
Refer to the <VIVE OpenXR sample path>/Plugin/Input/ActionMap/InputActions.inputActions about the "Input Action Path" usage and the sample <VIVE OpenXR sample path>/Plugin/Input/OpenXRInput.unity.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1983ec0f3f6f1841b9824ef68235039
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8626a4ae9aacf7d41b32411a6e5a04f9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,342 @@
|
||||
// Copyright HTC Corporation All Rights Reserved.
|
||||
|
||||
using UnityEngine.Scripting;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.XR;
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.XR;
|
||||
using UnityEngine.XR.OpenXR.Input;
|
||||
using System.Text;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
#if USE_INPUT_SYSTEM_POSE_CONTROL // Scripting Define Symbol added by using OpenXR Plugin 1.6.0.
|
||||
using PoseControl = UnityEngine.InputSystem.XR.PoseControl;
|
||||
#else
|
||||
using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl;
|
||||
#endif
|
||||
|
||||
namespace VIVE.OpenXR.Hand
|
||||
{
|
||||
/// <summary>
|
||||
/// This <see cref="OpenXRInteractionFeature"/> enables the use of hand interaction profiles in OpenXR. It enables <see cref="ViveHandInteraction.kOpenxrExtensionString">XR_HTC_hand_interaction</see> in the underyling runtime.
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "VIVE XR Hand Interaction",
|
||||
BuildTargetGroups = new[] { BuildTargetGroup.Android , BuildTargetGroup.Standalone},
|
||||
Company = "HTC",
|
||||
Desc = "Support for enabling the hand interaction profile. Will register the controller map for hand interaction if enabled.",
|
||||
DocumentationLink = "..\\Documentation",
|
||||
Version = "1.0.0",
|
||||
OpenxrExtensionStrings = kOpenxrExtensionString,
|
||||
Category = FeatureCategory.Interaction,
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
public class ViveHandInteraction : OpenXRInteractionFeature
|
||||
{
|
||||
const string LOG_TAG = "VIVE.OpenXR.Hand.ViveHandInteraction ";
|
||||
StringBuilder m_sb = null;
|
||||
StringBuilder sb {
|
||||
get {
|
||||
if (m_sb == null) { m_sb = new StringBuilder(); }
|
||||
return m_sb;
|
||||
}
|
||||
}
|
||||
void DEBUG(StringBuilder msg) { Debug.Log(msg); }
|
||||
void WARNING(StringBuilder msg) { Debug.LogWarning(msg); }
|
||||
|
||||
/// <summary>
|
||||
/// OpenXR specification <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_HTC_hand_interaction">12.69. XR_HTC_hand_interaction</see>.
|
||||
/// </summary>
|
||||
public const string kOpenxrExtensionString = "XR_HTC_hand_interaction";
|
||||
|
||||
/// <summary>
|
||||
/// The feature id string. This is used to give the feature a well known id for reference.
|
||||
/// </summary>
|
||||
public const string featureId = "vive.openxr.feature.hand.interaction";
|
||||
|
||||
/// <summary>
|
||||
/// The interaction profile string used to reference the hand interaction input device.
|
||||
/// </summary>
|
||||
private const string profile = "/interaction_profiles/htc/hand_interaction";
|
||||
|
||||
private const string leftHand = "/user/hand_htc/left";
|
||||
private const string rightHand = "/user/hand_htc/right";
|
||||
|
||||
/// <summary>
|
||||
/// Constant for a float interaction binding '.../input/select/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
|
||||
/// </summary>
|
||||
public const string selectValue = "/input/select/value";
|
||||
|
||||
/// <summary>
|
||||
/// Constant for a float interaction binding '.../input/squeeze/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
|
||||
/// </summary>
|
||||
public const string gripValue = "/input/squeeze/value";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constant for a pose interaction binding '.../input/aim/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
|
||||
/// </summary>
|
||||
private const string pointerPose = "/input/aim/pose";
|
||||
|
||||
/// <summary>
|
||||
/// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
|
||||
/// </summary>
|
||||
public const string devicePose = "/input/grip/pose";
|
||||
|
||||
|
||||
[Preserve, InputControlLayout(displayName = "Vive Hand Interaction (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" }, isGenericTypeOfDevice = true)]
|
||||
public class HandInteractionDevice : OpenXRDevice
|
||||
{
|
||||
const string LOG_TAG = "VIVE.OpenXR.Hand.ViveHandInteraction.HandInteractionDevice";
|
||||
void DEBUG(string msg) { Debug.Log(LOG_TAG + " " + msg); }
|
||||
|
||||
/// <summary>
|
||||
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the <see cref="ViveHandInteraction.selectValue"/> OpenXR binding.
|
||||
/// </summary>
|
||||
[Preserve, InputControl(aliases = new[] { "selectAxis, pinchStrength" }, usage = "Select")]
|
||||
public AxisControl selectValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="AxisControl"/> representing information from the <see cref="ViveHandInteraction.squeeze"/> OpenXR binding.
|
||||
/// </summary>
|
||||
[Preserve, InputControl(aliases = new[] { "GripAxis" }, usage = "Grip")]
|
||||
public AxisControl gripValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="PoseControl"/> representing information from the <see cref="ViveHandInteraction.devicePose"/> OpenXR binding.
|
||||
/// </summary>
|
||||
[Preserve, InputControl(offset = 0, aliases = new[] { "device", "gripPose" }, usage = "Device")]
|
||||
public PoseControl devicePose { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="PoseControl"/> representing the <see cref="ViveHandInteraction.pointerPose"/> OpenXR binding.
|
||||
/// </summary>
|
||||
[Preserve, InputControl(offset = 0, alias = "aimPose", usage = "Pointer")]
|
||||
public PoseControl pointerPose { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) required for backwards compatibility with the XRSDK layouts. This represents the overall tracking state of the device. This value is equivalent to mapping devicePose/isTracked.
|
||||
/// </summary>
|
||||
[Preserve, InputControl(offset = 8, usage = "IsTracked")]
|
||||
public ButtonControl isTracked { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A [IntegerControl](xref:UnityEngine.InputSystem.Controls.IntegerControl) required for backwards compatibility with the XRSDK layouts. This represents the bit flag set to indicate what data is valid. This value is equivalent to mapping devicePose/trackingState.
|
||||
/// </summary>
|
||||
[Preserve, InputControl(offset = 12, usage = "TrackingState")]
|
||||
public IntegerControl trackingState { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the device position. For the VIVE Focus 3 device, this is both the device and the pointer position. This value is equivalent to mapping devicePose/position.
|
||||
/// </summary>
|
||||
[Preserve, InputControl(offset = 16, alias = "gripPosition")]
|
||||
public Vector3Control devicePosition { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the device orientation. For the VIVE Focus 3 device, this is both the device and the pointer rotation. This value is equivalent to mapping devicePose/rotation.
|
||||
/// </summary>
|
||||
[Preserve, InputControl(offset = 28, alias = "gripOrientation")]
|
||||
public QuaternionControl deviceRotation { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal call used to assign controls to the the correct element.
|
||||
/// </summary>
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
DEBUG("FinishSetup() interfaceName: " + description.interfaceName
|
||||
+ ", deviceClass: " + description.deviceClass
|
||||
+ ", product: " + description.product
|
||||
+ ", serial: " + description.serial
|
||||
+ ", version: " + description.version);
|
||||
|
||||
base.FinishSetup();
|
||||
|
||||
selectValue = GetChildControl<AxisControl>("selectValue");
|
||||
gripValue = GetChildControl<AxisControl>("gripValue");
|
||||
|
||||
devicePose = GetChildControl<PoseControl>("devicePose");
|
||||
pointerPose = GetChildControl<PoseControl>("pointerPose");
|
||||
|
||||
isTracked = GetChildControl<ButtonControl>("isTracked");
|
||||
trackingState = GetChildControl<IntegerControl>("trackingState");
|
||||
devicePosition = GetChildControl<Vector3Control>("devicePosition");
|
||||
deviceRotation = GetChildControl<QuaternionControl>("deviceRotation");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable
|
||||
private bool m_XrInstanceCreated = false;
|
||||
#pragma warning restore
|
||||
private XrInstance m_XrInstance = 0;
|
||||
/// <summary>
|
||||
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateInstance">xrCreateInstance</see> is done.
|
||||
/// </summary>
|
||||
/// <param name="xrInstance">The created instance.</param>
|
||||
/// <returns>True for valid <see cref="XrInstance">XrInstance</see></returns>
|
||||
protected override bool OnInstanceCreate(ulong xrInstance)
|
||||
{
|
||||
// Requires the eye tracking extension
|
||||
if (!OpenXRRuntime.IsExtensionEnabled(kOpenxrExtensionString))
|
||||
{
|
||||
sb.Clear().Append(LOG_TAG).Append("OnInstanceCreate() ").Append(kOpenxrExtensionString).Append(" is NOT enabled."); WARNING(sb);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_XrInstanceCreated = true;
|
||||
m_XrInstance = xrInstance;
|
||||
sb.Clear().Append(LOG_TAG).Append("OnInstanceCreate() " + m_XrInstance); DEBUG(sb);
|
||||
|
||||
return base.OnInstanceCreate(xrInstance);
|
||||
}
|
||||
|
||||
private const string kLayoutName = "ViveHandInteraction";
|
||||
private const string kDeviceLocalizedName = "Vive Hand Interaction OpenXR";
|
||||
/// <summary>
|
||||
/// Registers the <see cref="HandInteractionDevice"/> layout with the Input System.
|
||||
/// </summary>
|
||||
protected override void RegisterDeviceLayout()
|
||||
{
|
||||
sb.Clear().Append(LOG_TAG).Append("RegisterDeviceLayout() Layout: ").Append(kLayoutName)
|
||||
.Append(", Product: ").Append(kDeviceLocalizedName);
|
||||
DEBUG(sb);
|
||||
InputSystem.RegisterLayout(typeof(HandInteractionDevice),
|
||||
kLayoutName,
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(XRUtilities.InterfaceMatchAnyVersion)
|
||||
.WithProduct(kDeviceLocalizedName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the <see cref="HandInteractionDevice"/> layout from the Input System.
|
||||
/// </summary>
|
||||
protected override void UnregisterDeviceLayout()
|
||||
{
|
||||
sb.Clear().Append(LOG_TAG).Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
|
||||
InputSystem.RemoveLayout(kLayoutName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers action maps to Unity XR.
|
||||
/// </summary>
|
||||
protected override void RegisterActionMapsWithRuntime()
|
||||
{
|
||||
sb.Clear().Append(LOG_TAG).Append("RegisterActionMapsWithRuntime() Action map vivehandinteraction")
|
||||
.Append(", localizedName: ").Append(kDeviceLocalizedName)
|
||||
.Append(", desiredInteractionProfile").Append(profile);
|
||||
DEBUG(sb);
|
||||
|
||||
ActionMapConfig actionMap = new ActionMapConfig()
|
||||
{
|
||||
name = "vivehandinteraction",
|
||||
localizedName = kDeviceLocalizedName,
|
||||
desiredInteractionProfile = profile,
|
||||
manufacturer = "HTC",
|
||||
serialNumber = "",
|
||||
deviceInfos = new List<DeviceConfig>()
|
||||
{
|
||||
new DeviceConfig()
|
||||
{
|
||||
characteristics = InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.HandTracking | InputDeviceCharacteristics.Left,
|
||||
userPath = leftHand // "/user/hand_htc/left"
|
||||
},
|
||||
new DeviceConfig()
|
||||
{
|
||||
characteristics = InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.HandTracking | InputDeviceCharacteristics.Right,
|
||||
userPath = rightHand // "/user/hand_htc/right"
|
||||
}
|
||||
},
|
||||
actions = new List<ActionConfig>()
|
||||
{
|
||||
// Grip Axis
|
||||
new ActionConfig()
|
||||
{
|
||||
name = "gripValue",
|
||||
localizedName = "Grip Axis",
|
||||
type = ActionType.Axis1D,
|
||||
usages = new List<string>()
|
||||
{
|
||||
"Grip"
|
||||
},
|
||||
bindings = new List<ActionBinding>()
|
||||
{
|
||||
new ActionBinding()
|
||||
{
|
||||
interactionPath = gripValue,
|
||||
interactionProfileName = profile,
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select Axis
|
||||
new ActionConfig()
|
||||
{
|
||||
name = "selectValue",
|
||||
localizedName = "Select Axis",
|
||||
type = ActionType.Axis1D,
|
||||
usages = new List<string>()
|
||||
{
|
||||
"Select"
|
||||
},
|
||||
bindings = new List<ActionBinding>()
|
||||
{
|
||||
new ActionBinding()
|
||||
{
|
||||
interactionPath = selectValue,
|
||||
interactionProfileName = profile,
|
||||
}
|
||||
}
|
||||
},
|
||||
// Grip pose
|
||||
new ActionConfig()
|
||||
{
|
||||
name = "devicePose",
|
||||
localizedName = "Device Pose",
|
||||
type = ActionType.Pose,
|
||||
usages = new List<string>()
|
||||
{
|
||||
"Device"
|
||||
},
|
||||
bindings = new List<ActionBinding>()
|
||||
{
|
||||
new ActionBinding()
|
||||
{
|
||||
interactionPath = devicePose,
|
||||
interactionProfileName = profile,
|
||||
}
|
||||
}
|
||||
},
|
||||
// Pointer Pose
|
||||
new ActionConfig()
|
||||
{
|
||||
name = "pointerPose",
|
||||
localizedName = "Pointer Pose",
|
||||
type = ActionType.Pose,
|
||||
usages = new List<string>()
|
||||
{
|
||||
"Pointer"
|
||||
},
|
||||
bindings = new List<ActionBinding>()
|
||||
{
|
||||
new ActionBinding()
|
||||
{
|
||||
interactionPath = pointerPose,
|
||||
interactionProfileName = profile,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AddActionMap(actionMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec058e82c4fd831488e0fe81bb41d440
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c20ac17e6a9698a4ab9e7ac290153915
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3276899460ff6249b597e331d84b121
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
# 12.28 XR_EXT_hand_tracking
|
||||
## Name String
|
||||
XR_EXT_hand_tracking
|
||||
## Revision
|
||||
4
|
||||
## New Object Types
|
||||
- [XrHandTrackerEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandTrackerEXT)
|
||||
## New Enum Constants
|
||||
- [XR_HAND_JOINT_COUNT_EXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XR_HAND_JOINT_COUNT_EXT)
|
||||
[XrObjectType](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrObjectType) enumeration is extended with:
|
||||
- XR_OBJECT_TYPE_HAND_TRACKER_EXT
|
||||
[XrStructureType](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrStructureType) enumeration is extended with:
|
||||
- XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT
|
||||
- XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT
|
||||
- XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT
|
||||
- XR_TYPE_HAND_JOINT_LOCATIONS_EXT
|
||||
- XR_TYPE_HAND_JOINT_VELOCITIES_EXT
|
||||
## New Enums
|
||||
- [XrHandEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandEXT)
|
||||
- [XrHandJointEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandJointEXT)
|
||||
- [XrHandJointSetEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandJointSetEXT)
|
||||
## New Structures
|
||||
- [XrSystemHandTrackingPropertiesEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrSystemHandTrackingPropertiesEXT)
|
||||
- [XrHandTrackerCreateInfoEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandTrackerCreateInfoEXT)
|
||||
- [XrHandJointsLocateInfoEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandJointsLocateInfoEXT)
|
||||
- [XrHandJointLocationEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandJointLocationEXT)
|
||||
- [XrHandJointVelocityEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandJointVelocityEXT)
|
||||
- [XrHandJointLocationsEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandJointLocationsEXT)
|
||||
- [XrHandJointVelocitiesEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandJointVelocitiesEXT)
|
||||
## New Functions
|
||||
- [xrCreateHandTrackerEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#xrCreateHandTrackerEXT)
|
||||
- [xrDestroyHandTrackerEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#xrDestroyHandTrackerEXT)
|
||||
- [xrLocateHandJointsEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#xrLocateHandJointsEXT)
|
||||
|
||||
## VIVE Plugin
|
||||
|
||||
After enabling the "VIVE Focus3 Hand Tracking" from "Project Settings > XR Plugin-in Management > OpenXR > Android Tab", you can retrieve the [XrHandJointLocationEXT](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XrHandJointLocationEXT) by using the following code.
|
||||
|
||||
using VIVE.OpenXR.Hand;
|
||||
|
||||
XrHandJointLocationEXT[] HandjointLocations = new XrHandJointLocationEXT[(int)XrHandJointEXT.XR_HAND_JOINT_MAX_ENUM_EXT];
|
||||
var feature = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
|
||||
if (feature && feature.GetJointLocations(isLeft, out HandjointLocations))
|
||||
{
|
||||
// now you have the hand joint data
|
||||
}
|
||||
|
||||
Refer to <VIVE OpenXR sample path>/Plugin/Input/Scripts/VIVE/RenderHand.cs about the sample code.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05f3bff8b2a4d0a4ea96ffedf619e30c
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9ee0f2aa88738b47ab943ec3a3b52a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,820 @@
|
||||
// "VIVE SDK
|
||||
// © 2020 HTC Corporation. All Rights Reserved.
|
||||
//
|
||||
// Unless otherwise required by copyright law and practice,
|
||||
// upon the execution of HTC SDK license agreement,
|
||||
// HTC grants you access to and use of the VIVE SDK(s).
|
||||
// You shall fully comply with all of HTC’s SDK license agreement terms and
|
||||
// conditions signed by you and all SDK and API requirements,
|
||||
// specifications, and documentation provided by HTC to You."
|
||||
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using UnityEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine.XR;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
namespace VIVE.OpenXR.Hand
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "VIVE XR Hand Tracking",
|
||||
BuildTargetGroups = new[] { BuildTargetGroup.Android , BuildTargetGroup.Standalone },
|
||||
Company = "HTC",
|
||||
Desc = "Support the Hand Tracking extension.",
|
||||
DocumentationLink = "..\\Documentation",
|
||||
OpenxrExtensionStrings = kOpenxrExtensionString,
|
||||
Version = "4.0.0",
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
public class ViveHandTracking : OpenXRFeature
|
||||
{
|
||||
const string LOG_TAG = "VIVE.OpenXR.Hand.ViveHandTracking";
|
||||
void DEBUG(string msg) { Debug.Log(LOG_TAG + " " + msg); }
|
||||
void WARNING(string msg) { Debug.LogWarning(LOG_TAG + " " + msg); }
|
||||
void ERROR(string msg) { Debug.LogError(LOG_TAG + " " + msg); }
|
||||
|
||||
/// <summary>
|
||||
/// OpenXR specification <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_hand_tracking">12.29 XR_EXT_hand_tracking</see>.
|
||||
/// </summary>
|
||||
public const string kOpenxrExtensionString = "XR_EXT_hand_tracking";
|
||||
/// <summary>
|
||||
/// The feature id string. This is used to give the feature a well known id for reference.
|
||||
/// </summary>
|
||||
public const string featureId = "vive.openxr.feature.hand.tracking";
|
||||
|
||||
#region OpenXR Life Cycle
|
||||
private bool m_XrInstanceCreated = false;
|
||||
private XrInstance m_XrInstance = 0;
|
||||
/// <summary>
|
||||
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateInstance">xrCreateInstance</see> is done.
|
||||
/// </summary>
|
||||
/// <param name="xrInstance">The created instance.</param>
|
||||
/// <returns>True for valid <see cref="XrInstance">XrInstance</see></returns>
|
||||
protected override bool OnInstanceCreate(ulong xrInstance)
|
||||
{
|
||||
if (!OpenXRRuntime.IsExtensionEnabled(kOpenxrExtensionString))
|
||||
{
|
||||
WARNING("OnInstanceCreate() " + kOpenxrExtensionString + " is NOT enabled.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_XrInstanceCreated = true;
|
||||
m_XrInstance = xrInstance;
|
||||
DEBUG("OnInstanceCreate() " + m_XrInstance);
|
||||
|
||||
return GetXrFunctionDelegates(m_XrInstance);
|
||||
}
|
||||
/// <summary>
|
||||
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrDestroyInstance">xrDestroyInstance</see> is done.
|
||||
/// </summary>
|
||||
/// <param name="xrInstance">The instance to destroy.</param>
|
||||
protected override void OnInstanceDestroy(ulong xrInstance)
|
||||
{
|
||||
m_XrInstanceCreated = false;
|
||||
m_XrInstance = 0;
|
||||
DEBUG("OnInstanceDestroy() " + xrInstance);
|
||||
}
|
||||
|
||||
private XrSystemId m_XrSystemId = 0;
|
||||
/// <summary>
|
||||
/// Called when the <see cref="XrSystemId">XrSystemId</see> retrieved by <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrGetSystem">xrGetSystem</see> is changed.
|
||||
/// </summary>
|
||||
/// <param name="xrSystem">The system id.</param>
|
||||
protected override void OnSystemChange(ulong xrSystem)
|
||||
{
|
||||
m_XrSystemId = xrSystem;
|
||||
DEBUG("OnSystemChange() " + m_XrSystemId);
|
||||
}
|
||||
|
||||
private bool m_XrSessionCreated = false;
|
||||
private XrSession m_XrSession = 0;
|
||||
private bool hasReferenceSpaceLocal = false, hasReferenceSpaceStage = false;
|
||||
private XrSpace m_ReferenceSpaceLocal = 0, m_ReferenceSpaceStage = 0;
|
||||
|
||||
private bool hasLeftHandTracker = false, hasRightHandTracker = false;
|
||||
private XrHandTrackerEXT leftHandTracker = 0, rightHandTracker = 0;
|
||||
/// <summary>
|
||||
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateSession">xrCreateSession</see> is done.
|
||||
/// </summary>
|
||||
/// <param name="xrSession">The created session ID.</param>
|
||||
protected override void OnSessionCreate(ulong xrSession)
|
||||
{
|
||||
m_XrSession = xrSession;
|
||||
m_XrSessionCreated = true;
|
||||
DEBUG("OnSessionCreate() " + m_XrSession);
|
||||
|
||||
// Enumerate supported reference space types and create the XrSpace.
|
||||
XrReferenceSpaceType[] spaces = new XrReferenceSpaceType[Enum.GetNames(typeof(XrReferenceSpaceType)).Count()];
|
||||
UInt32 spaceCountOutput;
|
||||
#pragma warning disable 0618
|
||||
if (EnumerateReferenceSpaces(
|
||||
spaceCapacityInput: 0,
|
||||
spaceCountOutput: out spaceCountOutput,
|
||||
spaces: out spaces[0]) == XrResult.XR_SUCCESS)
|
||||
#pragma warning restore 0618
|
||||
{
|
||||
DEBUG("OnSessionCreate() spaceCountOutput: " + spaceCountOutput);
|
||||
|
||||
Array.Resize(ref spaces, (int)spaceCountOutput);
|
||||
#pragma warning disable 0618
|
||||
if (EnumerateReferenceSpaces(
|
||||
spaceCapacityInput: spaceCountOutput,
|
||||
spaceCountOutput: out spaceCountOutput,
|
||||
spaces: out spaces[0]) == XrResult.XR_SUCCESS)
|
||||
#pragma warning restore 0618
|
||||
{
|
||||
XrReferenceSpaceCreateInfo createInfo;
|
||||
|
||||
/// Create m_ReferenceSpaceLocal
|
||||
if (IsReferenceSpaceTypeSupported(spaceCountOutput, spaces, XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_LOCAL))
|
||||
{
|
||||
createInfo.type = XrStructureType.XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
|
||||
createInfo.next = IntPtr.Zero;
|
||||
createInfo.referenceSpaceType = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_LOCAL;//referenceSpaceType;
|
||||
createInfo.poseInReferenceSpace.orientation = new XrQuaternionf(0, 0, 0, 1);
|
||||
createInfo.poseInReferenceSpace.position = new XrVector3f(0, 0, 0);
|
||||
|
||||
#pragma warning disable 0618
|
||||
if (CreateReferenceSpace(
|
||||
createInfo: ref createInfo,
|
||||
space: out m_ReferenceSpaceLocal) == XrResult.XR_SUCCESS)
|
||||
#pragma warning restore 0618
|
||||
{
|
||||
hasReferenceSpaceLocal = true;
|
||||
DEBUG("OnSessionCreate() CreateReferenceSpace LOCAL: " + m_ReferenceSpaceLocal);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("OnSessionCreate() CreateReferenceSpace LOCAL failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Create m_ReferenceSpaceStage
|
||||
if (IsReferenceSpaceTypeSupported(spaceCountOutput, spaces, XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_STAGE))
|
||||
{
|
||||
createInfo.type = XrStructureType.XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
|
||||
createInfo.next = IntPtr.Zero;
|
||||
createInfo.referenceSpaceType = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_STAGE;
|
||||
createInfo.poseInReferenceSpace.orientation = new XrQuaternionf(0, 0, 0, 1);
|
||||
createInfo.poseInReferenceSpace.position = new XrVector3f(0, 0, 0);
|
||||
|
||||
#pragma warning disable 0618
|
||||
if (CreateReferenceSpace(
|
||||
createInfo: ref createInfo,
|
||||
space: out m_ReferenceSpaceStage) == XrResult.XR_SUCCESS)
|
||||
#pragma warning restore 0618
|
||||
{
|
||||
hasReferenceSpaceStage = true;
|
||||
DEBUG("OnSessionCreate() CreateReferenceSpace STAGE: " + m_ReferenceSpaceStage);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("OnSessionCreate() CreateReferenceSpace STAGE failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("OnSessionCreate() EnumerateReferenceSpaces(" + spaceCountOutput + ") failed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("OnSessionCreate() EnumerateReferenceSpaces(0) failed.");
|
||||
}
|
||||
|
||||
{ // left hand tracker
|
||||
if (CreateHandTrackers(true, out XrHandTrackerEXT value))
|
||||
{
|
||||
hasLeftHandTracker = true;
|
||||
leftHandTracker = value;
|
||||
DEBUG("OnSessionCreate() leftHandTracker " + leftHandTracker);
|
||||
}
|
||||
}
|
||||
{ // right hand tracker
|
||||
if (CreateHandTrackers(false, out XrHandTrackerEXT value))
|
||||
{
|
||||
hasRightHandTracker = true;
|
||||
rightHandTracker = value;
|
||||
DEBUG("OnSessionCreate() rightHandTracker " + rightHandTracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrDestroySession">xrDestroySession</see> is done.
|
||||
/// </summary>
|
||||
/// <param name="xrSession">The session ID to destroy.</param>
|
||||
protected override void OnSessionDestroy(ulong xrSession)
|
||||
{
|
||||
DEBUG("OnSessionDestroy() " + xrSession);
|
||||
|
||||
// Reference Space is binding with xrSession so we destroy the xrSpace when xrSession is destroyed.
|
||||
if (hasReferenceSpaceLocal)
|
||||
{
|
||||
#pragma warning disable 0618
|
||||
if (DestroySpace(m_ReferenceSpaceLocal) == XrResult.XR_SUCCESS)
|
||||
#pragma warning restore 0618
|
||||
{
|
||||
DEBUG("OnSessionDestroy() DestroySpace LOCAL " + m_ReferenceSpaceLocal);
|
||||
m_ReferenceSpaceLocal = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("OnSessionDestroy() DestroySpace LOCAL " + m_ReferenceSpaceLocal + " failed.");
|
||||
}
|
||||
hasReferenceSpaceLocal = false;
|
||||
}
|
||||
if (hasReferenceSpaceStage)
|
||||
{
|
||||
#pragma warning disable 0618
|
||||
if (DestroySpace(m_ReferenceSpaceStage) == XrResult.XR_SUCCESS)
|
||||
#pragma warning restore 0618
|
||||
{
|
||||
DEBUG("OnSessionDestroy() DestroySpace STAGE " + m_ReferenceSpaceStage);
|
||||
m_ReferenceSpaceStage = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("OnSessionDestroy() DestroySpace STAGE " + m_ReferenceSpaceStage + " failed.");
|
||||
}
|
||||
hasReferenceSpaceStage = false;
|
||||
}
|
||||
|
||||
// Hand Tracking is binding with xrSession so we destroy the hand trackers when xrSession is destroyed.
|
||||
if (hasLeftHandTracker)
|
||||
{
|
||||
if (DestroyHandTrackerEXT(leftHandTracker) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
DEBUG("OnSessionDestroy() Left DestroyHandTrackerEXT " + leftHandTracker);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("OnSessionDestroy() Left DestroyHandTrackerEXT " + leftHandTracker + " failed.");
|
||||
}
|
||||
hasLeftHandTracker = false;
|
||||
}
|
||||
if (hasRightHandTracker)
|
||||
{
|
||||
if (DestroyHandTrackerEXT(rightHandTracker) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
DEBUG("OnSessionDestroy() Right DestroyHandTrackerEXT " + rightHandTracker);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("OnSessionDestroy() Right DestroyHandTrackerEXT " + rightHandTracker + " failed.");
|
||||
}
|
||||
hasRightHandTracker = false;
|
||||
}
|
||||
|
||||
m_XrSession = 0;
|
||||
m_XrSessionCreated = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region OpenXR function delegates
|
||||
/// xrGetInstanceProcAddr
|
||||
OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddr;
|
||||
|
||||
/// xrGetSystemProperties
|
||||
OpenXRHelper.xrGetSystemPropertiesDelegate xrGetSystemProperties;
|
||||
/// <summary>
|
||||
/// An application can call GetSystemProperties to retrieve information about the system such as vendor ID, system name, and graphics and tracking properties.
|
||||
/// </summary>
|
||||
/// <param name="properties">Points to an instance of the XrSystemProperties structure, that will be filled with returned information.</param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
[Obsolete("This function will become private in next release")]
|
||||
public XrResult GetSystemProperties(ref XrSystemProperties properties)
|
||||
{
|
||||
if (!m_XrSessionCreated)
|
||||
{
|
||||
ERROR("GetSystemProperties() XR_ERROR_SESSION_LOST.");
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
}
|
||||
if (!m_XrInstanceCreated)
|
||||
{
|
||||
ERROR("GetSystemProperties() XR_ERROR_INSTANCE_LOST.");
|
||||
return XrResult.XR_ERROR_INSTANCE_LOST;
|
||||
}
|
||||
|
||||
return xrGetSystemProperties(m_XrInstance, m_XrSystemId, ref properties);
|
||||
}
|
||||
|
||||
/// xrEnumerateReferenceSpaces
|
||||
OpenXRHelper.xrEnumerateReferenceSpacesDelegate xrEnumerateReferenceSpaces;
|
||||
/// <summary>
|
||||
/// Enumerates the set of reference space types that this runtime supports for a given session. Runtimes must always return identical buffer contents from this enumeration for the lifetime of the session.
|
||||
/// </summary>
|
||||
/// <param name="spaceCapacityInput">The capacity of the spaces array, or 0 to indicate a request to retrieve the required capacity.</param>
|
||||
/// <param name="spaceCountOutput">A pointer to the count of spaces written, or a pointer to the required capacity in the case that spaceCapacityInput is insufficient.</param>
|
||||
/// <param name="spaces">A pointer to an application-allocated array that will be filled with the enumerant of each supported reference space. It can be NULL if spaceCapacityInput is 0.</param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
[Obsolete("This function will become private in next release")]
|
||||
public XrResult EnumerateReferenceSpaces(UInt32 spaceCapacityInput, out UInt32 spaceCountOutput, out XrReferenceSpaceType spaces)
|
||||
{
|
||||
if (!m_XrSessionCreated)
|
||||
{
|
||||
ERROR("EnumerateReferenceSpaces() XR_ERROR_SESSION_LOST.");
|
||||
spaceCountOutput = 0;
|
||||
spaces = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT;
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
}
|
||||
if (!m_XrInstanceCreated)
|
||||
{
|
||||
ERROR("EnumerateReferenceSpaces() XR_ERROR_SESSION_LOST.");
|
||||
spaceCountOutput = 0;
|
||||
spaces = XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT;
|
||||
return XrResult.XR_ERROR_INSTANCE_LOST;
|
||||
}
|
||||
|
||||
return xrEnumerateReferenceSpaces(m_XrSession, spaceCapacityInput, out spaceCountOutput, out spaces);
|
||||
}
|
||||
|
||||
/// xrCreateReferenceSpace
|
||||
OpenXRHelper.xrCreateReferenceSpaceDelegate xrCreateReferenceSpace;
|
||||
/// <summary>
|
||||
/// Creates an <see cref="XrSpace">XrSpace</see> handle based on a chosen reference space. Application can provide an <see cref="XrPosef">XrPosef</see> to define the position and orientation of the new space’s origin within the natural reference frame of the reference space.
|
||||
/// </summary>
|
||||
/// <param name="createInfo">The XrReferenceSpaceCreateInfo used to specify the space.</param>
|
||||
/// <param name="space">The returned XrSpace handle.</param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
[Obsolete("This function will become private in next release")]
|
||||
public XrResult CreateReferenceSpace(ref XrReferenceSpaceCreateInfo createInfo, out XrSpace space)
|
||||
{
|
||||
if (!m_XrSessionCreated)
|
||||
{
|
||||
ERROR("CreateReferenceSpace() XR_ERROR_SESSION_LOST.");
|
||||
space = 0;
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
}
|
||||
if (!m_XrInstanceCreated)
|
||||
{
|
||||
ERROR("CreateReferenceSpace() XR_ERROR_INSTANCE_LOST.");
|
||||
space = 0;
|
||||
return XrResult.XR_ERROR_INSTANCE_LOST;
|
||||
}
|
||||
|
||||
return xrCreateReferenceSpace(m_XrSession, ref createInfo, out space);
|
||||
}
|
||||
|
||||
/// xrDestroySpace
|
||||
OpenXRHelper.xrDestroySpaceDelegate xrDestroySpace;
|
||||
/// <summary>
|
||||
/// <see cref="XrSpace">XrSpace</see> handles are destroyed using DestroySpace. The runtime may still use this space if there are active dependencies (e.g, compositions in progress).
|
||||
/// </summary>
|
||||
/// <param name="space">Must be a valid XrSpace handle.</param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
[Obsolete("This function will become private in next release")]
|
||||
public XrResult DestroySpace(XrSpace space)
|
||||
{
|
||||
if (!m_XrSessionCreated)
|
||||
{
|
||||
ERROR("DestroySpace() XR_ERROR_SESSION_LOST.");
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
}
|
||||
if (!m_XrInstanceCreated)
|
||||
{
|
||||
ERROR("DestroySpace() XR_ERROR_INSTANCE_LOST.");
|
||||
return XrResult.XR_ERROR_INSTANCE_LOST;
|
||||
}
|
||||
|
||||
return xrDestroySpace(space);
|
||||
}
|
||||
|
||||
/// xrCreateHandTrackerEXT
|
||||
ViveHandTrackingHelper.xrCreateHandTrackerEXTDelegate xrCreateHandTrackerEXT;
|
||||
/// <summary>
|
||||
/// An application can create an <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> handle using CreateHandTrackerEXT function.
|
||||
/// </summary>
|
||||
/// <param name="createInfo">The XrHandTrackerCreateInfoEXT used to specify the hand tracker.</param>
|
||||
/// <param name="handTracker">The returned XrHandTrackerEXT handle.</param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
public XrResult CreateHandTrackerEXT(ref XrHandTrackerCreateInfoEXT createInfo, out XrHandTrackerEXT handTracker)
|
||||
{
|
||||
if (!m_XrSessionCreated)
|
||||
{
|
||||
ERROR("CreateHandTrackerEXT() XR_ERROR_SESSION_LOST.");
|
||||
handTracker = 0;
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
}
|
||||
if (!m_XrInstanceCreated)
|
||||
{
|
||||
ERROR("CreateHandTrackerEXT() XR_ERROR_INSTANCE_LOST.");
|
||||
handTracker = 0;
|
||||
return XrResult.XR_ERROR_INSTANCE_LOST;
|
||||
}
|
||||
|
||||
if (createInfo.hand == XrHandEXT.XR_HAND_LEFT_EXT && hasLeftHandTracker)
|
||||
{
|
||||
DEBUG("CreateHandTrackerEXT() Left tracker " + leftHandTracker + " already created.");
|
||||
handTracker = leftHandTracker;
|
||||
return XrResult.XR_SUCCESS;
|
||||
}
|
||||
if (createInfo.hand == XrHandEXT.XR_HAND_RIGHT_EXT && hasRightHandTracker)
|
||||
{
|
||||
DEBUG("CreateHandTrackerEXT() Right tracker " + rightHandTracker + " already created.");
|
||||
handTracker = rightHandTracker;
|
||||
return XrResult.XR_SUCCESS;
|
||||
}
|
||||
|
||||
return xrCreateHandTrackerEXT(m_XrSession, ref createInfo, out handTracker);
|
||||
}
|
||||
|
||||
/// xrDestroyHandTrackerEXT
|
||||
ViveHandTrackingHelper.xrDestroyHandTrackerEXTDelegate xrDestroyHandTrackerEXT;
|
||||
/// <summary>
|
||||
/// Releases the handTracker and the underlying resources when finished with hand tracking experiences.
|
||||
/// </summary>
|
||||
/// <param name="handTracker">An XrHandTrackerEXT previously created by <see cref="CreateHandTrackerEXT">CreateHandTrackerEXT</see>.</param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
public XrResult DestroyHandTrackerEXT(XrHandTrackerEXT handTracker)
|
||||
{
|
||||
if (!m_XrSessionCreated)
|
||||
{
|
||||
ERROR("DestroyHandTrackerEXT() XR_ERROR_SESSION_LOST.");
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
}
|
||||
if (!m_XrInstanceCreated)
|
||||
{
|
||||
ERROR("DestroyHandTrackerEXT() XR_ERROR_INSTANCE_LOST.");
|
||||
return XrResult.XR_ERROR_INSTANCE_LOST;
|
||||
}
|
||||
|
||||
return xrDestroyHandTrackerEXT(handTracker);
|
||||
}
|
||||
|
||||
/// xrLocateHandJointsEXT
|
||||
ViveHandTrackingHelper.xrLocateHandJointsEXTDelegate xrLocateHandJointsEXT;
|
||||
/// <summary>
|
||||
/// The LocateHandJointsEXT function locates an array of hand joints to a base space at given time.
|
||||
/// </summary>
|
||||
/// <param name="handTracker">An <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> previously created by <see cref="ViveHandTracking.CreateHandTrackerEXT(ref XrHandTrackerCreateInfoEXT, out XrHandTrackerEXT)">CreateHandTrackerEXT</see>.</param>
|
||||
/// <param name="locateInfo">A pointer to <see cref="XrHandJointsLocateInfoEXT">XrHandJointsLocateInfoEXT</see> describing information to locate hand joints.</param>
|
||||
/// <param name="locations">A pointer to <see cref="XrHandJointLocationsEXT">XrHandJointLocationsEXT</see> receiving the returned hand joint locations.</param>
|
||||
/// <returns></returns>
|
||||
public XrResult LocateHandJointsEXT(XrHandTrackerEXT handTracker, XrHandJointsLocateInfoEXT locateInfo, ref XrHandJointLocationsEXT locations)
|
||||
{
|
||||
if (!m_XrSessionCreated)
|
||||
{
|
||||
ERROR("LocateHandJointsEXT() XR_ERROR_SESSION_LOST.");
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
}
|
||||
if (!m_XrInstanceCreated)
|
||||
{
|
||||
ERROR("LocateHandJointsEXT() XR_ERROR_INSTANCE_LOST.");
|
||||
return XrResult.XR_ERROR_INSTANCE_LOST;
|
||||
}
|
||||
|
||||
return xrLocateHandJointsEXT(handTracker, locateInfo, ref locations);
|
||||
}
|
||||
|
||||
private bool GetXrFunctionDelegates(XrInstance xrInstance)
|
||||
{
|
||||
/// xrGetInstanceProcAddr
|
||||
if (xrGetInstanceProcAddr != null && xrGetInstanceProcAddr != IntPtr.Zero)
|
||||
{
|
||||
DEBUG("Get function pointer of xrGetInstanceProcAddr.");
|
||||
XrGetInstanceProcAddr = Marshal.GetDelegateForFunctionPointer(
|
||||
xrGetInstanceProcAddr,
|
||||
typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate)) as OpenXRHelper.xrGetInstanceProcAddrDelegate;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("xrGetInstanceProcAddr");
|
||||
return false;
|
||||
}
|
||||
|
||||
IntPtr funcPtr = IntPtr.Zero;
|
||||
/// xrGetSystemProperties
|
||||
if (XrGetInstanceProcAddr(xrInstance, "xrGetSystemProperties", out funcPtr) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
if (funcPtr != IntPtr.Zero)
|
||||
{
|
||||
DEBUG("Get function pointer of xrGetSystemProperties.");
|
||||
xrGetSystemProperties = Marshal.GetDelegateForFunctionPointer(
|
||||
funcPtr,
|
||||
typeof(OpenXRHelper.xrGetSystemPropertiesDelegate)) as OpenXRHelper.xrGetSystemPropertiesDelegate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("xrGetSystemProperties");
|
||||
return false;
|
||||
}
|
||||
/// xrEnumerateReferenceSpaces
|
||||
if (XrGetInstanceProcAddr(xrInstance, "xrEnumerateReferenceSpaces", out funcPtr) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
if (funcPtr != IntPtr.Zero)
|
||||
{
|
||||
DEBUG("Get function pointer of xrEnumerateReferenceSpaces.");
|
||||
xrEnumerateReferenceSpaces = Marshal.GetDelegateForFunctionPointer(
|
||||
funcPtr,
|
||||
typeof(OpenXRHelper.xrEnumerateReferenceSpacesDelegate)) as OpenXRHelper.xrEnumerateReferenceSpacesDelegate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("xrEnumerateReferenceSpaces");
|
||||
return false;
|
||||
}
|
||||
/// xrCreateReferenceSpace
|
||||
if (XrGetInstanceProcAddr(xrInstance, "xrCreateReferenceSpace", out funcPtr) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
if (funcPtr != IntPtr.Zero)
|
||||
{
|
||||
DEBUG("Get function pointer of xrCreateReferenceSpace.");
|
||||
xrCreateReferenceSpace = Marshal.GetDelegateForFunctionPointer(
|
||||
funcPtr,
|
||||
typeof(OpenXRHelper.xrCreateReferenceSpaceDelegate)) as OpenXRHelper.xrCreateReferenceSpaceDelegate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("xrCreateReferenceSpace");
|
||||
return false;
|
||||
}
|
||||
/// xrDestroySpace
|
||||
if (XrGetInstanceProcAddr(xrInstance, "xrDestroySpace", out funcPtr) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
if (funcPtr != IntPtr.Zero)
|
||||
{
|
||||
DEBUG("Get function pointer of xrDestroySpace.");
|
||||
xrDestroySpace = Marshal.GetDelegateForFunctionPointer(
|
||||
funcPtr,
|
||||
typeof(OpenXRHelper.xrDestroySpaceDelegate)) as OpenXRHelper.xrDestroySpaceDelegate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("xrDestroySpace");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// xrCreateHandTrackerEXT
|
||||
if (XrGetInstanceProcAddr(xrInstance, "xrCreateHandTrackerEXT", out funcPtr) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
if (funcPtr != IntPtr.Zero)
|
||||
{
|
||||
DEBUG("Get function pointer of xrCreateHandTrackerEXT.");
|
||||
xrCreateHandTrackerEXT = Marshal.GetDelegateForFunctionPointer(
|
||||
funcPtr,
|
||||
typeof(ViveHandTrackingHelper.xrCreateHandTrackerEXTDelegate)) as ViveHandTrackingHelper.xrCreateHandTrackerEXTDelegate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("xrCreateHandTrackerEXT");
|
||||
return false;
|
||||
}
|
||||
/// xrDestroyHandTrackerEXT
|
||||
if (XrGetInstanceProcAddr(xrInstance, "xrDestroyHandTrackerEXT", out funcPtr) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
if (funcPtr != IntPtr.Zero)
|
||||
{
|
||||
DEBUG("Get function pointer of xrDestroyHandTrackerEXT.");
|
||||
xrDestroyHandTrackerEXT = Marshal.GetDelegateForFunctionPointer(
|
||||
funcPtr,
|
||||
typeof(ViveHandTrackingHelper.xrDestroyHandTrackerEXTDelegate)) as ViveHandTrackingHelper.xrDestroyHandTrackerEXTDelegate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("xrDestroyHandTrackerEXT");
|
||||
return false;
|
||||
}
|
||||
/// xrLocateHandJointsEXT
|
||||
if (XrGetInstanceProcAddr(xrInstance, "xrLocateHandJointsEXT", out funcPtr) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
if (funcPtr != IntPtr.Zero)
|
||||
{
|
||||
DEBUG("Get function pointer of xrLocateHandJointsEXT.");
|
||||
xrLocateHandJointsEXT = Marshal.GetDelegateForFunctionPointer(
|
||||
funcPtr,
|
||||
typeof(ViveHandTrackingHelper.xrLocateHandJointsEXTDelegate)) as ViveHandTrackingHelper.xrLocateHandJointsEXTDelegate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("xrLocateHandJointsEXT");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
static List<XRInputSubsystem> s_InputSubsystems = new List<XRInputSubsystem>();
|
||||
/// <summary>
|
||||
/// Retrieves the current tracking origin in Unity XR.
|
||||
/// </summary>
|
||||
/// <returns>The tracking origin in <see href="https://docs.unity3d.com/ScriptReference/XR.TrackingOriginModeFlags.html">TrackingOriginModeFlags</see></returns>
|
||||
public TrackingOriginModeFlags GetTrackingOriginMode()
|
||||
{
|
||||
XRInputSubsystem subsystem = null;
|
||||
|
||||
SubsystemManager.GetInstances(s_InputSubsystems);
|
||||
if (s_InputSubsystems.Count > 0)
|
||||
{
|
||||
subsystem = s_InputSubsystems[0];
|
||||
}
|
||||
|
||||
if (subsystem != null)
|
||||
{
|
||||
return subsystem.GetTrackingOriginMode();
|
||||
}
|
||||
|
||||
return TrackingOriginModeFlags.Unknown;
|
||||
}
|
||||
private bool IsReferenceSpaceTypeSupported(UInt32 spaceCountOutput, XrReferenceSpaceType[] spaces, XrReferenceSpaceType space)
|
||||
{
|
||||
bool support = false;
|
||||
for (int i = 0; i < spaceCountOutput; i++)
|
||||
{
|
||||
DEBUG("IsReferenceSpaceTypeSupported() supported space[" + i + "]: " + spaces[i]);
|
||||
if (spaces[i] == space) { support = true; }
|
||||
}
|
||||
|
||||
return support;
|
||||
}
|
||||
|
||||
XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties;
|
||||
XrSystemProperties systemProperties;
|
||||
private bool IsHandTrackingSupported()
|
||||
{
|
||||
bool ret = false;
|
||||
if (!m_XrSessionCreated)
|
||||
{
|
||||
ERROR("IsHandTrackingSupported() session is not created.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
handTrackingSystemProperties.type = XrStructureType.XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT;
|
||||
systemProperties.type = XrStructureType.XR_TYPE_SYSTEM_PROPERTIES;
|
||||
systemProperties.next = Marshal.AllocHGlobal(Marshal.SizeOf(handTrackingSystemProperties));
|
||||
|
||||
long offset = 0;
|
||||
if (IntPtr.Size == 4)
|
||||
offset = systemProperties.next.ToInt32();
|
||||
else
|
||||
offset = systemProperties.next.ToInt64();
|
||||
|
||||
IntPtr sys_hand_tracking_prop_ptr = new IntPtr(offset);
|
||||
Marshal.StructureToPtr(handTrackingSystemProperties, sys_hand_tracking_prop_ptr, false);
|
||||
|
||||
#pragma warning disable 0618
|
||||
if (GetSystemProperties(ref systemProperties) == XrResult.XR_SUCCESS)
|
||||
#pragma warning restore 0618
|
||||
{
|
||||
if (IntPtr.Size == 4)
|
||||
offset = systemProperties.next.ToInt32();
|
||||
else
|
||||
offset = systemProperties.next.ToInt64();
|
||||
|
||||
sys_hand_tracking_prop_ptr = new IntPtr(offset);
|
||||
handTrackingSystemProperties = (XrSystemHandTrackingPropertiesEXT)Marshal.PtrToStructure(sys_hand_tracking_prop_ptr, typeof(XrSystemHandTrackingPropertiesEXT));
|
||||
|
||||
DEBUG("IsHandTrackingSupported() XrSystemHandTrackingPropertiesEXT.supportsHandTracking: " + handTrackingSystemProperties.supportsHandTracking);
|
||||
ret = handTrackingSystemProperties.supportsHandTracking > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("IsHandTrackingSupported() GetSystemProperties failed.");
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(systemProperties.next);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool CreateHandTrackers(bool isLeft, out XrHandTrackerEXT handTracker)
|
||||
{
|
||||
if (!IsHandTrackingSupported())
|
||||
{
|
||||
ERROR("CreateHandTrackers() " + (isLeft ? "Left" : "Right") + " hand tracking is NOT supported.");
|
||||
handTracker = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
XrHandTrackerCreateInfoEXT createInfo;
|
||||
createInfo.type = XrStructureType.XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT;
|
||||
createInfo.next = IntPtr.Zero;
|
||||
createInfo.hand = isLeft ? XrHandEXT.XR_HAND_LEFT_EXT : XrHandEXT.XR_HAND_RIGHT_EXT;
|
||||
createInfo.handJointSet = XrHandJointSetEXT.XR_HAND_JOINT_SET_DEFAULT_EXT;
|
||||
|
||||
var ret = CreateHandTrackerEXT(ref createInfo, out handTracker);
|
||||
DEBUG("CreateHandTrackers() " + (isLeft ? "Left" : "Right") + " CreateHandTrackerEXT = " + ret);
|
||||
|
||||
return ret == XrResult.XR_SUCCESS;
|
||||
}
|
||||
|
||||
private XrHandJointLocationEXT[] jointLocationsL = new XrHandJointLocationEXT[(int)XrHandJointEXT.XR_HAND_JOINT_MAX_ENUM_EXT];
|
||||
private XrHandJointLocationEXT[] jointLocationsR = new XrHandJointLocationEXT[(int)XrHandJointEXT.XR_HAND_JOINT_MAX_ENUM_EXT];
|
||||
private XrHandJointLocationsEXT locations = new XrHandJointLocationsEXT(XrStructureType.XR_TYPE_HAND_JOINT_LOCATIONS_EXT, IntPtr.Zero, false, 0, IntPtr.Zero);
|
||||
|
||||
public bool GetHandTrackingSpace(out XrSpace space)
|
||||
{
|
||||
space = 0;
|
||||
|
||||
TrackingOriginModeFlags origin = GetTrackingOriginMode();
|
||||
if (origin == TrackingOriginModeFlags.Unknown || origin == TrackingOriginModeFlags.Unbounded) { return false; }
|
||||
|
||||
space = (origin == TrackingOriginModeFlags.Device ? m_ReferenceSpaceLocal : m_ReferenceSpaceStage);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the <see cref="XrHandJointLocationEXT"> XrHandJointLocationEXT </see> data.
|
||||
/// </summary>
|
||||
/// <param name="isLeft">Left or right hand.</param>
|
||||
/// <param name="handJointLocation">Output parameter to retrieve <see cref="XrHandJointLocationEXT"> XrHandJointLocationEXT </see> data.</param>
|
||||
/// <returns>True for valid data.</returns>
|
||||
public bool GetJointLocations(bool isLeft, out XrHandJointLocationEXT[] handJointLocation)
|
||||
{
|
||||
bool ret = false;
|
||||
handJointLocation = isLeft ? jointLocationsL : jointLocationsR;
|
||||
|
||||
if (isLeft && !hasLeftHandTracker) { return ret; }
|
||||
if (!isLeft && !hasRightHandTracker) { return ret; }
|
||||
|
||||
TrackingOriginModeFlags origin = GetTrackingOriginMode();
|
||||
if (origin == TrackingOriginModeFlags.Unknown || origin == TrackingOriginModeFlags.Unbounded) { return ret; }
|
||||
XrSpace baseSpace = (origin == TrackingOriginModeFlags.Device ? m_ReferenceSpaceLocal : m_ReferenceSpaceStage);
|
||||
|
||||
/// Configures XrHandJointsLocateInfoEXT
|
||||
XrHandJointsLocateInfoEXT locateInfo = new XrHandJointsLocateInfoEXT(
|
||||
in_type: XrStructureType.XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT,
|
||||
in_next: IntPtr.Zero,
|
||||
in_baseSpace: baseSpace,
|
||||
in_time: 1);//
|
||||
|
||||
/// Configures XrHandJointLocationsEXT
|
||||
locations.type = XrStructureType.XR_TYPE_HAND_JOINT_LOCATIONS_EXT;
|
||||
locations.next = IntPtr.Zero;
|
||||
locations.isActive = false;
|
||||
locations.jointCount = (uint)(isLeft ? jointLocationsL.Length : jointLocationsR.Length);
|
||||
|
||||
XrHandJointLocationEXT joint_location_ext_type = default(XrHandJointLocationEXT);
|
||||
int jointLocationsLength = isLeft ? jointLocationsL.Length : jointLocationsR.Length;
|
||||
locations.jointLocations = Marshal.AllocHGlobal(Marshal.SizeOf(joint_location_ext_type) * jointLocationsLength);
|
||||
|
||||
long offset = 0;
|
||||
/*if (IntPtr.Size == 4)
|
||||
offset = locations.jointLocations.ToInt32();
|
||||
else
|
||||
offset = locations.jointLocations.ToInt64();
|
||||
|
||||
for (int i = 0; i < jointLocationsLength; i++)
|
||||
{
|
||||
IntPtr joint_location_ext_ptr = new IntPtr(offset);
|
||||
|
||||
if (isLeft)
|
||||
Marshal.StructureToPtr(jointLocationsL[i], joint_location_ext_ptr, false);
|
||||
else
|
||||
Marshal.StructureToPtr(jointLocationsR[i], joint_location_ext_ptr, false);
|
||||
|
||||
offset += Marshal.SizeOf(joint_location_ext_type);
|
||||
}*/
|
||||
|
||||
if (LocateHandJointsEXT(
|
||||
handTracker: (isLeft ? leftHandTracker : rightHandTracker),
|
||||
locateInfo: locateInfo,
|
||||
locations: ref locations) == XrResult.XR_SUCCESS)
|
||||
{
|
||||
if (locations.isActive)
|
||||
{
|
||||
if (IntPtr.Size == 4)
|
||||
offset = locations.jointLocations.ToInt32();
|
||||
else
|
||||
offset = locations.jointLocations.ToInt64();
|
||||
|
||||
for (int i = 0; i < locations.jointCount; i++)
|
||||
{
|
||||
IntPtr joint_location_ext_ptr = new IntPtr(offset);
|
||||
|
||||
if (isLeft)
|
||||
jointLocationsL[i] = (XrHandJointLocationEXT)Marshal.PtrToStructure(joint_location_ext_ptr, typeof(XrHandJointLocationEXT));
|
||||
else
|
||||
jointLocationsR[i] = (XrHandJointLocationEXT)Marshal.PtrToStructure(joint_location_ext_ptr, typeof(XrHandJointLocationEXT));
|
||||
|
||||
offset += Marshal.SizeOf(joint_location_ext_type);
|
||||
}
|
||||
|
||||
// ToDo: locationFlags?
|
||||
handJointLocation = isLeft ? jointLocationsL : jointLocationsR;
|
||||
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(locations.jointLocations);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 946578d91fd159a47b2ef0d5f4524fdb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,358 @@
|
||||
// "VIVE SDK
|
||||
// © 2020 HTC Corporation. All Rights Reserved.
|
||||
//
|
||||
// Unless otherwise required by copyright law and practice,
|
||||
// upon the execution of HTC SDK license agreement,
|
||||
// HTC grants you access to and use of the VIVE SDK(s).
|
||||
// You shall fully comply with all of HTC’s SDK license agreement terms and
|
||||
// conditions signed by you and all SDK and API requirements,
|
||||
// specifications, and documentation provided by HTC to You."
|
||||
|
||||
using System;
|
||||
|
||||
namespace VIVE.OpenXR.Hand
|
||||
{
|
||||
/// <summary>
|
||||
/// The XrHandTrackerEXT handle represents the resources for hand tracking of the specific hand.
|
||||
/// </summary>
|
||||
public struct XrHandTrackerEXT : IEquatable<ulong>
|
||||
{
|
||||
private readonly ulong value;
|
||||
|
||||
public XrHandTrackerEXT(ulong u)
|
||||
{
|
||||
value = u;
|
||||
}
|
||||
|
||||
public static implicit operator ulong(XrHandTrackerEXT xrInst)
|
||||
{
|
||||
return xrInst.value;
|
||||
}
|
||||
public static implicit operator XrHandTrackerEXT(ulong u)
|
||||
{
|
||||
return new XrHandTrackerEXT(u);
|
||||
}
|
||||
|
||||
public bool Equals(XrHandTrackerEXT other)
|
||||
{
|
||||
return value == other.value;
|
||||
}
|
||||
public bool Equals(ulong other)
|
||||
{
|
||||
return value == other;
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is XrHandTrackerEXT && Equals((XrHandTrackerEXT)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return value.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static bool operator ==(XrHandTrackerEXT a, XrHandTrackerEXT b) { return a.Equals(b); }
|
||||
public static bool operator !=(XrHandTrackerEXT a, XrHandTrackerEXT b) { return !a.Equals(b); }
|
||||
public static bool operator >=(XrHandTrackerEXT a, XrHandTrackerEXT b) { return a.value >= b.value; }
|
||||
public static bool operator <=(XrHandTrackerEXT a, XrHandTrackerEXT b) { return a.value <= b.value; }
|
||||
public static bool operator >(XrHandTrackerEXT a, XrHandTrackerEXT b) { return a.value > b.value; }
|
||||
public static bool operator <(XrHandTrackerEXT a, XrHandTrackerEXT b) { return a.value < b.value; }
|
||||
public static XrHandTrackerEXT operator +(XrHandTrackerEXT a, XrHandTrackerEXT b) { return a.value + b.value; }
|
||||
public static XrHandTrackerEXT operator -(XrHandTrackerEXT a, XrHandTrackerEXT b) { return a.value - b.value; }
|
||||
public static XrHandTrackerEXT operator *(XrHandTrackerEXT a, XrHandTrackerEXT b) { return a.value * b.value; }
|
||||
public static XrHandTrackerEXT operator /(XrHandTrackerEXT a, XrHandTrackerEXT b)
|
||||
{
|
||||
if (b.value == 0)
|
||||
{
|
||||
throw new DivideByZeroException();
|
||||
}
|
||||
return a.value / b.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The XrHandEXT describes which hand the <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> is tracking.
|
||||
/// </summary>
|
||||
public enum XrHandEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the hand tracker will be tracking the user’s left hand.
|
||||
/// </summary>
|
||||
XR_HAND_LEFT_EXT = 1,
|
||||
/// <summary>
|
||||
/// Specifies the hand tracker will be tracking the user’s right hand.
|
||||
/// </summary>
|
||||
XR_HAND_RIGHT_EXT = 2,
|
||||
XR_HAND_MAX_ENUM_EXT = 3
|
||||
}
|
||||
/// <summary>
|
||||
/// Defines 26 joints for hand tracking: 4 joints for the thumb finger, 5 joints for the other four fingers, and the wrist and palm of the hands.
|
||||
/// </summary>
|
||||
public enum XrHandJointEXT
|
||||
{
|
||||
XR_HAND_JOINT_PALM_EXT = 0,
|
||||
XR_HAND_JOINT_WRIST_EXT = 1,
|
||||
XR_HAND_JOINT_THUMB_METACARPAL_EXT = 2,
|
||||
XR_HAND_JOINT_THUMB_PROXIMAL_EXT = 3,
|
||||
XR_HAND_JOINT_THUMB_DISTAL_EXT = 4,
|
||||
XR_HAND_JOINT_THUMB_TIP_EXT = 5,
|
||||
XR_HAND_JOINT_INDEX_METACARPAL_EXT = 6,
|
||||
XR_HAND_JOINT_INDEX_PROXIMAL_EXT = 7,
|
||||
XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT = 8,
|
||||
XR_HAND_JOINT_INDEX_DISTAL_EXT = 9,
|
||||
XR_HAND_JOINT_INDEX_TIP_EXT = 10,
|
||||
XR_HAND_JOINT_MIDDLE_METACARPAL_EXT = 11,
|
||||
XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT = 12,
|
||||
XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT = 13,
|
||||
XR_HAND_JOINT_MIDDLE_DISTAL_EXT = 14,
|
||||
XR_HAND_JOINT_MIDDLE_TIP_EXT = 15,
|
||||
XR_HAND_JOINT_RING_METACARPAL_EXT = 16,
|
||||
XR_HAND_JOINT_RING_PROXIMAL_EXT = 17,
|
||||
XR_HAND_JOINT_RING_INTERMEDIATE_EXT = 18,
|
||||
XR_HAND_JOINT_RING_DISTAL_EXT = 19,
|
||||
XR_HAND_JOINT_RING_TIP_EXT = 20,
|
||||
XR_HAND_JOINT_LITTLE_METACARPAL_EXT = 21,
|
||||
XR_HAND_JOINT_LITTLE_PROXIMAL_EXT = 22,
|
||||
XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT = 23,
|
||||
XR_HAND_JOINT_LITTLE_DISTAL_EXT = 24,
|
||||
XR_HAND_JOINT_LITTLE_TIP_EXT = 25,
|
||||
XR_HAND_JOINT_MAX_ENUM_EXT = 26
|
||||
}
|
||||
/// <summary>
|
||||
/// The XrHandJointSetEXT enum describes the set of hand joints to track when creating an <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see>.
|
||||
/// </summary>
|
||||
public enum XrHandJointSetEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the created <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> tracks the set of hand joints described by <see cref="XrHandJointEXT">XrHandJointEXT</see> enum, i.e. the <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrLocateHandJointsEXT">xrLocateHandJointsEXT</see> function returns an array of joint locations with the count of <see cref="ViveHandTrackingHelper.XR_HAND_JOINT_COUNT_EXT">XR_HAND_JOINT_COUNT_EXT</see> and can be indexed using <see cref="XrHandJointEXT">XrHandJointEXT</see>.
|
||||
/// </summary>
|
||||
XR_HAND_JOINT_SET_DEFAULT_EXT = 0,
|
||||
XR_HAND_JOINT_SET_MAX_ENUM_EXT = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An application can inspect whether the system is capable of hand tracking input by extending the <see cref="XrSystemProperties">XrSystemProperties</see> with XrSystemHandTrackingPropertiesEXT structure when calling <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrGetSystemProperties">xrGetSystemProperties</see>.
|
||||
/// </summary>
|
||||
public struct XrSystemHandTrackingPropertiesEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="XrStructureType">XrStructureType</see> of this structure.
|
||||
/// </summary>
|
||||
public XrStructureType type;
|
||||
/// <summary>
|
||||
/// NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.
|
||||
/// </summary>
|
||||
public IntPtr next;
|
||||
/// <summary>
|
||||
/// An <see cref="XrBool32">XrBool32</see>, indicating if current system is capable of hand tracking input.
|
||||
/// </summary>
|
||||
public XrBool32 supportsHandTracking;
|
||||
};
|
||||
/// <summary>
|
||||
/// The XrHandTrackerCreateInfoEXT structure describes the information to create an <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> handle.
|
||||
/// </summary>
|
||||
public struct XrHandTrackerCreateInfoEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// The XrStructureType of this structure.
|
||||
/// </summary>
|
||||
public XrStructureType type;
|
||||
/// <summary>
|
||||
/// NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.
|
||||
/// </summary>
|
||||
public IntPtr next;
|
||||
/// <summary>
|
||||
/// An <see cref="XrHandEXT">XrHandEXT</see> which describes which hand the tracker is tracking.
|
||||
/// </summary>
|
||||
public XrHandEXT hand;
|
||||
/// <summary>
|
||||
/// An <see cref="XrHandJointSetEXT">XrHandJointSetEXT</see> describe the set of hand joints to retrieve.
|
||||
/// </summary>
|
||||
public XrHandJointSetEXT handJointSet;
|
||||
/// <param name="in_type">The XrStructureType of this structure.</param>
|
||||
/// <param name="in_next">NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.</param>
|
||||
/// <param name="in_hand">An <see cref="XrHandEXT">XrHandEXT</see> which describes which hand the tracker is tracking.</param>
|
||||
/// <param name="in_handJointSet">An <see cref="XrHandJointSetEXT">XrHandJointSetEXT</see> describe the set of hand joints to retrieve.</param>
|
||||
public XrHandTrackerCreateInfoEXT(XrStructureType in_type, IntPtr in_next, XrHandEXT in_hand, XrHandJointSetEXT in_handJointSet)
|
||||
{
|
||||
type = in_type;
|
||||
next = in_next;
|
||||
hand = in_hand;
|
||||
handJointSet = in_handJointSet;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The XrHandJointsLocateInfoEXT structure describes the information to locate hand joints.
|
||||
/// </summary>
|
||||
public struct XrHandJointsLocateInfoEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="XrStructureType">XrStructureType</see> of this structure.
|
||||
/// </summary>
|
||||
public XrStructureType type;
|
||||
/// <summary>
|
||||
/// NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.
|
||||
/// </summary>
|
||||
public IntPtr next;
|
||||
/// <summary>
|
||||
/// An <see cref="XrSpace">XrSpace</see> within which the returned hand joint locations will be represented.
|
||||
/// </summary>
|
||||
public XrSpace baseSpace;
|
||||
/// <summary>
|
||||
/// An <see cref="XrTime">XrTime</see> at which to locate the hand joints.
|
||||
/// </summary>
|
||||
public XrTime time;
|
||||
/// <param name="in_type">The <see cref="XrStructureType">XrStructureType</see> of this structure.</param>
|
||||
/// <param name="in_next">NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.</param>
|
||||
/// <param name="in_baseSpace">An <see cref="XrSpace">XrSpace</see> within which the returned hand joint locations will be represented.</param>
|
||||
/// <param name="in_time">An <see cref="XrTime">XrTime</see> at which to locate the hand joints.</param>
|
||||
public XrHandJointsLocateInfoEXT(XrStructureType in_type, IntPtr in_next, XrSpace in_baseSpace, XrTime in_time)
|
||||
{
|
||||
type = in_type;
|
||||
next = in_next;
|
||||
baseSpace = in_baseSpace;
|
||||
time = in_time;
|
||||
}
|
||||
};
|
||||
/// <summary>
|
||||
/// XrHandJointLocationEXT structure describes the position, orientation, and radius of a hand joint.
|
||||
/// </summary>
|
||||
public struct XrHandJointLocationEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// A bitfield, with bit masks defined in <see cref="XrSpaceLocationFlags">XrSpaceLocationFlags</see>, to indicate which members contain valid data. If none of the bits are set, no other fields in this structure should be considered to be valid or meaningful.
|
||||
/// </summary>
|
||||
public XrSpaceLocationFlags locationFlags;
|
||||
/// <summary>
|
||||
/// An <see cref="XrPosef">XrPosef</see> defining the position and orientation of the origin of a hand joint within the reference frame of the corresponding <see cref="XrHandJointsLocateInfoEXT.baseSpace">XrHandJointsLocateInfoEXT::baseSpace</see>.
|
||||
/// </summary>
|
||||
public XrPosef pose;
|
||||
/// <summary>
|
||||
/// A float value radius of the corresponding joint in units of meters.
|
||||
/// </summary>
|
||||
public float radius;
|
||||
}
|
||||
/// <summary>
|
||||
/// XrHandJointVelocityEXT structure describes the linear and angular velocity of a hand joint.
|
||||
/// </summary>
|
||||
public struct XrHandJointVelocityEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// A bitfield, with bit masks defined in <see cref="XrSpaceVelocityFlags">XrSpaceVelocityFlags</see>, to indicate which members contain valid data. If none of the bits are set, no other fields in this structure should be considered to be valid or meaningful.
|
||||
/// </summary>
|
||||
public XrSpaceVelocityFlags velocityFlags;
|
||||
/// <summary>
|
||||
/// The relative linear velocity of the hand joint with respect to and expressed in the reference frame of the corresponding <see cref="XrHandJointsLocateInfoEXT.baseSpace">XrHandJointsLocateInfoEXT::baseSpace</see>, in units of meters per second.
|
||||
/// </summary>
|
||||
public XrVector3f linearVelocity;
|
||||
/// <summary>
|
||||
/// The relative angular velocity of the hand joint with respect to the corresponding <see cref="XrHandJointsLocateInfoEXT.baseSpace">XrHandJointsLocateInfoEXT::baseSpace</see>. The vector’s direction is expressed in the reference frame of the corresponding <see cref="XrHandJointsLocateInfoEXT.baseSpace">XrHandJointsLocateInfoEXT::baseSpace</see> and is parallel to the rotational axis of the hand joint. The vector’s magnitude is the relative angular speed of the hand joint in radians per second. The vector follows the right-hand rule for torque/rotation.
|
||||
/// </summary>
|
||||
public XrVector3f angularVelocity;
|
||||
}
|
||||
/// <summary>
|
||||
/// The application can chain an XrHandJointVelocitiesEXT structure to the next pointer of <see cref="XrHandJointLocationsEXT">XrHandJointLocationsEXT</see> when calling <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrLocateHandJointsEXT">xrLocateHandJointsEXT</see> to retrieve the hand joint velocities.
|
||||
/// </summary>
|
||||
public struct XrHandJointVelocitiesEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="XrStructureType">XrStructureType</see> of this structure.
|
||||
/// </summary>
|
||||
public XrStructureType type;
|
||||
/// <summary>
|
||||
/// NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.
|
||||
/// </summary>
|
||||
public IntPtr next;
|
||||
/// <summary>
|
||||
/// A uint32_t describing the number of elements in jointVelocities array.
|
||||
/// </summary>
|
||||
UInt32 jointCount;
|
||||
/// <summary>
|
||||
/// An array of <see cref="XrHandJointVelocityEXT">XrHandJointVelocityEXT</see> receiving the returned hand joint velocities.
|
||||
/// </summary>
|
||||
IntPtr jointVelocities; //XrHandJointVelocityEXT*
|
||||
}
|
||||
/// <summary>
|
||||
/// XrHandJointLocationsEXT structure returns the state of the hand joint locations.
|
||||
/// </summary>
|
||||
public struct XrHandJointLocationsEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="XrStructureType">XrStructureType</see> of this structure.
|
||||
/// </summary>
|
||||
public XrStructureType type;
|
||||
/// <summary>
|
||||
/// NULL or a pointer to the next structure in a structure chain, such as <see cref="XrHandJointVelocitiesEXT">XrHandJointVelocitiesEXT</see>.
|
||||
/// </summary>
|
||||
public IntPtr next;
|
||||
/// <summary>
|
||||
/// An <see cref="XrBool32">XrBool32</see> indicating if the hand tracker is actively tracking.
|
||||
/// </summary>
|
||||
public XrBool32 isActive;
|
||||
/// <summary>
|
||||
/// A uint32_t describing the count of elements in jointLocations array.
|
||||
/// </summary>
|
||||
public UInt32 jointCount;
|
||||
/// <summary>
|
||||
/// An array of <see cref="XrHandJointLocationEXT">XrHandJointLocationEXT</see> receiving the returned hand joint locations.
|
||||
/// </summary>
|
||||
public IntPtr jointLocations; //XrHandJointLocationEXT*
|
||||
/// <param name="in_type">The <see cref="XrStructureType">XrStructureType</see> of this structure.</param>
|
||||
/// <param name="in_next">NULL or a pointer to the next structure in a structure chain, such as <see cref="XrHandJointVelocitiesEXT">XrHandJointVelocitiesEXT</see>.</param>
|
||||
/// <param name="in_isActive">An <see cref="XrBool32">XrBool32</see> indicating if the hand tracker is actively tracking.</param>
|
||||
/// <param name="in_jointCount">A uint32_t describing the count of elements in jointLocations array.</param>
|
||||
/// <param name="in_jointLocations">An array of <see cref="XrHandJointLocationEXT">XrHandJointLocationEXT</see> receiving the returned hand joint locations.</param>
|
||||
public XrHandJointLocationsEXT(XrStructureType in_type, IntPtr in_next, XrBool32 in_isActive, UInt32 in_jointCount, IntPtr in_jointLocations)
|
||||
{
|
||||
type = in_type;
|
||||
next = in_next;
|
||||
isActive = in_isActive;
|
||||
jointCount = in_jointCount;
|
||||
jointLocations = in_jointLocations;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ViveHandTrackingHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the number of hand joint enumerants defined in <see cref="XrHandJointEXT">XrHandJointEXT</see>.
|
||||
/// </summary>
|
||||
public const int XR_HAND_JOINT_COUNT_EXT = 26;
|
||||
|
||||
/// <summary>
|
||||
/// The function delegate of <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateHandTrackerEXT">xrCreateHandTrackerEXT</see>.
|
||||
/// </summary>
|
||||
/// <param name="session">An <see cref="XrSession">XrSession</see> in which the hand tracker will be active.</param>
|
||||
/// <param name="createInfo">The <see cref="XrHandTrackerCreateInfoEXT">XrHandTrackerCreateInfoEXT</see> used to specify the hand tracker.</param>
|
||||
/// <param name="handTracker">The returned <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> handle.</param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
public delegate XrResult xrCreateHandTrackerEXTDelegate(
|
||||
XrSession session,
|
||||
ref XrHandTrackerCreateInfoEXT createInfo,
|
||||
out XrHandTrackerEXT handTracker);
|
||||
/// <summary>
|
||||
/// The function delegate of <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrDestroyHandTrackerEXT">xrDestroyHandTrackerEXT</see>.
|
||||
/// </summary>
|
||||
/// <param name="handTracker">An <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> previously created by <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateHandTrackerEXT">xrCreateHandTrackerEXT</see>.</param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
public delegate XrResult xrDestroyHandTrackerEXTDelegate(
|
||||
XrHandTrackerEXT handTracker);
|
||||
/// <summary>
|
||||
/// The function delegate of <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrLocateHandJointsEXT">xrLocateHandJointsEXT</see>.
|
||||
/// </summary>
|
||||
/// <param name="handTracker">An <see cref="XrHandTrackerEXT">XrHandTrackerEXT</see> previously created by <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateHandTrackerEXT">xrCreateHandTrackerEXT</see>.</param>
|
||||
/// <param name="locateInfo">A pointer to <see cref="XrHandJointsLocateInfoEXT">XrHandJointsLocateInfoEXT</see> describing information to locate hand joints.</param>
|
||||
/// <param name="locations">A pointer to <see cref="XrHandJointLocationsEXT">XrHandJointLocationsEXT</see> receiving the returned hand joint locations.</param>
|
||||
/// <returns></returns>
|
||||
public delegate XrResult xrLocateHandJointsEXTDelegate(
|
||||
XrHandTrackerEXT handTracker,
|
||||
XrHandJointsLocateInfoEXT locateInfo,
|
||||
ref XrHandJointLocationsEXT locations);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46df1d8f60e72ea44bf13cdca1f908b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user