version 2.5.1
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
@@ -107,6 +106,12 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
|
||||
public static class VIVEInput
|
||||
{
|
||||
private const string kFloatType = "float";
|
||||
private const string kVector2Type = "Vector2";
|
||||
private const string kVector3Type = "Vector3";
|
||||
private const string kQuaternionType = "Quaternion";
|
||||
private const string kPoseType = "Pose";
|
||||
|
||||
private struct InputActionMapping
|
||||
{
|
||||
public DeviceCategory device;
|
||||
@@ -115,15 +120,18 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
public HandEvent handEvent;
|
||||
public InputAction inputAction { get; private set; }
|
||||
|
||||
public InputActionMapping(string bindingPath, DeviceCategory device,
|
||||
PoseState poseState = PoseState.None, ButtonEvent buttonEvent = ButtonEvent.None, HandEvent handEvent = HandEvent.None)
|
||||
public InputActionMapping(string in_BindingPath, DeviceCategory in_Device,
|
||||
PoseState in_PoseState = PoseState.None,
|
||||
ButtonEvent in_ButtonEvent = ButtonEvent.None,
|
||||
HandEvent in_HandEvent = HandEvent.None,
|
||||
string in_Type = "")
|
||||
{
|
||||
inputAction = new InputAction(binding: bindingPath);
|
||||
inputAction = new InputAction(binding: in_BindingPath, expectedControlType: in_Type);
|
||||
inputAction.Enable();
|
||||
this.device = device;
|
||||
this.poseState = poseState;
|
||||
this.buttonEvent = buttonEvent;
|
||||
this.handEvent = handEvent;
|
||||
this.device = in_Device;
|
||||
this.poseState = in_PoseState;
|
||||
this.buttonEvent = in_ButtonEvent;
|
||||
this.handEvent = in_HandEvent;
|
||||
}
|
||||
|
||||
public static InputActionMapping Identify => new InputActionMapping("", DeviceCategory.None);
|
||||
@@ -150,11 +158,11 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
public Vector3 position { get; private set; }
|
||||
public Quaternion rotation { get; private set; }
|
||||
|
||||
public JointData(bool isValid, Vector3 position, Quaternion rotation)
|
||||
public JointData(bool in_IsValid, Vector3 in_Position, Quaternion in_Rotation)
|
||||
{
|
||||
this.isValid = isValid;
|
||||
this.position = position;
|
||||
this.rotation = rotation;
|
||||
this.isValid = in_IsValid;
|
||||
this.position = in_Position;
|
||||
this.rotation = in_Rotation;
|
||||
}
|
||||
|
||||
public static JointData Identify => new JointData(false, Vector3.zero, Quaternion.identity);
|
||||
@@ -164,18 +172,44 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
public bool isTracked { get; private set; }
|
||||
public int updateTime { get; private set; }
|
||||
public JointData[] joints { get; private set; }
|
||||
private JointData[] jointBuffer;
|
||||
|
||||
public HandData(JointData[] joints)
|
||||
public HandData(JointData[] in_Joints)
|
||||
{
|
||||
this.joints = joints;
|
||||
isTracked = !this.joints.Any(x => x.isValid == false);
|
||||
jointBuffer = new JointData[(int)HandJointType.Count];
|
||||
for (int i = 0; i < in_Joints.Length; i++)
|
||||
{
|
||||
jointBuffer[i] = in_Joints[i];
|
||||
}
|
||||
this.joints = jointBuffer;
|
||||
isTracked = true;
|
||||
for (int i = 0; i < this.joints.Length; i++)
|
||||
{
|
||||
if (!this.joints[i].isValid)
|
||||
{
|
||||
isTracked = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateTime = Time.frameCount;
|
||||
}
|
||||
|
||||
public void Update(JointData[] joints)
|
||||
public void Update(JointData[] in_Joints)
|
||||
{
|
||||
this.joints = joints;
|
||||
isTracked = !this.joints.Any(x => x.isValid == false);
|
||||
for (int i = 0; i < in_Joints.Length; i++)
|
||||
{
|
||||
jointBuffer[i] = in_Joints[i];
|
||||
}
|
||||
this.joints = jointBuffer;
|
||||
isTracked = true;
|
||||
for (int i = 0; i < this.joints.Length; i++)
|
||||
{
|
||||
if (!this.joints[i].isValid)
|
||||
{
|
||||
isTracked = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateTime = Time.frameCount;
|
||||
}
|
||||
|
||||
@@ -193,12 +227,16 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
}
|
||||
}
|
||||
|
||||
private static bool isInitInputActions = false;
|
||||
private static List<InputActionMapping> inputActions = new List<InputActionMapping>();
|
||||
private static HandData leftHand = HandData.Identify;
|
||||
private static HandData rightHand = HandData.Identify;
|
||||
private static bool m_IsInitInputActions = false;
|
||||
private static bool m_IsSupportViveHand = false;
|
||||
private static bool m_IsSupportXrHand = false;
|
||||
private static List<InputActionMapping> s_InputActions = new List<InputActionMapping>();
|
||||
private static HandData m_LeftHand = HandData.Identify;
|
||||
private static HandData m_RightHand = HandData.Identify;
|
||||
private static JointData[] m_JointBuffer = new JointData[(int)HandJointType.Count];
|
||||
#if UNITY_XR_HANDS
|
||||
private static XRHandSubsystem handSubsystem = null;
|
||||
private static XRHandSubsystem m_HandSubsystem = null;
|
||||
private static List<XRHandSubsystem> m_HandSubsystems = new List<XRHandSubsystem>();
|
||||
#endif
|
||||
|
||||
#region Public Interface
|
||||
@@ -221,18 +259,16 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
}
|
||||
else
|
||||
{
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == device && x.poseState == poseState);
|
||||
if (inputActionMapping == null) { return false; }
|
||||
|
||||
try
|
||||
if (GetInputActionMapping(device, poseState, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<float>() > 0;
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<float>() > 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,18 +291,16 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
}
|
||||
else
|
||||
{
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == device && x.poseState == poseState);
|
||||
if (inputActionMapping == null) { return false; }
|
||||
|
||||
try
|
||||
if (GetInputActionMapping(device, poseState, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<Vector3>();
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kVector3Type)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<Vector3>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,18 +323,16 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
}
|
||||
else
|
||||
{
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == device && x.poseState == poseState);
|
||||
if (inputActionMapping == null) { return false; }
|
||||
|
||||
try
|
||||
if (GetInputActionMapping(device, poseState, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<Quaternion>();
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kQuaternionType)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<Quaternion>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,11 +347,14 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
{
|
||||
CheckInitialize();
|
||||
eventResult = false;
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent);
|
||||
if (inputActionMapping != null)
|
||||
if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.WasPressedThisFrame();
|
||||
return true;
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.WasPressedThisFrame();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -335,11 +370,14 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
{
|
||||
CheckInitialize();
|
||||
eventResult = false;
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent);
|
||||
if (inputActionMapping != null)
|
||||
if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.WasReleasedThisFrame();
|
||||
return true;
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.WasReleasedThisFrame();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -355,21 +393,16 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
{
|
||||
CheckInitialize();
|
||||
eventResult = false;
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent);
|
||||
if (inputActionMapping != null)
|
||||
if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
try
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<float>() == 1;
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -383,21 +416,16 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
{
|
||||
CheckInitialize();
|
||||
eventResult = 0f;
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent);
|
||||
if (inputActionMapping != null)
|
||||
if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
try
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<float>();
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -411,18 +439,14 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
{
|
||||
CheckInitialize();
|
||||
eventResult = Vector2.zero;
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent);
|
||||
if (inputActionMapping != null)
|
||||
if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
try
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kVector2Type)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<Vector2>();
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -438,18 +462,14 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
{
|
||||
CheckInitialize();
|
||||
eventResult = 0;
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetHand(handedness) && x.handEvent == handEvent);
|
||||
if (inputActionMapping != null)
|
||||
if (GetInputActionMapping(GetHand(handedness), handEvent, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
try
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
|
||||
{
|
||||
eventResult = inputActionMapping.inputAction.ReadValue<float>();
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -465,19 +485,19 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
{
|
||||
CheckInitialize();
|
||||
eventResult = Pose.identity;
|
||||
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetHand(handedness) && x.handEvent == handEvent);
|
||||
if (inputActionMapping != null)
|
||||
if (GetInputActionMapping(GetHand(handedness), handEvent, out InputActionMapping inputActionMapping))
|
||||
{
|
||||
try
|
||||
var inputAction = inputActionMapping.inputAction;
|
||||
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kPoseType)
|
||||
{
|
||||
# if USE_INPUT_SYSTEM_POSE_CONTROL
|
||||
UnityEngine.InputSystem.XR.PoseState pose = inputActionMapping.inputAction.ReadValue<UnityEngine.InputSystem.XR.PoseState>();
|
||||
#else
|
||||
UnityEngine.XR.OpenXR.Input.Pose pose = inputActionMapping.inputAction.ReadValue<UnityEngine.XR.OpenXR.Input.Pose>();
|
||||
#endif
|
||||
eventResult = new Pose(pose.position, pose.rotation);
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -495,13 +515,13 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
jointPose = Pose.identity;
|
||||
if (handedness == Handedness.Left)
|
||||
{
|
||||
jointPose = new Pose(leftHand.joints[(int)joint].position, leftHand.joints[(int)joint].rotation);
|
||||
return leftHand.joints[(int)joint].isValid;
|
||||
jointPose = new Pose(m_LeftHand.joints[(int)joint].position, m_LeftHand.joints[(int)joint].rotation);
|
||||
return m_LeftHand.joints[(int)joint].isValid;
|
||||
}
|
||||
else
|
||||
{
|
||||
jointPose = new Pose(rightHand.joints[(int)joint].position, rightHand.joints[(int)joint].rotation);
|
||||
return rightHand.joints[(int)joint].isValid;
|
||||
jointPose = new Pose(m_RightHand.joints[(int)joint].position, m_RightHand.joints[(int)joint].rotation);
|
||||
return m_RightHand.joints[(int)joint].isValid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,24 +533,27 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
public static bool IsHandTracked(Handedness handedness)
|
||||
{
|
||||
CheckHandUpdated();
|
||||
return handedness == Handedness.Left ? leftHand.isTracked : rightHand.isTracked;
|
||||
return handedness == Handedness.Left ? m_LeftHand.isTracked : m_RightHand.isTracked;
|
||||
}
|
||||
|
||||
public static bool IsHandValidate()
|
||||
{
|
||||
ViveHandTracking viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
|
||||
if (viveHand)
|
||||
if (!m_IsInitInputActions)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
ViveHandTracking viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
|
||||
if (viveHand)
|
||||
{
|
||||
m_IsSupportViveHand = true;
|
||||
}
|
||||
#if UNITY_XR_HANDS
|
||||
HandTracking xrHand = OpenXRSettings.Instance.GetFeature<HandTracking>();
|
||||
if (xrHand)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
HandTracking xrHand = OpenXRSettings.Instance.GetFeature<HandTracking>();
|
||||
if (xrHand)
|
||||
{
|
||||
m_IsSupportXrHand = true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return m_IsSupportViveHand || m_IsSupportXrHand;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -538,192 +561,233 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
private static bool CheckInitialize()
|
||||
{
|
||||
if (!isInitInputActions)
|
||||
if (!m_IsInitInputActions)
|
||||
{
|
||||
Initialized();
|
||||
isInitInputActions = true;
|
||||
IsHandValidate();
|
||||
m_IsInitInputActions = true;
|
||||
}
|
||||
return isInitInputActions;
|
||||
return m_IsInitInputActions;
|
||||
}
|
||||
|
||||
private static void Initialized()
|
||||
{
|
||||
#region Head
|
||||
inputActions.Add(new InputActionMapping("<XRHMD>/isTracked", DeviceCategory.HMD, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyePosition", DeviceCategory.HMD, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeRotation", DeviceCategory.HMD, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeVelocity", DeviceCategory.HMD, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAngularVelocity", DeviceCategory.HMD, poseState: PoseState.AngularVelocity));
|
||||
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAcceleration", DeviceCategory.HMD, poseState: PoseState.Acceleration));
|
||||
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAngularAcceleration", DeviceCategory.HMD, poseState: PoseState.AngularAcceleration));
|
||||
s_InputActions.Add(new InputActionMapping("<XRHMD>/isTracked", DeviceCategory.HMD, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyePosition", DeviceCategory.HMD, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeRotation", DeviceCategory.HMD, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeVelocity", DeviceCategory.HMD, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAngularVelocity", DeviceCategory.HMD, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAcceleration", DeviceCategory.HMD, in_PoseState: PoseState.Acceleration, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAngularAcceleration", DeviceCategory.HMD, in_PoseState: PoseState.AngularAcceleration, in_Type: kVector3Type));
|
||||
#endregion
|
||||
#region Eye
|
||||
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/isTracked", DeviceCategory.CenterEye, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/position", DeviceCategory.CenterEye, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/rotation", DeviceCategory.CenterEye, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/velocity", DeviceCategory.CenterEye, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/angularVelocity", DeviceCategory.CenterEye, poseState: PoseState.AngularVelocity));
|
||||
s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/isTracked", DeviceCategory.CenterEye, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/position", DeviceCategory.CenterEye, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/rotation", DeviceCategory.CenterEye, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/velocity", DeviceCategory.CenterEye, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/angularVelocity", DeviceCategory.CenterEye, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
#endregion
|
||||
#region Controller
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/isTracked", DeviceCategory.LeftController, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/pointerPosition", DeviceCategory.LeftController, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/pointerRotation", DeviceCategory.LeftController, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceVelocity", DeviceCategory.LeftController, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAngularVelocity", DeviceCategory.LeftController, poseState: PoseState.AngularVelocity));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAcceleration", DeviceCategory.LeftController, poseState: PoseState.Acceleration));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAngularAcceleration", DeviceCategory.LeftController, poseState: PoseState.AngularAcceleration));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{grip}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.GripValue));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{gripButton}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.GripPress));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{trigger}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.TriggerValue));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/triggerTouched", DeviceCategory.LeftController, buttonEvent: ButtonEvent.TriggerTouch));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{triggerButton}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.TriggerPress));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxis}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Primary2DAxisValue));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxisTouch}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Primary2DAxisTouch));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxisClick}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Primary2DAxisPress));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxis}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Secondary2DAxisValue));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxisTouch}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Secondary2DAxisTouch));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxisClick}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Secondary2DAxisPress));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primaryButton}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.PrimaryButton));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondaryButton}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.SecondaryButton));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/parkingTouched", DeviceCategory.LeftController, buttonEvent: ButtonEvent.ParkingTouch));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/menu", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Menu));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/isTracked", DeviceCategory.LeftController, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/pointerPosition", DeviceCategory.LeftController, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/pointerRotation", DeviceCategory.LeftController, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceVelocity", DeviceCategory.LeftController, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAngularVelocity", DeviceCategory.LeftController, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAcceleration", DeviceCategory.LeftController, in_PoseState: PoseState.Acceleration, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAngularAcceleration", DeviceCategory.LeftController, in_PoseState: PoseState.AngularAcceleration, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{grip}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.GripValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{gripButton}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.GripPress, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{trigger}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.TriggerValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/triggerTouched", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.TriggerTouch, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{triggerButton}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.TriggerPress, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxis}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Primary2DAxisValue, in_Type: kVector2Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxisTouch}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Primary2DAxisTouch, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxisClick}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Primary2DAxisPress, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxis}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Secondary2DAxisValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxisTouch}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Secondary2DAxisTouch, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxisClick}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Secondary2DAxisPress, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primaryButton}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.PrimaryButton, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondaryButton}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.SecondaryButton, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/parkingTouched", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.ParkingTouch, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/menu", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Menu, in_Type: kFloatType));
|
||||
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/isTracked", DeviceCategory.RightController, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/pointerPosition", DeviceCategory.RightController, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/pointerRotation", DeviceCategory.RightController, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceVelocity", DeviceCategory.RightController, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAngularVelocity", DeviceCategory.RightController, poseState: PoseState.AngularVelocity));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAcceleration", DeviceCategory.RightController, poseState: PoseState.Acceleration));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAngularAcceleration", DeviceCategory.RightController, poseState: PoseState.AngularAcceleration));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{grip}", DeviceCategory.RightController, buttonEvent: ButtonEvent.GripValue));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{gripButton}", DeviceCategory.RightController, buttonEvent: ButtonEvent.GripPress));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{trigger}", DeviceCategory.RightController, buttonEvent: ButtonEvent.TriggerValue));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/triggerTouched", DeviceCategory.RightController, buttonEvent: ButtonEvent.TriggerTouch));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{triggerButton}", DeviceCategory.RightController, buttonEvent: ButtonEvent.TriggerPress));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxis}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Primary2DAxisValue));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxisTouch}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Primary2DAxisTouch));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxisClick}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Primary2DAxisPress));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxis}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Secondary2DAxisValue));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxisTouch}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Secondary2DAxisTouch));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxisClick}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Secondary2DAxisPress));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primaryButton}", DeviceCategory.RightController, buttonEvent: ButtonEvent.PrimaryButton));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondaryButton}", DeviceCategory.RightController, buttonEvent: ButtonEvent.SecondaryButton));
|
||||
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/parkingTouched", DeviceCategory.RightController, buttonEvent: ButtonEvent.ParkingTouch));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/isTracked", DeviceCategory.RightController, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/pointerPosition", DeviceCategory.RightController, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/pointerRotation", DeviceCategory.RightController, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceVelocity", DeviceCategory.RightController, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAngularVelocity", DeviceCategory.RightController, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAcceleration", DeviceCategory.RightController, in_PoseState: PoseState.Acceleration, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAngularAcceleration", DeviceCategory.RightController, in_PoseState: PoseState.AngularAcceleration, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{grip}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.GripValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{gripButton}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.GripPress, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{trigger}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.TriggerValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/triggerTouched", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.TriggerTouch, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{triggerButton}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.TriggerPress, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxis}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Primary2DAxisValue, in_Type: kVector2Type));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxisTouch}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Primary2DAxisTouch, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxisClick}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Primary2DAxisPress, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxis}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Secondary2DAxisValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxisTouch}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Secondary2DAxisTouch, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxisClick}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Secondary2DAxisPress, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primaryButton}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.PrimaryButton, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondaryButton}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.SecondaryButton, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/parkingTouched", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.ParkingTouch, in_Type: kFloatType));
|
||||
#endregion
|
||||
#region Hand
|
||||
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/selectValue", DeviceCategory.LeftHand, handEvent: HandEvent.PinchValue));
|
||||
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/pointerPose", DeviceCategory.LeftHand, handEvent: HandEvent.PinchPose));
|
||||
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/gripValue", DeviceCategory.LeftHand, handEvent: HandEvent.GraspValue));
|
||||
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/devicePose", DeviceCategory.LeftHand, handEvent: HandEvent.GraspPose));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/selectValue", DeviceCategory.LeftHand, in_HandEvent: HandEvent.PinchValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/pointerPose", DeviceCategory.LeftHand, in_HandEvent: HandEvent.PinchPose, in_Type: kPoseType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/gripValue", DeviceCategory.LeftHand, in_HandEvent: HandEvent.GraspValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/devicePose", DeviceCategory.LeftHand, in_HandEvent: HandEvent.GraspPose, in_Type: kPoseType));
|
||||
|
||||
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/selectValue", DeviceCategory.RightHand, handEvent: HandEvent.PinchValue));
|
||||
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/pointerPose", DeviceCategory.RightHand, handEvent: HandEvent.PinchPose));
|
||||
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/gripValue", DeviceCategory.RightHand, handEvent: HandEvent.GraspValue));
|
||||
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/devicePose", DeviceCategory.RightHand, handEvent: HandEvent.GraspPose));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/selectValue", DeviceCategory.RightHand, in_HandEvent: HandEvent.PinchValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/pointerPose", DeviceCategory.RightHand, in_HandEvent: HandEvent.PinchPose, in_Type: kPoseType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/gripValue", DeviceCategory.RightHand, in_HandEvent: HandEvent.GraspValue, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/devicePose", DeviceCategory.RightHand, in_HandEvent: HandEvent.GraspPose, in_Type: kPoseType));
|
||||
#endregion
|
||||
#region Tracker
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/isTracked", DeviceCategory.Tracker0, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePosition", DeviceCategory.Tracker0, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/deviceRotation", DeviceCategory.Tracker0, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/velocity", DeviceCategory.Tracker0, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/angularVelocity", DeviceCategory.Tracker0, poseState: PoseState.AngularVelocity));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/isTracked", DeviceCategory.Tracker0, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePosition", DeviceCategory.Tracker0, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/deviceRotation", DeviceCategory.Tracker0, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/velocity", DeviceCategory.Tracker0, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/angularVelocity", DeviceCategory.Tracker0, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/isTracked", DeviceCategory.Tracker1, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePosition", DeviceCategory.Tracker1, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/deviceRotation", DeviceCategory.Tracker1, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/velocity", DeviceCategory.Tracker1, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/angularVelocity", DeviceCategory.Tracker1, poseState: PoseState.AngularVelocity));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/isTracked", DeviceCategory.Tracker1, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePosition", DeviceCategory.Tracker1, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/deviceRotation", DeviceCategory.Tracker1, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/velocity", DeviceCategory.Tracker1, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/angularVelocity", DeviceCategory.Tracker1, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/isTracked", DeviceCategory.Tracker2, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePosition", DeviceCategory.Tracker2, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/deviceRotation", DeviceCategory.Tracker2, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/velocity", DeviceCategory.Tracker2, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/angularVelocity", DeviceCategory.Tracker2, poseState: PoseState.AngularVelocity));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/isTracked", DeviceCategory.Tracker2, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePosition", DeviceCategory.Tracker2, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/deviceRotation", DeviceCategory.Tracker2, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/velocity", DeviceCategory.Tracker2, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/angularVelocity", DeviceCategory.Tracker2, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/isTracked", DeviceCategory.Tracker3, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePosition", DeviceCategory.Tracker3, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/deviceRotation", DeviceCategory.Tracker3, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/velocity", DeviceCategory.Tracker3, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/angularVelocity", DeviceCategory.Tracker3, poseState: PoseState.AngularVelocity));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/isTracked", DeviceCategory.Tracker3, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePosition", DeviceCategory.Tracker3, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/deviceRotation", DeviceCategory.Tracker3, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/velocity", DeviceCategory.Tracker3, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/angularVelocity", DeviceCategory.Tracker3, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/isTracked", DeviceCategory.Tracker4, poseState: PoseState.IsTracked));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePosition", DeviceCategory.Tracker4, poseState: PoseState.Position));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/deviceRotation", DeviceCategory.Tracker4, poseState: PoseState.Rotation));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/velocity", DeviceCategory.Tracker4, poseState: PoseState.Velocity));
|
||||
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/angularVelocity", DeviceCategory.Tracker4, poseState: PoseState.AngularVelocity));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/isTracked", DeviceCategory.Tracker4, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePosition", DeviceCategory.Tracker4, in_PoseState: PoseState.Position, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/deviceRotation", DeviceCategory.Tracker4, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/velocity", DeviceCategory.Tracker4, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
|
||||
s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/angularVelocity", DeviceCategory.Tracker4, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
|
||||
#endregion
|
||||
}
|
||||
|
||||
private static bool GetInputActionMapping(DeviceCategory device, PoseState poseState, out InputActionMapping inputActionMapping)
|
||||
{
|
||||
inputActionMapping = default;
|
||||
for (int i = 0; i < s_InputActions.Count; i++)
|
||||
{
|
||||
var action = s_InputActions[i];
|
||||
if (action.device == device && action.poseState == poseState)
|
||||
{
|
||||
inputActionMapping = action;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool GetInputActionMapping(DeviceCategory device, ButtonEvent buttonEvent, out InputActionMapping inputActionMapping)
|
||||
{
|
||||
inputActionMapping = default;
|
||||
for (int i = 0; i < s_InputActions.Count; i++)
|
||||
{
|
||||
var action = s_InputActions[i];
|
||||
if (action.device == device && action.buttonEvent == buttonEvent)
|
||||
{
|
||||
inputActionMapping = action;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool GetInputActionMapping(DeviceCategory device, HandEvent handEvent, out InputActionMapping inputActionMapping)
|
||||
{
|
||||
inputActionMapping = default;
|
||||
for (int i = 0; i < s_InputActions.Count; i++)
|
||||
{
|
||||
var action = s_InputActions[i];
|
||||
if (action.device == device && action.handEvent == handEvent)
|
||||
{
|
||||
inputActionMapping = action;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void CheckHandUpdated()
|
||||
{
|
||||
if (Time.frameCount > leftHand.updateTime ||
|
||||
Time.frameCount > rightHand.updateTime)
|
||||
int frameCount = Time.frameCount;
|
||||
if (frameCount > m_LeftHand.updateTime ||
|
||||
frameCount > m_RightHand.updateTime)
|
||||
{
|
||||
ViveHandTracking viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
|
||||
if (viveHand)
|
||||
{
|
||||
UpdateViveHand(true, viveHand);
|
||||
UpdateViveHand(false, viveHand);
|
||||
}
|
||||
|
||||
#if UNITY_XR_HANDS
|
||||
HandTracking xrHand = OpenXRSettings.Instance.GetFeature<HandTracking>();
|
||||
if (xrHand)
|
||||
if (m_IsSupportViveHand || m_IsSupportXrHand)
|
||||
{
|
||||
if (handSubsystem == null || !handSubsystem.running)
|
||||
if (m_HandSubsystem == null || !m_HandSubsystem.running)
|
||||
{
|
||||
if (handSubsystem != null && !handSubsystem.running)
|
||||
if (m_HandSubsystem != null)
|
||||
{
|
||||
handSubsystem.updatedHands -= OnUpdatedHands;
|
||||
handSubsystem = null;
|
||||
m_HandSubsystem.updatedHands -= OnUpdatedHands;
|
||||
m_HandSubsystem = null;
|
||||
}
|
||||
|
||||
var handSubsystems = new List<XRHandSubsystem>();
|
||||
SubsystemManager.GetSubsystems(handSubsystems);
|
||||
for (var i = 0; i < handSubsystems.Count; ++i)
|
||||
m_HandSubsystems.Clear();
|
||||
SubsystemManager.GetSubsystems(m_HandSubsystems);
|
||||
for (var i = 0; i < m_HandSubsystems.Count; ++i)
|
||||
{
|
||||
var xrHnad = handSubsystems[i];
|
||||
if (xrHnad.running)
|
||||
var xrHand = m_HandSubsystems[i];
|
||||
if (xrHand.running)
|
||||
{
|
||||
handSubsystem = xrHnad;
|
||||
m_HandSubsystem = xrHand;
|
||||
m_HandSubsystem.updatedHands += OnUpdatedHands;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (handSubsystem != null && handSubsystem.running)
|
||||
{
|
||||
handSubsystem.updatedHands += OnUpdatedHands;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (m_IsSupportViveHand)
|
||||
{
|
||||
UpdateViveHand(true);
|
||||
UpdateViveHand(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateViveHand(bool isLeft, ViveHandTracking viveHand)
|
||||
private static void UpdateViveHand(bool isLeft)
|
||||
{
|
||||
bool isUpdated = viveHand.GetJointLocations(isLeft, out XrHandJointLocationEXT[] viveJoints);
|
||||
JointData[] joints = new JointData[viveJoints.Length];
|
||||
for (int i = 0; i < joints.Length; i++)
|
||||
bool isUpdated = XR_EXT_hand_tracking.Interop.GetJointLocations(isLeft, out XrHandJointLocationEXT[] viveJoints);
|
||||
for (int i = 0; i < m_JointBuffer.Length; i++)
|
||||
{
|
||||
bool isValid = isUpdated &&
|
||||
viveJoints[i].locationFlags.HasFlag(XrSpaceLocationFlags.XR_SPACE_LOCATION_POSITION_TRACKED_BIT) &&
|
||||
viveJoints[i].locationFlags.HasFlag(XrSpaceLocationFlags.XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT);
|
||||
Vector3 position = viveJoints[i].pose.position.ToUnityVector();
|
||||
Quaternion rotation = viveJoints[i].pose.orientation.ToUnityQuaternion();
|
||||
joints[i] = new JointData(isValid, position, rotation);
|
||||
m_JointBuffer[i] = new JointData(isValid, position, rotation);
|
||||
}
|
||||
if (isLeft)
|
||||
{
|
||||
leftHand.Update(joints);
|
||||
m_LeftHand.Update(m_JointBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
rightHand.Update(joints);
|
||||
m_RightHand.Update(m_JointBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_XR_HANDS
|
||||
private static void OnUpdatedHands(XRHandSubsystem xrHnad, XRHandSubsystem.UpdateSuccessFlags flags, XRHandSubsystem.UpdateType type)
|
||||
private static void OnUpdatedHands(XRHandSubsystem xrHnad, XRHandSubsystem.UpdateSuccessFlags flags, XRHandSubsystem.UpdateType type)
|
||||
{
|
||||
if (xrHnad != null && xrHnad.running)
|
||||
{
|
||||
@@ -732,42 +796,48 @@ namespace VIVE.OpenXR.Toolkits.Common
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateXRHand(bool isLeft, XRHandSubsystem xrHnad, bool isUpdated)
|
||||
private static void UpdateXRHand(bool isLeft, XRHandSubsystem xrHand, bool isUpdated)
|
||||
{
|
||||
JointData[] joints = new JointData[(int)HandJointType.Count];
|
||||
for (int i = 0; i < joints.Length; i++)
|
||||
for (int i = 0; i < m_JointBuffer.Length; i++)
|
||||
{
|
||||
XRHandJointID jointId = JointTypeToXRId(i);
|
||||
XRHandJoint joint = (isLeft ? xrHnad.leftHand : xrHnad.rightHand).GetJoint(jointId);
|
||||
bool isValid = isUpdated && joint.trackingState.HasFlag(XRHandJointTrackingState.Pose);
|
||||
joint.TryGetPose(out Pose pose);
|
||||
joints[i] = new JointData(isValid, pose.position, pose.rotation);
|
||||
}
|
||||
if (isLeft)
|
||||
{
|
||||
leftHand.Update(joints);
|
||||
}
|
||||
else
|
||||
{
|
||||
rightHand.Update(joints);
|
||||
}
|
||||
}
|
||||
XRHandJoint joint = (isLeft ? xrHand.leftHand : xrHand.rightHand).GetJoint(jointId);
|
||||
|
||||
private static XRHandJointID JointTypeToXRId(int id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0:
|
||||
return XRHandJointID.Palm;
|
||||
case 1:
|
||||
return XRHandJointID.Wrist;
|
||||
default:
|
||||
return (XRHandJointID)(id + 1);
|
||||
}
|
||||
}
|
||||
if (isUpdated && joint.trackingState.HasFlag(XRHandJointTrackingState.Pose))
|
||||
{
|
||||
joint.TryGetPose(out Pose pose);
|
||||
m_JointBuffer[i] = new JointData(true, pose.position, pose.rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_JointBuffer[i] = new JointData(false, Vector3.zero, Quaternion.identity);
|
||||
}
|
||||
}
|
||||
if (isLeft)
|
||||
{
|
||||
m_LeftHand.Update(m_JointBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RightHand.Update(m_JointBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static XRHandJointID JointTypeToXRId(int id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0:
|
||||
return XRHandJointID.Palm;
|
||||
case 1:
|
||||
return XRHandJointID.Wrist;
|
||||
default:
|
||||
return (XRHandJointID)(id + 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private static DeviceCategory GetController(Handedness handedness)
|
||||
private static DeviceCategory GetController(Handedness handedness)
|
||||
{
|
||||
DeviceCategory device = DeviceCategory.None;
|
||||
switch (handedness)
|
||||
|
||||
@@ -5,8 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using System.Threading.Tasks;
|
||||
using VIVE.OpenXR;
|
||||
using System.Linq;
|
||||
|
||||
namespace VIVE.OpenXR.Passthrough
|
||||
{
|
||||
@@ -27,13 +26,7 @@ namespace VIVE.OpenXR.Passthrough
|
||||
return false;
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
private static Dictionary<XrPassthroughHTC, XrCompositionLayerPassthroughHTC> passthrough2Layer = new Dictionary<XrPassthroughHTC, XrCompositionLayerPassthroughHTC>();
|
||||
private static Dictionary<XrPassthroughHTC, IntPtr> passthrough2LayerPtr = new Dictionary<XrPassthroughHTC, IntPtr>();
|
||||
private static Dictionary<XrPassthroughHTC, bool> passthrough2IsUnderLay= new Dictionary<XrPassthroughHTC, bool>();
|
||||
private static Dictionary<XrPassthroughHTC, XrPassthroughMeshTransformInfoHTC> passthrough2meshTransform = new Dictionary<XrPassthroughHTC, XrPassthroughMeshTransformInfoHTC>();
|
||||
private static Dictionary<XrPassthroughHTC, IntPtr> passthrough2meshTransformInfoPtr = new Dictionary<XrPassthroughHTC, IntPtr>();
|
||||
#endif
|
||||
private static Dictionary<XrPassthroughHTC, PassthroughLayer> layersDict = new Dictionary<XrPassthroughHTC, PassthroughLayer>();
|
||||
|
||||
#region Public APIs
|
||||
/// <summary>
|
||||
@@ -58,42 +51,32 @@ namespace VIVE.OpenXR.Passthrough
|
||||
}
|
||||
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
|
||||
XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC,
|
||||
#if UNITY_ANDROID
|
||||
IntPtr.Zero,
|
||||
#else
|
||||
new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe.
|
||||
#endif
|
||||
XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PLANAR_HTC
|
||||
);
|
||||
|
||||
#if UNITY_ANDROID
|
||||
res = passthroughFeature.CreatePassthroughHTC(createInfo, out passthrough, layerType, compositionDepth, onDestroyPassthroughSessionHandler);
|
||||
DEBUG("CreatePlanarPassthrough() CreatePassthroughHTC result: " + res + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
#if UNITY_STANDALONE
|
||||
res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough);
|
||||
if(res == XrResult.XR_SUCCESS)
|
||||
{
|
||||
XrPassthroughColorHTC passthroughColor = new XrPassthroughColorHTC(
|
||||
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_COLOR_HTC,
|
||||
in_next: IntPtr.Zero,
|
||||
in_alpha: alpha);
|
||||
XrCompositionLayerPassthroughHTC compositionLayerPassthrough = new XrCompositionLayerPassthroughHTC(
|
||||
in_type: XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC,
|
||||
in_next: IntPtr.Zero,
|
||||
in_layerFlags: (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT,
|
||||
in_space: 0,
|
||||
in_passthrough: passthrough,
|
||||
in_color: passthroughColor);
|
||||
passthrough2Layer.Add(passthrough, compositionLayerPassthrough);
|
||||
IntPtr layerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrCompositionLayerPassthroughHTC)));
|
||||
passthrough2LayerPtr.Add(passthrough, layerPtr);
|
||||
if (layerType == CompositionLayer.LayerType.Underlay)
|
||||
passthrough2IsUnderLay.Add(passthrough, true);
|
||||
if (layerType == CompositionLayer.LayerType.Overlay)
|
||||
passthrough2IsUnderLay.Add(passthrough, false);
|
||||
{
|
||||
PassthroughLayer layer = new PassthroughLayer(passthrough, layerType);
|
||||
var xrLayer = PassthroughLayer.MakeEmptyLayer();
|
||||
xrLayer.passthrough = passthrough;
|
||||
xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
xrLayer.color.alpha = alpha;
|
||||
layer.SetLayer(xrLayer);
|
||||
|
||||
layersDict.Add(passthrough, layer);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (res == XrResult.XR_SUCCESS)
|
||||
{
|
||||
SetPassthroughAlpha(passthrough, alpha);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -138,54 +121,34 @@ namespace VIVE.OpenXR.Passthrough
|
||||
|
||||
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
|
||||
XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC,
|
||||
#if UNITY_ANDROID
|
||||
IntPtr.Zero,
|
||||
#else
|
||||
new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe.
|
||||
#endif
|
||||
XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PROJECTED_HTC
|
||||
);
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough);
|
||||
if (res == XrResult.XR_SUCCESS)
|
||||
{
|
||||
XrPassthroughMeshTransformInfoHTC PassthroughMeshTransformInfo = new XrPassthroughMeshTransformInfoHTC(
|
||||
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC,
|
||||
in_next: IntPtr.Zero,
|
||||
in_vertexCount: 0,
|
||||
in_vertices: new XrVector3f[0],
|
||||
in_indexCount: 0,
|
||||
in_indices: new UInt32[0],
|
||||
in_baseSpace: XR_HTC_passthrough.Interop.GetTrackingSpace(),
|
||||
in_time: XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime,
|
||||
in_pose: new XrPosef(),
|
||||
in_scale: new XrVector3f()
|
||||
);
|
||||
IntPtr meshTransformInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrPassthroughMeshTransformInfoHTC)));
|
||||
Marshal.StructureToPtr(PassthroughMeshTransformInfo, meshTransformInfoPtr, false);
|
||||
XrPassthroughColorHTC passthroughColor = new XrPassthroughColorHTC(
|
||||
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_COLOR_HTC,
|
||||
in_next: IntPtr.Zero,
|
||||
in_alpha: alpha);
|
||||
XrCompositionLayerPassthroughHTC compositionLayerPassthrough = new XrCompositionLayerPassthroughHTC(
|
||||
in_type: XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC,
|
||||
in_next: meshTransformInfoPtr,
|
||||
in_layerFlags: (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT,
|
||||
in_space: 0,
|
||||
in_passthrough: passthrough,
|
||||
in_color: passthroughColor);
|
||||
passthrough2meshTransform.Add(passthrough, PassthroughMeshTransformInfo);
|
||||
passthrough2meshTransformInfoPtr.Add(passthrough, meshTransformInfoPtr);
|
||||
passthrough2Layer.Add(passthrough, compositionLayerPassthrough);
|
||||
IntPtr layerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrCompositionLayerPassthroughHTC)));
|
||||
passthrough2LayerPtr.Add(passthrough, layerPtr);
|
||||
if (layerType == CompositionLayer.LayerType.Underlay)
|
||||
passthrough2IsUnderLay.Add(passthrough, true);
|
||||
if (layerType == CompositionLayer.LayerType.Overlay)
|
||||
passthrough2IsUnderLay.Add(passthrough, false);
|
||||
var layer = new PassthroughLayer(passthrough, layerType);
|
||||
var xrLayer = PassthroughLayer.MakeEmptyLayer();
|
||||
xrLayer.passthrough = passthrough;
|
||||
xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
xrLayer.space = 0;
|
||||
xrLayer.color.alpha = alpha;
|
||||
layer.SetLayer(xrLayer);
|
||||
var xrMesh = PassthroughLayer.MakeMeshTransform();
|
||||
|
||||
xrMesh.time = XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime;
|
||||
xrMesh.baseSpace = XR_HTC_passthrough.Interop.GetTrackingSpace();
|
||||
xrMesh.scale = new XrVector3f(meshScale.x, meshScale.y, meshScale.z);
|
||||
layer.SetMeshTransform(xrMesh);
|
||||
|
||||
layersDict.Add(passthrough, layer);
|
||||
}
|
||||
#endif
|
||||
#if UNITY_ANDROID
|
||||
res = passthroughFeature.CreatePassthroughHTC(createInfo, out passthrough, layerType, compositionDepth, onDestroyPassthroughSessionHandler);
|
||||
DEBUG("CreateProjectedPassthrough() CreatePassthroughHTC result: " + res + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
|
||||
if (res == XrResult.XR_SUCCESS)
|
||||
{
|
||||
SetPassthroughAlpha(passthrough, alpha);
|
||||
@@ -219,54 +182,30 @@ namespace VIVE.OpenXR.Passthrough
|
||||
|
||||
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
|
||||
XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC,
|
||||
#if UNITY_ANDROID
|
||||
IntPtr.Zero,
|
||||
#else
|
||||
new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe.
|
||||
#endif
|
||||
XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PROJECTED_HTC
|
||||
);
|
||||
);
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough);
|
||||
if (res == XrResult.XR_SUCCESS)
|
||||
{
|
||||
XrPassthroughMeshTransformInfoHTC PassthroughMeshTransformInfo = new XrPassthroughMeshTransformInfoHTC(
|
||||
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC,
|
||||
in_next: IntPtr.Zero,
|
||||
in_vertexCount: 0,
|
||||
in_vertices: new XrVector3f[0],
|
||||
in_indexCount: 0,
|
||||
in_indices: new UInt32[0],
|
||||
in_baseSpace: XR_HTC_passthrough.Interop.GetTrackingSpace(),
|
||||
in_time: XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime,
|
||||
in_pose: new XrPosef(),
|
||||
in_scale: new XrVector3f()
|
||||
);
|
||||
IntPtr meshTransformInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrPassthroughMeshTransformInfoHTC)));
|
||||
Marshal.StructureToPtr(PassthroughMeshTransformInfo, meshTransformInfoPtr, false);
|
||||
XrPassthroughColorHTC passthroughColor = new XrPassthroughColorHTC(
|
||||
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_COLOR_HTC,
|
||||
in_next: IntPtr.Zero,
|
||||
in_alpha: alpha);
|
||||
XrCompositionLayerPassthroughHTC compositionLayerPassthrough = new XrCompositionLayerPassthroughHTC(
|
||||
in_type: XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC,
|
||||
in_next: meshTransformInfoPtr,
|
||||
in_layerFlags: (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT,
|
||||
in_space: 0,
|
||||
in_passthrough: passthrough,
|
||||
in_color: passthroughColor);
|
||||
passthrough2meshTransform.Add(passthrough, PassthroughMeshTransformInfo);
|
||||
passthrough2meshTransformInfoPtr.Add(passthrough, meshTransformInfoPtr);
|
||||
passthrough2Layer.Add(passthrough, compositionLayerPassthrough);
|
||||
IntPtr layerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrCompositionLayerPassthroughHTC)));
|
||||
passthrough2LayerPtr.Add(passthrough, layerPtr);
|
||||
if (layerType == CompositionLayer.LayerType.Underlay)
|
||||
passthrough2IsUnderLay.Add(passthrough, true);
|
||||
if (layerType == CompositionLayer.LayerType.Overlay)
|
||||
passthrough2IsUnderLay.Add(passthrough, false);
|
||||
var layer = new PassthroughLayer(passthrough, layerType);
|
||||
var xrLayer = PassthroughLayer.MakeEmptyLayer();
|
||||
xrLayer.passthrough = passthrough;
|
||||
xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
xrLayer.color.alpha = alpha;
|
||||
layer.SetLayer(xrLayer);
|
||||
|
||||
var xrMesh = PassthroughLayer.MakeMeshTransform();
|
||||
layer.SetMeshTransform(xrMesh, true);
|
||||
|
||||
layersDict.Add(passthrough, layer);
|
||||
}
|
||||
#endif
|
||||
#if UNITY_ANDROID
|
||||
res = passthroughFeature.CreatePassthroughHTC(createInfo, out passthrough, layerType, onDestroyPassthroughSessionHandler);
|
||||
DEBUG("CreateProjectedPassthrough() CreatePassthroughHTC result: " + res + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
|
||||
if (res == XrResult.XR_SUCCESS)
|
||||
{
|
||||
SetPassthroughAlpha(passthrough, alpha);
|
||||
@@ -275,43 +214,18 @@ namespace VIVE.OpenXR.Passthrough
|
||||
return res;
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
private static async void SubmitLayer()
|
||||
{
|
||||
await Task.Run(() => {
|
||||
int layerListCount = 0;
|
||||
while(layerListCount == 0)
|
||||
{
|
||||
System.Threading.Thread.Sleep(1);
|
||||
XR_HTC_passthrough.Interop.GetOriginEndFrameLayerList(out List<IntPtr> layerList);//GetOriginEndFrameLayers
|
||||
layerListCount = layerList.Count;
|
||||
foreach (var passthrough in passthrough2IsUnderLay.Keys)
|
||||
{
|
||||
//Get and submit layer list
|
||||
if (layerListCount != 0)
|
||||
{
|
||||
Marshal.StructureToPtr(passthrough2Layer[passthrough], passthrough2LayerPtr[passthrough], false);
|
||||
if (passthrough2IsUnderLay[passthrough])
|
||||
layerList.Insert(0, passthrough2LayerPtr[passthrough]);
|
||||
else
|
||||
layerList.Insert(1, passthrough2LayerPtr[passthrough]);
|
||||
}
|
||||
}
|
||||
if(layerListCount != 0)
|
||||
XR_HTC_passthrough.Interop.SubmitLayers(layerList);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
#endif
|
||||
private static void SubmitLayer()
|
||||
{
|
||||
passthroughFeature.SubmitLayers(layersDict.Values.ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To Destroying a passthrough.
|
||||
/// You should call this function when the <see cref="VivePassthrough.OnPassthroughSessionDestroyDelegate">delegate</see> is invoked.
|
||||
/// </summary>
|
||||
/// <param name="passthrough">The created <see cref="XrPassthroughHTC"/></param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
public static XrResult DestroyPassthrough(XrPassthroughHTC passthrough)
|
||||
/// <summary>
|
||||
/// To Destroying a passthrough.
|
||||
/// You should call this function when the <see cref="VivePassthrough.OnPassthroughSessionDestroyDelegate">delegate</see> is invoked.
|
||||
/// </summary>
|
||||
/// <param name="passthrough">The created <see cref="XrPassthroughHTC"/></param>
|
||||
/// <returns>XR_SUCCESS for success.</returns>
|
||||
public static XrResult DestroyPassthrough(XrPassthroughHTC passthrough)
|
||||
{
|
||||
XrResult res = XrResult.XR_ERROR_RUNTIME_FAILURE;
|
||||
|
||||
@@ -326,23 +240,17 @@ namespace VIVE.OpenXR.Passthrough
|
||||
return res;
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
XrPassthroughHTC pt = passthrough2Layer[passthrough].passthrough;
|
||||
XR_HTC_passthrough.xrDestroyPassthroughHTC(pt);
|
||||
passthrough2IsUnderLay.Remove(passthrough);
|
||||
if (layersDict.ContainsKey(passthrough))
|
||||
{
|
||||
XR_HTC_passthrough.xrDestroyPassthroughHTC(passthrough);
|
||||
var layer = layersDict[passthrough];
|
||||
layer.Dispose();
|
||||
layersDict.Remove(passthrough);
|
||||
}
|
||||
|
||||
SubmitLayer();
|
||||
passthrough2Layer.Remove(pt);
|
||||
if(passthrough2LayerPtr.ContainsKey(passthrough)) Marshal.FreeHGlobal(passthrough2LayerPtr[passthrough]);
|
||||
passthrough2LayerPtr.Remove(passthrough);
|
||||
if(passthrough2meshTransformInfoPtr.ContainsKey(passthrough)) Marshal.FreeHGlobal(passthrough2meshTransformInfoPtr[passthrough]);
|
||||
passthrough2meshTransformInfoPtr.Remove(passthrough);
|
||||
passthrough2meshTransform.Remove(passthrough);
|
||||
|
||||
res = XrResult.XR_SUCCESS;
|
||||
#elif UNITY_ANDROID
|
||||
res = passthroughFeature.DestroyPassthroughHTC(passthrough);
|
||||
DEBUG("DestroyPassthrough() DestroyPassthroughHTC result: " + res + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -368,36 +276,18 @@ namespace VIVE.OpenXR.Passthrough
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
if (autoClamp)
|
||||
if (layersDict.ContainsKey(passthrough))
|
||||
{
|
||||
ret = passthroughFeature.SetAlpha(passthrough, Mathf.Clamp01(alpha));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (alpha < 0f || alpha > 1f)
|
||||
{
|
||||
ERROR("SetPassthroughAlpha: Alpha out of range");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = passthroughFeature.SetAlpha(passthrough, alpha);
|
||||
}
|
||||
DEBUG("SetPassthroughAlpha() SetAlpha result: " + ret + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
if (passthrough2Layer.ContainsKey(passthrough))
|
||||
{
|
||||
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
|
||||
layer.color.alpha = alpha;
|
||||
passthrough2Layer[passthrough] = layer;
|
||||
var layer = layersDict[passthrough];
|
||||
var xrLayer = layer.GetLayer();
|
||||
xrLayer.color.alpha = alpha;
|
||||
layer.SetLayer(xrLayer);
|
||||
|
||||
SubmitLayer();
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -425,45 +315,18 @@ namespace VIVE.OpenXR.Passthrough
|
||||
return ret;
|
||||
}
|
||||
|
||||
XrVector3f[] vertexBufferXrVector = new XrVector3f[vertexBuffer.Length];
|
||||
if (layersDict[passthrough] == null)
|
||||
{
|
||||
ERROR("Passthrough layer not found.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < vertexBuffer.Length; i++)
|
||||
{
|
||||
vertexBufferXrVector[i] = OpenXRHelper.ToOpenXRVector(vertexBuffer[i], convertFromUnityToOpenXR);
|
||||
}
|
||||
|
||||
uint[] indexBufferUint = new uint[indexBuffer.Length];
|
||||
|
||||
for (int i = 0; i < indexBuffer.Length; i++)
|
||||
{
|
||||
indexBufferUint[i] = (uint)indexBuffer[i];
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
|
||||
{
|
||||
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
|
||||
MeshTransformInfo.vertexCount = (uint)vertexBuffer.Length;
|
||||
MeshTransformInfo.vertices = vertexBufferXrVector;
|
||||
MeshTransformInfo.indexCount = (uint)indexBuffer.Length;
|
||||
MeshTransformInfo.indices = indexBufferUint;
|
||||
passthrough2meshTransform[passthrough] = MeshTransformInfo;
|
||||
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
|
||||
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
|
||||
layer.next = passthrough2meshTransformInfoPtr[passthrough];
|
||||
passthrough2Layer[passthrough] = layer;
|
||||
SubmitLayer();
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
#endif
|
||||
//Note: Ignore Clock-Wise definition of index buffer for now as passthrough extension does not have back-face culling
|
||||
#if UNITY_ANDROID
|
||||
ret = passthroughFeature.SetMesh(passthrough, (uint)vertexBuffer.Length, vertexBufferXrVector, (uint)indexBuffer.Length, indexBufferUint); ;
|
||||
DEBUG("SetProjectedPassthroughMesh() SetMesh result: " + ret + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
return ret;
|
||||
var layer = layersDict[passthrough];
|
||||
var xrMesh = layer.GetMesh();
|
||||
layer.SetMeshData(ref xrMesh, vertexBuffer, indexBuffer, convertFromUnityToOpenXR);
|
||||
layer.SetMeshTransform(xrMesh);
|
||||
SubmitLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -508,29 +371,22 @@ namespace VIVE.OpenXR.Passthrough
|
||||
|
||||
XrVector3f meshXrScale = OpenXRHelper.ToOpenXRVector(meshScale, false);
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
|
||||
{
|
||||
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
|
||||
MeshTransformInfo.pose = meshXrPose;
|
||||
MeshTransformInfo.scale = meshXrScale;
|
||||
passthrough2meshTransform[passthrough] = MeshTransformInfo;
|
||||
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
|
||||
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
|
||||
layer.next = passthrough2meshTransformInfoPtr[passthrough];
|
||||
passthrough2Layer[passthrough] = layer;
|
||||
SubmitLayer();
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
#endif
|
||||
if (layersDict[passthrough] == null)
|
||||
{
|
||||
ERROR("Passthrough layer not found.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
ret = passthroughFeature.SetMeshTransform(passthrough, passthroughFeature.GetXrSpaceFromSpaceType(spaceType), meshXrPose, meshXrScale);
|
||||
DEBUG("SetProjectedPassthroughMeshTransform() SetMeshTransform result: " + ret + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
return ret;
|
||||
var layer = layersDict[passthrough];
|
||||
var xrMesh = layer.GetMesh();
|
||||
xrMesh.pose = meshXrPose;
|
||||
xrMesh.scale = meshXrScale;
|
||||
xrMesh.time = XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime;
|
||||
xrMesh.baseSpace = passthroughFeature.GetXrSpaceFromSpaceType(spaceType);
|
||||
|
||||
layer.SetMeshTransform(xrMesh);
|
||||
SubmitLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -550,22 +406,18 @@ namespace VIVE.OpenXR.Passthrough
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
if (passthrough2IsUnderLay.ContainsKey(passthrough))
|
||||
{
|
||||
passthrough2IsUnderLay[passthrough] = layerType == CompositionLayer.LayerType.Underlay ? true : false;
|
||||
SubmitLayer();
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
#endif
|
||||
if (layersDict[passthrough] == null)
|
||||
{
|
||||
ERROR("Passthrough layer not found.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
ret = passthroughFeature.SetLayerType(passthrough, layerType, compositionDepth);
|
||||
DEBUG("SetPassthroughLayerType() SetLayerType result: " + ret + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
return ret;
|
||||
var layer = layersDict[passthrough];
|
||||
layer.LayerType = layerType;
|
||||
layer.Depth = (int)compositionDepth;
|
||||
|
||||
SubmitLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -584,28 +436,18 @@ namespace VIVE.OpenXR.Passthrough
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
|
||||
{
|
||||
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
|
||||
MeshTransformInfo.baseSpace = passthroughFeature.GetXrSpaceFromSpaceType(spaceType);
|
||||
passthrough2meshTransform[passthrough] = MeshTransformInfo;
|
||||
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
|
||||
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
|
||||
layer.next = passthrough2meshTransformInfoPtr[passthrough];
|
||||
passthrough2Layer[passthrough] = layer;
|
||||
SubmitLayer();
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
#endif
|
||||
if (layersDict[passthrough] == null)
|
||||
{
|
||||
ERROR("Passthrough layer not found.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
ret = passthroughFeature.SetMeshTransformSpace(passthrough, passthroughFeature.GetXrSpaceFromSpaceType(spaceType));
|
||||
DEBUG("SetProjectedPassthroughSpaceType() SetMeshTransformSpace result: " + ret + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
return ret;
|
||||
var layer = layersDict[passthrough];
|
||||
var xrMesh = layer.GetMesh();
|
||||
xrMesh.baseSpace = passthroughFeature.GetXrSpaceFromSpaceType(spaceType);
|
||||
layer.SetMeshTransform(xrMesh);
|
||||
SubmitLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -639,30 +481,18 @@ namespace VIVE.OpenXR.Passthrough
|
||||
trackingSpaceMeshPosition = trackingSpaceLayerPoseTRS.GetColumn(3); //4th Column of TRS Matrix is the position
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
|
||||
{
|
||||
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
|
||||
XrPosef meshXrPose = MeshTransformInfo.pose;
|
||||
meshXrPose.position = OpenXRHelper.ToOpenXRVector(trackingSpaceMeshPosition, convertFromUnityToOpenXR); ;
|
||||
MeshTransformInfo.pose = meshXrPose;
|
||||
passthrough2meshTransform[passthrough] = MeshTransformInfo;
|
||||
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
|
||||
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
|
||||
layer.next = passthrough2meshTransformInfoPtr[passthrough];
|
||||
passthrough2Layer[passthrough] = layer;
|
||||
SubmitLayer();
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
#endif
|
||||
if (layersDict[passthrough] == null)
|
||||
{
|
||||
ERROR("Passthrough layer not found.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
ret = passthroughFeature.SetMeshTransformPosition(passthrough, OpenXRHelper.ToOpenXRVector(trackingSpaceMeshPosition, convertFromUnityToOpenXR));
|
||||
DEBUG("SetProjectedPassthroughMeshPosition() SetMeshTransformPosition result: " + ret + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
return ret;
|
||||
var layer = layersDict[passthrough];
|
||||
var xrMesh = layer.GetMesh();
|
||||
xrMesh.pose.position = OpenXRHelper.ToOpenXRVector(trackingSpaceMeshPosition, convertFromUnityToOpenXR);
|
||||
layer.SetMeshTransform(xrMesh);
|
||||
SubmitLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -696,30 +526,18 @@ namespace VIVE.OpenXR.Passthrough
|
||||
trackingSpaceMeshRotation = Quaternion.LookRotation(trackingSpaceLayerPoseTRS.GetColumn(2), trackingSpaceLayerPoseTRS.GetColumn(1));
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
|
||||
{
|
||||
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
|
||||
XrPosef meshXrPose = MeshTransformInfo.pose;
|
||||
meshXrPose.orientation = OpenXRHelper.ToOpenXRQuaternion(trackingSpaceMeshRotation, convertFromUnityToOpenXR);
|
||||
MeshTransformInfo.pose = meshXrPose;
|
||||
passthrough2meshTransform[passthrough] = MeshTransformInfo;
|
||||
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
|
||||
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
|
||||
layer.next = passthrough2meshTransformInfoPtr[passthrough];
|
||||
passthrough2Layer[passthrough] = layer;
|
||||
SubmitLayer();
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
#endif
|
||||
if (layersDict[passthrough] == null)
|
||||
{
|
||||
ERROR("Passthrough layer not found.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
ret = passthroughFeature.SetMeshTransformOrientation(passthrough, OpenXRHelper.ToOpenXRQuaternion(trackingSpaceMeshRotation, convertFromUnityToOpenXR));
|
||||
DEBUG("SetProjectedPassthroughMeshOrientation() SetMeshTransformOrientation result: " + ret + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
return ret;
|
||||
var layer = layersDict[passthrough];
|
||||
var xrMesh = layer.GetMesh();
|
||||
xrMesh.pose.orientation = OpenXRHelper.ToOpenXRQuaternion(trackingSpaceMeshRotation, convertFromUnityToOpenXR);
|
||||
layer.SetMeshTransform(xrMesh);
|
||||
SubmitLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -738,28 +556,18 @@ namespace VIVE.OpenXR.Passthrough
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE
|
||||
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
|
||||
{
|
||||
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
|
||||
MeshTransformInfo.scale = OpenXRHelper.ToOpenXRVector(meshScale, false);
|
||||
passthrough2meshTransform[passthrough] = MeshTransformInfo;
|
||||
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
|
||||
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
|
||||
layer.next = passthrough2meshTransformInfoPtr[passthrough];
|
||||
passthrough2Layer[passthrough] = layer;
|
||||
SubmitLayer();
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
#endif
|
||||
if (layersDict[passthrough] == null)
|
||||
{
|
||||
ERROR("Passthrough layer not found.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
ret = passthroughFeature.SetMeshTransformScale(passthrough, OpenXRHelper.ToOpenXRVector(meshScale, false));
|
||||
DEBUG("SetProjectedPassthroughScale() SetMeshTransformScale result: " + ret + ", passthrough: " + passthrough);
|
||||
#endif
|
||||
return ret;
|
||||
var layer = layersDict[passthrough];
|
||||
var xrMesh = layer.GetMesh();
|
||||
xrMesh.scale = OpenXRHelper.ToOpenXRVector(meshScale, false);
|
||||
layer.SetMeshTransform(xrMesh);
|
||||
SubmitLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -699,6 +699,7 @@ GameObject:
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4806409459047702211}
|
||||
- component: {fileID: 5568897672767345397}
|
||||
- component: {fileID: 1039589470112983849}
|
||||
- component: {fileID: 1039589470112983840}
|
||||
- component: {fileID: 1039589470112983852}
|
||||
@@ -725,6 +726,19 @@ Transform:
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &5568897672767345397
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4806409459047702212}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 52790aba0e3d55f4fb27aded6c698d8b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Handedness: 1
|
||||
--- !u!114 &1039589470112983849
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -858,6 +858,7 @@ GameObject:
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7152668487518777764}
|
||||
- component: {fileID: 7057365311429264906}
|
||||
- component: {fileID: 3431167848623168894}
|
||||
- component: {fileID: 3431167848623168881}
|
||||
- component: {fileID: 3431167848623168882}
|
||||
@@ -884,6 +885,19 @@ Transform:
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &7057365311429264906
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7152668487518777765}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 52790aba0e3d55f4fb27aded6c698d8b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Handedness: 0
|
||||
--- !u!114 &3431167848623168894
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
// conditions signed by you and all SDK and API requirements,
|
||||
// specifications, and documentation provided by HTC to You."
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
{
|
||||
@@ -129,6 +130,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
private HandGrabInteractable candidate = null;
|
||||
private Pose wristPose = Pose.identity;
|
||||
private Quaternion[] fingerJointRotation = new Quaternion[jointsPathMapping.Count];
|
||||
private bool isNewInputSystem = false;
|
||||
|
||||
#region MonoBehaviours
|
||||
|
||||
@@ -156,6 +158,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
sb.Append("However, you still can record grab pose if you use direct preview mode.");
|
||||
WARNING(sb);
|
||||
}
|
||||
isNewInputSystem = Keyboard.current != null;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
@@ -199,7 +202,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))
|
||||
if (IsEnterPressed())
|
||||
{
|
||||
FindNearInteractable();
|
||||
SavePoseWithCandidate();
|
||||
@@ -326,6 +329,19 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
return updated;
|
||||
}
|
||||
|
||||
private bool IsEnterPressed()
|
||||
{
|
||||
if (isNewInputSystem)
|
||||
{
|
||||
return (Keyboard.current.enterKey?.wasPressedThisFrame ?? false) ||
|
||||
(Keyboard.current.numpadEnterKey?.wasPressedThisFrame ?? false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the nearest interactable object to the hand.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
// conditions signed by you and all SDK and API requirements,
|
||||
// specifications, and documentation provided by HTC to You."
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
@@ -87,8 +86,8 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
|
||||
[SerializeField]
|
||||
private IOneHandContraintMovement m_OneHandContraintMovement;
|
||||
public IOneHandContraintMovement oneHandContraintMovement { get { return m_OneHandContraintMovement; } set { m_OneHandContraintMovement = value; } }
|
||||
public bool isContraint => m_OneHandContraintMovement != null;
|
||||
public IOneHandContraintMovement oneHandContraintMovement { get { return m_OneHandContraintMovement; } set { m_OneHandContraintMovement = value; } }
|
||||
public bool isContraint => m_OneHandContraintMovement != null;
|
||||
|
||||
#pragma warning disable
|
||||
[SerializeField]
|
||||
@@ -183,8 +182,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
{
|
||||
if (!isGrabbable || isGrabbed) { return 0; }
|
||||
Vector3 closestPoint = GetClosestPoint(grabberPos);
|
||||
float distacne = Vector3.Distance(grabberPos, closestPoint);
|
||||
return distacne > grabDistance ? 0 : 1 - (distacne / grabDistance);
|
||||
float distanceSqr = (grabberPos - closestPoint).sqrMagnitude;
|
||||
float grabDistSqr = grabDistance * grabDistance;
|
||||
return distanceSqr > grabDistSqr ? 0 : 1 - (distanceSqr / grabDistSqr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -263,35 +263,41 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
private Vector3 GetClosestPoint(Vector3 sourcePos)
|
||||
{
|
||||
Vector3 closestPoint = Vector3.zero;
|
||||
float shortDistance = float.MaxValue;
|
||||
float shortDistanceSqr = float.MaxValue;
|
||||
for (int i = 0; i < allColliders.Count; i++)
|
||||
{
|
||||
Collider collider = allColliders[i];
|
||||
Vector3 closePoint = collider.ClosestPointOnBounds(sourcePos);
|
||||
float distance = Vector3.Distance(sourcePos, closePoint);
|
||||
float distanceSqr = (sourcePos - closePoint).sqrMagnitude;
|
||||
if (distanceSqr < 0.001f)
|
||||
{
|
||||
return closePoint;
|
||||
}
|
||||
|
||||
if (collider.bounds.Contains(closePoint))
|
||||
{
|
||||
Vector3 direction = closePoint - sourcePos;
|
||||
direction.Normalize();
|
||||
int hitCount = Physics.RaycastNonAlloc(sourcePos, direction, hitResults, distance);
|
||||
int hitCount = Physics.RaycastNonAlloc(sourcePos, direction, hitResults, Mathf.Sqrt(distanceSqr));
|
||||
|
||||
for (int j = 0; j < hitCount; j++)
|
||||
{
|
||||
RaycastHit hit = hitResults[j];
|
||||
if (hit.collider == collider)
|
||||
{
|
||||
float hitDistance = Vector3.Distance(sourcePos, hit.point);
|
||||
if (distance > hitDistance)
|
||||
float hitDistanceSqr = (sourcePos - hit.point).sqrMagnitude;
|
||||
if (distanceSqr > hitDistanceSqr)
|
||||
{
|
||||
distance = hitDistance;
|
||||
distanceSqr = hitDistanceSqr;
|
||||
closePoint = hit.point;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shortDistance > distance)
|
||||
if (shortDistanceSqr > distanceSqr)
|
||||
{
|
||||
shortDistance = distance;
|
||||
shortDistanceSqr = distanceSqr;
|
||||
closestPoint = closePoint;
|
||||
}
|
||||
}
|
||||
@@ -361,9 +367,12 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
/// <param name="index">The index of the indicator to show.</param>
|
||||
private void ShowIndicatorByIndex(int index)
|
||||
{
|
||||
foreach (var grabPose in m_GrabPoses)
|
||||
for (int i = 0; i < m_GrabPoses.Count; i++)
|
||||
{
|
||||
grabPose.indicator.SetActive(false);
|
||||
if (index != i)
|
||||
{
|
||||
m_GrabPoses[i].indicator.SetActive(false);
|
||||
}
|
||||
}
|
||||
if (index >= 0 && index < m_GrabPoses.Count &&
|
||||
m_GrabPoses[index].indicator.enableIndicator)
|
||||
@@ -379,9 +388,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
/// <param name="isLeft">Whether the hand side is left.</param>
|
||||
private void ShowAllIndicator(bool isLeft)
|
||||
{
|
||||
foreach (var grabPose in m_GrabPoses)
|
||||
for (int i = 0; i < m_GrabPoses.Count; i++)
|
||||
{
|
||||
grabPose.indicator.SetActive(false);
|
||||
m_GrabPoses[i].indicator.SetActive(false);
|
||||
}
|
||||
foreach (var grabPose in m_GrabPoses)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
// conditions signed by you and all SDK and API requirements,
|
||||
// specifications, and documentation provided by HTC to You."
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
@@ -79,6 +78,13 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
private Pose wristPose = Pose.identity;
|
||||
private Vector3[] fingerTipPosition = new Vector3[(int)FingerId.Count];
|
||||
|
||||
private const int kMaxCacheSize = 100;
|
||||
private int lastBufferCount = 0;
|
||||
private Collider[] colliderBuffer = new Collider[50];
|
||||
private HandGrabInteractable[] grabbableBuffer = new HandGrabInteractable[50];
|
||||
private LinkedList<Collider> lruList = new LinkedList<Collider>();
|
||||
private Dictionary<Collider, LinkedListNode<Collider>> unusedColliders = new Dictionary<Collider, LinkedListNode<Collider>>();
|
||||
|
||||
#region MonoBehaviour
|
||||
private void Awake()
|
||||
{
|
||||
@@ -159,7 +165,6 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
/// </summary>
|
||||
private void FindCandidate()
|
||||
{
|
||||
currentCandidate = null;
|
||||
float distanceScore = float.MinValue;
|
||||
if (GetClosestGrabbable(m_GrabDistance, out HandGrabInteractable grabbable, out float score) && score > distanceScore)
|
||||
{
|
||||
@@ -189,28 +194,47 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
grabbable = null;
|
||||
maxScore = 0f;
|
||||
|
||||
Collider[] nearColliders = Physics.OverlapSphere(wristPose.position, 0.5f);
|
||||
List<HandGrabInteractable> nearHandGrabInteractables = new List<HandGrabInteractable>();
|
||||
for (int i = 0; i < nearColliders.Length; i++)
|
||||
for (int i = 0; i < lastBufferCount; i++)
|
||||
{
|
||||
HandGrabInteractable interactable = nearColliders[i].GetComponentInParent<HandGrabInteractable>();
|
||||
if (interactable && !nearHandGrabInteractables.Contains(interactable))
|
||||
{
|
||||
nearHandGrabInteractables.Add(interactable);
|
||||
continue;
|
||||
}
|
||||
interactable = nearColliders[i].GetComponentInChildren<HandGrabInteractable>();
|
||||
if (interactable && !nearHandGrabInteractables.Contains(interactable))
|
||||
{
|
||||
nearHandGrabInteractables.Add(interactable);
|
||||
continue;
|
||||
}
|
||||
HandGrabInteractable interactable = grabbableBuffer[i];
|
||||
interactable.ShowIndicator(false, this);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nearHandGrabInteractables.Count; i++)
|
||||
int colliderCount = Physics.OverlapSphereNonAlloc(wristPose.position, grabDistance * 5, colliderBuffer);
|
||||
int interactableCount = 0;
|
||||
for (int i = 0; i < colliderCount; i++)
|
||||
{
|
||||
HandGrabInteractable interactable = nearHandGrabInteractables[i];
|
||||
interactable.ShowIndicator(false, this);
|
||||
Collider collider = colliderBuffer[i];
|
||||
if (unusedColliders.TryGetValue(collider, out _)) { continue; }
|
||||
|
||||
HandGrabInteractable interactable = collider.GetComponentInParent<HandGrabInteractable>()
|
||||
?? collider.GetComponentInChildren<HandGrabInteractable>();
|
||||
if (interactable != null)
|
||||
{
|
||||
bool isUnique = true;
|
||||
for (int j = 0; j < interactableCount; j++)
|
||||
{
|
||||
if (grabbableBuffer[j] == interactable)
|
||||
{
|
||||
isUnique = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isUnique)
|
||||
{
|
||||
grabbableBuffer[interactableCount++] = interactable;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddUnusedColliders(collider);
|
||||
}
|
||||
}
|
||||
lastBufferCount = interactableCount;
|
||||
|
||||
for (int i = 0; i < interactableCount; i++)
|
||||
{
|
||||
HandGrabInteractable interactable = grabbableBuffer[i];
|
||||
for (int j = 0; j < fingerTipPosition.Length; j++)
|
||||
{
|
||||
float distanceScore = interactable.CalculateDistanceScore(fingerTipPosition[j], grabDistance);
|
||||
@@ -279,5 +303,18 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
}
|
||||
m_Grabbable.UpdatePositionAndRotation(wristPose);
|
||||
}
|
||||
|
||||
private void AddUnusedColliders(Collider collider)
|
||||
{
|
||||
if (lruList.Count >= kMaxCacheSize)
|
||||
{
|
||||
var oldest = lruList.First;
|
||||
unusedColliders.Remove(oldest.Value);
|
||||
lruList.RemoveFirst();
|
||||
}
|
||||
|
||||
var node = lruList.AddLast(collider);
|
||||
unusedColliders[collider] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
@@ -85,7 +84,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
private Quaternion lastRotation;
|
||||
private bool isInit = false;
|
||||
private bool isTracked = true;
|
||||
private List<Vector3> collisionDirections = new List<Vector3>();
|
||||
private const int k_MaxCollisionCount = 100;
|
||||
private readonly ContactPoint[] contactPointsBuffer = new ContactPoint[k_MaxCollisionCount];
|
||||
private readonly Vector3[] collisionsDirection = new Vector3[k_MaxCollisionCount];
|
||||
private readonly object collisionLock = new object();
|
||||
private int currentCollisionCount = 0;
|
||||
private bool isGrabbing = false;
|
||||
|
||||
#region MonoBehaviour
|
||||
@@ -163,7 +166,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
|
||||
if (isGrabbing)
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
rootJointRigidbody.linearVelocity = Vector3.zero;
|
||||
#else
|
||||
rootJointRigidbody.velocity = Vector3.zero;
|
||||
#endif
|
||||
rootJointRigidbody.angularVelocity = Vector3.zero;
|
||||
rootJoint.localPosition = lastRootPos;
|
||||
rootJoint.localRotation = lastRotation;
|
||||
@@ -175,7 +182,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
private IEnumerator WaitForInit()
|
||||
{
|
||||
@@ -232,33 +239,41 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
Vector3 vel = (lastRootPos - rootJoint.position) / Time.deltaTime;
|
||||
if (IsValidVelocity(vel))
|
||||
{
|
||||
if (collisionDirections.Count > 0)
|
||||
lock (collisionLock)
|
||||
{
|
||||
float minAngle = float.MaxValue;
|
||||
Vector3 closestDirection = Vector3.zero;
|
||||
foreach (Vector3 direction in collisionDirections.ToList())
|
||||
if (currentCollisionCount > 0)
|
||||
{
|
||||
float angle = Mathf.Abs(Vector3.Angle(direction, vel));
|
||||
if (angle < minAngle)
|
||||
{
|
||||
minAngle = angle;
|
||||
closestDirection = direction;
|
||||
}
|
||||
}
|
||||
collisionDirections.Clear();
|
||||
float minAngle = float.MaxValue;
|
||||
Vector3 closestDirection = Vector3.zero;
|
||||
|
||||
Vector3 adjustedDirection = closestDirection;
|
||||
if (Vector3.Dot(vel, closestDirection) > 0)
|
||||
{
|
||||
adjustedDirection *= -1f;
|
||||
}
|
||||
vel = Vector3.ProjectOnPlane(vel, adjustedDirection);
|
||||
if (vel.magnitude > 1)
|
||||
{
|
||||
vel.Normalize();
|
||||
for (int i = 0; i < currentCollisionCount; i++)
|
||||
{
|
||||
Vector3 direction = collisionsDirection[i];
|
||||
float angle = Mathf.Abs(Vector3.Angle(direction, vel));
|
||||
if (angle < minAngle)
|
||||
{
|
||||
minAngle = angle;
|
||||
closestDirection = direction;
|
||||
}
|
||||
}
|
||||
Vector3 adjustedDirection = closestDirection;
|
||||
if (Vector3.Dot(vel, closestDirection) > 0)
|
||||
{
|
||||
adjustedDirection *= -1f;
|
||||
}
|
||||
vel = Vector3.ProjectOnPlane(vel, adjustedDirection);
|
||||
if (vel.magnitude > 1)
|
||||
{
|
||||
vel.Normalize();
|
||||
}
|
||||
currentCollisionCount = 0;
|
||||
}
|
||||
}
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
rootJointRigidbody.linearVelocity = vel;
|
||||
#else
|
||||
rootJointRigidbody.velocity = vel;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +302,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
&& !float.IsInfinity(vector.x) && !float.IsInfinity(vector.y) && !float.IsInfinity(vector.z);
|
||||
}
|
||||
|
||||
#region Event CallBack
|
||||
#region Event CallBack
|
||||
|
||||
/// <summary>
|
||||
/// When tracking state changing, reset the pose and enable/disable collider.
|
||||
@@ -299,7 +314,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
{
|
||||
lastRootPos = Vector3.zero;
|
||||
lastRotation = Quaternion.identity;
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
rootJointRigidbody.linearVelocity = Vector3.zero;
|
||||
#else
|
||||
rootJointRigidbody.velocity = Vector3.zero;
|
||||
#endif
|
||||
rootJointRigidbody.angularVelocity = Vector3.zero;
|
||||
}
|
||||
foreach (JointCollider jointCollider in jointsCollider)
|
||||
@@ -355,17 +374,21 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
case JointCollider.CollisionState.Stay:
|
||||
if (collision.contactCount > 0 && (collision.rigidbody == null || collision.rigidbody.isKinematic))
|
||||
{
|
||||
ContactPoint[] contactPoints = new ContactPoint[collision.contactCount];
|
||||
collision.GetContacts(contactPoints);
|
||||
foreach (ContactPoint contactPoint in contactPoints)
|
||||
lock (collisionLock)
|
||||
{
|
||||
collisionDirections.Add(contactPoint.normal * -1f);
|
||||
currentCollisionCount = Mathf.Min(contactPointsBuffer.Length, collision.contactCount);
|
||||
collision.GetContacts(contactPointsBuffer);
|
||||
|
||||
for (int i = 0; i < currentCollisionCount; i++)
|
||||
{
|
||||
collisionsDirection[i] = contactPointsBuffer[i].normal * -1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,6 +635,8 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
}
|
||||
},
|
||||
};
|
||||
// palm, wrist, thumb, index, middle, ring, pinky
|
||||
private static readonly int[] fingerGroup = { 1, 1, 4, 5, 5, 5, 5 };
|
||||
|
||||
public bool valid = false;
|
||||
public bool isTracked = false;
|
||||
@@ -771,14 +773,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
group = 0;
|
||||
index = jointId;
|
||||
|
||||
// palm, wrist, thumb, index, middle, ring, pinky
|
||||
int[] fingerGroup = { 1, 1, 4, 5, 5, 5, 5 };
|
||||
while (index > fingerGroup[group])
|
||||
for (int i = 0; i < fingerGroup.Length; i++)
|
||||
{
|
||||
index -= fingerGroup[group];
|
||||
group += 1;
|
||||
if (index <= fingerGroup[i])
|
||||
{
|
||||
group = i;
|
||||
index -= 1; // Adjust to 0-based index
|
||||
return;
|
||||
}
|
||||
index -= fingerGroup[i];
|
||||
}
|
||||
index -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,32 +852,29 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
/// <param name="isLeft">True if the hand is left; otherwise, false.</param>
|
||||
private static void GetFingerData(FingerId id, ref FingerData finger, bool isLeft)
|
||||
{
|
||||
JointType[] jointTypes = { };
|
||||
switch (id)
|
||||
{
|
||||
case FingerId.Thumb: jointTypes = s_ThumbJoints; break;
|
||||
case FingerId.Index: jointTypes = s_IndexJoints; break;
|
||||
case FingerId.Middle: jointTypes = s_MiddleJoints; break;
|
||||
case FingerId.Ring: jointTypes = s_RingJoints; break;
|
||||
case FingerId.Pinky: jointTypes = s_PinkyJoints; break;
|
||||
default: return;
|
||||
}
|
||||
JointType[] jointTypes = GetJointTypes(id);
|
||||
if (jointTypes == null) return;
|
||||
|
||||
float deltaTime = Time.deltaTime;
|
||||
Vector3 parentVel = Vector3.zero;
|
||||
|
||||
for (int i = 0; i < jointTypes.Length; i++)
|
||||
{
|
||||
Vector3 parentVel = i == 0 ? Vector3.zero : finger.joints[i - 1].velocity;
|
||||
JointData lastJoint = finger.joints[i];
|
||||
GetJointData(jointTypes[i], ref finger.joints[i], isLeft);
|
||||
ref JointData joint = ref finger.joints[i];
|
||||
Vector3 lastPosition = joint.position;
|
||||
|
||||
DataWrapper.GetJointPose(jointTypes[i], ref joint.position, ref joint.rotation, isLeft);
|
||||
joint.velocity = (joint.position - lastPosition) / deltaTime;
|
||||
|
||||
//As the velocity of child node should not be lower than the parent node.
|
||||
//Add the current parent node's velocity multiplied by time to the last position of child node, obtaining the new simulated position.
|
||||
if (parentVel.magnitude > finger.joints[i].velocity.magnitude)
|
||||
if (parentVel.magnitude > joint.velocity.magnitude)
|
||||
{
|
||||
lastJoint.position += parentVel * Time.deltaTime;
|
||||
finger.joints[i] = lastJoint;
|
||||
joint.position += parentVel * deltaTime;
|
||||
}
|
||||
parentVel = joint.velocity;
|
||||
}
|
||||
|
||||
// Since the thumb does not have joint3, it is replaced by joint2.
|
||||
if (id == FingerId.Thumb)
|
||||
{
|
||||
finger.joints[(int)JointId.Tip] = finger.joint3;
|
||||
@@ -885,6 +886,19 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
}
|
||||
}
|
||||
|
||||
private static JointType[] GetJointTypes(FingerId id)
|
||||
{
|
||||
return id switch
|
||||
{
|
||||
FingerId.Thumb => s_ThumbJoints,
|
||||
FingerId.Index => s_IndexJoints,
|
||||
FingerId.Middle => s_MiddleJoints,
|
||||
FingerId.Ring => s_RingJoints,
|
||||
FingerId.Pinky => s_PinkyJoints,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the data for the left or right hand.
|
||||
/// </summary>
|
||||
@@ -1067,16 +1081,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
Vector3 thumbTip = thumbData.tip.position;
|
||||
Vector3 thumbJoint2 = thumbData.joint2.position;
|
||||
Vector3 thumbJoint1 = thumbData.joint1.position;
|
||||
Vector3[] fingerPos = { fingerData.tip.position,
|
||||
fingerData.joint3.position,
|
||||
fingerData.joint2.position};
|
||||
|
||||
float distance = float.PositiveInfinity;
|
||||
for (int i = 0; i < fingerPos.Length; i++)
|
||||
{
|
||||
distance = Mathf.Min(distance, CalculateShortestDistance(fingerPos[i], thumbTip, thumbJoint2));
|
||||
distance = Mathf.Min(distance, CalculateShortestDistance(fingerPos[i], thumbJoint2, thumbJoint1));
|
||||
}
|
||||
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.tip.position, thumbTip, thumbJoint2));
|
||||
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.tip.position, thumbJoint2, thumbJoint1));
|
||||
|
||||
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint3.position, thumbTip, thumbJoint2));
|
||||
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint3.position, thumbJoint2, thumbJoint1));
|
||||
|
||||
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint2.position, thumbTip, thumbJoint2));
|
||||
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint2.position, thumbJoint2, thumbJoint1));
|
||||
return distance;
|
||||
}
|
||||
|
||||
@@ -1732,9 +1746,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
/// <param name="enable">True to enable the indicator, false to deactivate it.</param>
|
||||
public void SetActive(bool enable)
|
||||
{
|
||||
if (target != null)
|
||||
if (target)
|
||||
{
|
||||
target.SetActive(enable);
|
||||
if (enable)
|
||||
{
|
||||
target.transform.localScale = Vector3.one;
|
||||
}
|
||||
else
|
||||
{
|
||||
target.transform.localScale = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
{
|
||||
[SerializeField]
|
||||
private HandMeshManager m_HandMesh;
|
||||
|
||||
|
||||
private bool keepUpdate = false;
|
||||
|
||||
protected override void OnEnable()
|
||||
@@ -18,11 +18,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
if (keepUpdate)
|
||||
{
|
||||
keepUpdate = false;
|
||||
StopCoroutine(UpdatePose());
|
||||
}
|
||||
keepUpdate = false;
|
||||
}
|
||||
|
||||
public void SetHandMeshRenderer(HandMeshManager handMeshRenderer)
|
||||
@@ -44,39 +40,32 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
{
|
||||
yield return new WaitUntil(() => m_Initialized);
|
||||
base.OnEnable();
|
||||
if (!keepUpdate)
|
||||
{
|
||||
keepUpdate = true;
|
||||
StartCoroutine(UpdatePose());
|
||||
}
|
||||
keepUpdate = true;
|
||||
}
|
||||
|
||||
private IEnumerator UpdatePose()
|
||||
private void Update()
|
||||
{
|
||||
while (keepUpdate)
|
||||
if (!keepUpdate) { return; }
|
||||
HandPose handPose = HandPoseProvider.GetHandPose(m_HandMesh.isLeft ? HandPoseType.HAND_LEFT : HandPoseType.HAND_RIGHT);
|
||||
m_IsTracked = handPose.IsTracked();
|
||||
if (!m_IsTracked) { return; }
|
||||
|
||||
for (int i = 0; i < poseCount; i++)
|
||||
{
|
||||
yield return new WaitForFixedUpdate();
|
||||
|
||||
HandPose handPose = HandPoseProvider.GetHandPose(m_HandMesh.isLeft ? HandPoseType.HAND_LEFT : HandPoseType.HAND_RIGHT);
|
||||
m_IsTracked = handPose.IsTracked();
|
||||
|
||||
for (int i = 0; i < poseCount; i++)
|
||||
if (m_HandMesh.GetJointPositionAndRotation((JointType)i, out Vector3 position, out Quaternion rotation) &&
|
||||
m_HandMesh.GetJointPositionAndRotation((JointType)i, out Vector3 localPosition, out Quaternion localRotation, local: true))
|
||||
{
|
||||
if (m_HandMesh.GetJointPositionAndRotation((JointType)i, out Vector3 position, out Quaternion rotation) &&
|
||||
m_HandMesh.GetJointPositionAndRotation((JointType)i, out Vector3 localPosition, out Quaternion localRotation, local: true))
|
||||
{
|
||||
m_Position[i] = position;
|
||||
m_Rotation[i] = rotation;
|
||||
m_LocalPosition[i] = localPosition;
|
||||
m_LocalRotation[i] = localRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Position[i] = Vector3.zero;
|
||||
m_Rotation[i] = Quaternion.identity;
|
||||
m_LocalPosition[i] = Vector3.zero;
|
||||
m_LocalRotation[i] = Quaternion.identity;
|
||||
}
|
||||
m_Position[i] = position;
|
||||
m_Rotation[i] = rotation;
|
||||
m_LocalPosition[i] = localPosition;
|
||||
m_LocalRotation[i] = localRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Position[i] = Vector3.zero;
|
||||
m_Rotation[i] = Quaternion.identity;
|
||||
m_LocalPosition[i] = Vector3.zero;
|
||||
m_LocalRotation[i] = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
if (keepUpdate)
|
||||
{
|
||||
keepUpdate = false;
|
||||
StopCoroutine(UpdatePose());
|
||||
}
|
||||
keepUpdate = false;
|
||||
}
|
||||
|
||||
public override void SetType(HandPoseType poseType)
|
||||
@@ -43,41 +39,33 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
{
|
||||
yield return new WaitUntil(() => m_Initialized);
|
||||
base.OnEnable();
|
||||
if (!keepUpdate)
|
||||
{
|
||||
keepUpdate = true;
|
||||
StartCoroutine(UpdatePose());
|
||||
}
|
||||
keepUpdate = true;
|
||||
}
|
||||
|
||||
private IEnumerator UpdatePose()
|
||||
private void Update()
|
||||
{
|
||||
if (!keepUpdate) { return; }
|
||||
HandData handData = CachedHand.Get(isLeft);
|
||||
m_IsTracked = handData.isTracked;
|
||||
if (!m_IsTracked) { return; }
|
||||
|
||||
Vector3 position = Vector3.zero;
|
||||
Quaternion rotation = Quaternion.identity;
|
||||
while (keepUpdate)
|
||||
for (int i = 0; i < poseCount; i++)
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
HandData handData = CachedHand.Get(isLeft);
|
||||
m_IsTracked = handData.isTracked;
|
||||
if (!m_IsTracked) { continue; }
|
||||
|
||||
for (int i = 0; i < poseCount; i++)
|
||||
if (handData.GetJointPosition((JointType)i, ref position) && handData.GetJointRotation((JointType)i, ref rotation))
|
||||
{
|
||||
if (handData.GetJointPosition((JointType)i, ref position) && handData.GetJointRotation((JointType)i, ref rotation))
|
||||
{
|
||||
m_Position[i] = transform.position + transform.rotation * position;
|
||||
m_Rotation[i] = transform.rotation * rotation;
|
||||
m_LocalPosition[i] = position;
|
||||
m_LocalRotation[i] = rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Position[i] = Vector3.zero;
|
||||
m_Rotation[i] = Quaternion.identity;
|
||||
m_LocalPosition[i] = Vector3.zero;
|
||||
m_LocalRotation[i] = Quaternion.identity;
|
||||
}
|
||||
m_Position[i] = transform.position + transform.rotation * position;
|
||||
m_Rotation[i] = transform.rotation * rotation;
|
||||
m_LocalPosition[i] = position;
|
||||
m_LocalRotation[i] = rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Position[i] = Vector3.zero;
|
||||
m_Rotation[i] = Quaternion.identity;
|
||||
m_LocalPosition[i] = Vector3.zero;
|
||||
m_LocalRotation[i] = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
@@ -9,13 +10,15 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
[SerializeField]
|
||||
private float forceMultiplier = 1.0f;
|
||||
|
||||
private readonly int MIN_POSE_SAMPLES = 2;
|
||||
private readonly int MAX_POSE_SAMPLES = 10;
|
||||
private const int MIN_POSE_SAMPLES = 2;
|
||||
private const int MAX_POSE_SAMPLES = 10;
|
||||
private readonly float MIN_VELOCITY = 0.5f;
|
||||
|
||||
private Rigidbody interactableRigidbody;
|
||||
private List<Pose> movementPoses = new List<Pose>();
|
||||
private List<float> timestamps = new List<float>();
|
||||
private Pose[] movementPoses = new Pose[MAX_POSE_SAMPLES];
|
||||
private float[] timestamps = new float[MAX_POSE_SAMPLES];
|
||||
private int currentPoseIndex = 0;
|
||||
private int poseCount = 0;
|
||||
private bool isBegin = false;
|
||||
private bool isEnd = false;
|
||||
private object lockVel = new object();
|
||||
@@ -36,7 +39,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
|
||||
if (isEnd)
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
interactableRigidbody.linearVelocity = Vector3.zero;
|
||||
#else
|
||||
interactableRigidbody.velocity = Vector3.zero;
|
||||
#endif
|
||||
interactableRigidbody.angularVelocity = Vector3.zero;
|
||||
|
||||
Vector3 velocity = CalculateVelocity();
|
||||
@@ -46,8 +53,10 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
}
|
||||
interactableRigidbody = null;
|
||||
|
||||
movementPoses.Clear();
|
||||
timestamps.Clear();
|
||||
Array.Clear(movementPoses, 0, MAX_POSE_SAMPLES);
|
||||
Array.Clear(timestamps, 0, MAX_POSE_SAMPLES);
|
||||
currentPoseIndex = 0;
|
||||
poseCount = 0;
|
||||
isEnd = false;
|
||||
}
|
||||
}
|
||||
@@ -55,28 +64,29 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
private void RecordMovement()
|
||||
{
|
||||
float time = Time.time;
|
||||
if (movementPoses.Count == 0 ||
|
||||
timestamps[movementPoses.Count - 1] != time)
|
||||
{
|
||||
movementPoses.Add(new Pose(interactableRigidbody.position, interactableRigidbody.rotation));
|
||||
timestamps.Add(time);
|
||||
}
|
||||
|
||||
if (movementPoses.Count > MAX_POSE_SAMPLES)
|
||||
int lastIndex = (currentPoseIndex + poseCount - 1) % MAX_POSE_SAMPLES;
|
||||
if (poseCount == 0 || timestamps[lastIndex] != time)
|
||||
{
|
||||
movementPoses.RemoveAt(0);
|
||||
timestamps.RemoveAt(0);
|
||||
movementPoses[currentPoseIndex] = new Pose(interactableRigidbody.position, interactableRigidbody.rotation);
|
||||
timestamps[currentPoseIndex] = time;
|
||||
|
||||
if (poseCount < MAX_POSE_SAMPLES)
|
||||
{
|
||||
poseCount++;
|
||||
}
|
||||
currentPoseIndex = (currentPoseIndex + 1) % MAX_POSE_SAMPLES;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 CalculateVelocity()
|
||||
{
|
||||
if (movementPoses.Count >= MIN_POSE_SAMPLES)
|
||||
if (poseCount >= MIN_POSE_SAMPLES)
|
||||
{
|
||||
List<Vector3> velocities = new List<Vector3>();
|
||||
for (int i = 0; i < movementPoses.Count - 1; i++)
|
||||
for (int i = 0; i < poseCount - 1; i++)
|
||||
{
|
||||
for (int j = i + 1; j < movementPoses.Count; j++)
|
||||
for (int j = i + 1; j < poseCount; j++)
|
||||
{
|
||||
velocities.Add(GetVelocity(i, j));
|
||||
}
|
||||
@@ -89,9 +99,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
|
||||
|
||||
private Vector3 GetVelocity(int idx1, int idx2)
|
||||
{
|
||||
if (idx1 < 0 || idx1 >= movementPoses.Count
|
||||
|| idx2 < 0 || idx2 >= movementPoses.Count
|
||||
|| movementPoses.Count < MIN_POSE_SAMPLES)
|
||||
if (idx1 < 0 || idx1 >= poseCount
|
||||
|| idx2 < 0 || idx2 >= poseCount
|
||||
|| poseCount < MIN_POSE_SAMPLES)
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user