Init
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
#if !PICO_OPENXR_SDK
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.XR.PXR;
|
||||
|
||||
public class PXR_Hand : MonoBehaviour
|
||||
{
|
||||
public HandType handType;
|
||||
public Transform Basemesh;
|
||||
[HideInInspector]
|
||||
public List<Transform> handJoints = new List<Transform>(new Transform[(int)HandJoint.JointMax]);
|
||||
|
||||
public bool Computed { get; private set; }
|
||||
public Posef RayPose { get; private set; }
|
||||
public bool RayValid { get; private set; }
|
||||
public bool Pinch { get; private set; }
|
||||
public float PinchStrength { get; private set; }
|
||||
|
||||
private HandJointLocations handJointLocations = new HandJointLocations();
|
||||
private HandAimState aimState = new HandAimState();
|
||||
[SerializeField]
|
||||
private Transform rayPose;
|
||||
[SerializeField]
|
||||
private GameObject defaultRay;
|
||||
private SkinnedMeshRenderer[] touchRenders;
|
||||
private bool isaAdaptiveScales = false;
|
||||
PXR_VstModelPosCheck mOffsetPos=null;
|
||||
private void Awake()
|
||||
{
|
||||
mOffsetPos= GetComponent<PXR_VstModelPosCheck>();
|
||||
}
|
||||
private void Start()
|
||||
{
|
||||
isaAdaptiveScales = PXR_ProjectSetting.GetProjectConfig().adaptiveHand;
|
||||
|
||||
if (defaultRay != null)
|
||||
{
|
||||
touchRenders = defaultRay.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void OnEnable() => Application.onBeforeRender += OnBeforeRender;
|
||||
|
||||
|
||||
protected void OnDisable() => Application.onBeforeRender -= OnBeforeRender;
|
||||
|
||||
private void OnBeforeRender()
|
||||
{
|
||||
UpdateHandJoints();
|
||||
UpdateAimState();
|
||||
UpdateRayPose();
|
||||
}
|
||||
|
||||
private void UpdateHandJoints()
|
||||
{
|
||||
if (PXR_HandTracking.GetJointLocations(handType, ref handJointLocations))
|
||||
{
|
||||
if (isaAdaptiveScales)
|
||||
{
|
||||
float scale = 0;
|
||||
PXR_HandTracking.GetHandScale(handType,ref scale);
|
||||
Basemesh.localScale = Vector3.one*scale;
|
||||
}
|
||||
|
||||
for (int i = 0; i < handJoints.Count; ++i)
|
||||
{
|
||||
if (handJoints[i] == null) continue;
|
||||
|
||||
if (i == (int)HandJoint.JointWrist)
|
||||
{
|
||||
handJoints[i].localPosition = handJointLocations.jointLocations[i].pose.Position.ToVector3();
|
||||
handJoints[i].localRotation = handJointLocations.jointLocations[i].pose.Orientation.ToQuat();
|
||||
}
|
||||
else
|
||||
{
|
||||
Pose parentPose = Pose.identity;
|
||||
|
||||
if (i == (int)HandJoint.JointPalm ||
|
||||
i == (int)HandJoint.JointThumbMetacarpal ||
|
||||
i == (int)HandJoint.JointIndexMetacarpal ||
|
||||
i == (int)HandJoint.JointMiddleMetacarpal ||
|
||||
i == (int)HandJoint.JointRingMetacarpal ||
|
||||
i == (int)HandJoint.JointLittleMetacarpal)
|
||||
{
|
||||
parentPose = new Pose(handJointLocations.jointLocations[1].pose.Position.ToVector3(), handJointLocations.jointLocations[1].pose.Orientation.ToQuat());
|
||||
}
|
||||
else
|
||||
{
|
||||
parentPose = new Pose(handJointLocations.jointLocations[i-1].pose.Position.ToVector3(), handJointLocations.jointLocations[i-1].pose.Orientation.ToQuat());
|
||||
}
|
||||
|
||||
var inverseParentRotation = Quaternion.Inverse(parentPose.rotation);
|
||||
handJoints[i].localRotation = inverseParentRotation * handJointLocations.jointLocations[i].pose.Orientation.ToQuat();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (mOffsetPos)
|
||||
{
|
||||
Basemesh.localPosition = handJointLocations.jointLocations[(int)Unity.XR.PXR.HandJoint.JointWrist].pose.Position.ToVector3()+ mOffsetPos.GetHandPosOffset();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAimState()
|
||||
{
|
||||
if (PXR_HandTracking.GetAimState(handType, ref aimState))
|
||||
{
|
||||
Computed = (aimState.aimStatus&HandAimStatus.AimComputed) != 0;
|
||||
|
||||
RayPose = aimState.aimRayPose;
|
||||
RayValid = (aimState.aimStatus&HandAimStatus.AimRayValid) != 0;
|
||||
Pinch = (aimState.aimStatus&HandAimStatus.AimRayTouched) != 0;
|
||||
PinchStrength = aimState.touchStrengthRay;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRayPose()
|
||||
{
|
||||
if (rayPose == null) return;
|
||||
|
||||
if (RayValid)
|
||||
{
|
||||
rayPose.gameObject.SetActive(true);
|
||||
rayPose.localPosition = RayPose.Position.ToVector3();
|
||||
rayPose.localRotation = RayPose.Orientation.ToQuat();
|
||||
|
||||
if (defaultRay != null)
|
||||
{
|
||||
foreach (var touchRender in touchRenders)
|
||||
{
|
||||
touchRender.SetBlendShapeWeight(0, aimState.touchStrengthRay*100);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rayPose.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f753f52cc8c63524f9ace6fcab377a5b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,570 @@
|
||||
#if !PICO_OPENXR_SDK
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using System;
|
||||
using UnityEngine.XR;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
public class PXR_HandPose : MonoBehaviour
|
||||
{
|
||||
public TrackType trackType;
|
||||
public PXR_HandPoseConfig config;
|
||||
public UnityEvent handPoseStart;
|
||||
public UpdateEvent handPoseUpdate;
|
||||
public UnityEvent handPoseEnd;
|
||||
|
||||
private List<Vector3> leftJointPos = new List<Vector3>(new Vector3[(int)HandJoint.JointMax]);
|
||||
private List<Vector3> rightJointPos = new List<Vector3>(new Vector3[(int)HandJoint.JointMax]);
|
||||
private HandJointLocations leftHandJointLocations = new HandJointLocations();
|
||||
private HandJointLocations rightHandJointLocations = new HandJointLocations();
|
||||
|
||||
private bool poseStateHold;
|
||||
private bool poseStateActive;
|
||||
private float poseStateHoldTime;
|
||||
|
||||
public enum TrackType
|
||||
{
|
||||
Any,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
private void HandPoseEventCheck()
|
||||
{
|
||||
switch (trackType)
|
||||
{
|
||||
case TrackType.Any:
|
||||
poseStateActive = (leftShapesActive && leftBonesActive && leftTransActive) || (rightShapesActive && rightBonesActive && rightTransActive);
|
||||
break;
|
||||
case TrackType.Left:
|
||||
poseStateActive = leftShapesActive && leftBonesActive && leftTransActive;
|
||||
break;
|
||||
case TrackType.Right:
|
||||
poseStateActive = rightShapesActive && rightBonesActive && rightTransActive;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (poseStateHold != poseStateActive)
|
||||
{
|
||||
poseStateHold = poseStateActive;
|
||||
if (poseStateHold)
|
||||
{
|
||||
poseStateActive = true;
|
||||
if (handPoseStart != null)
|
||||
{
|
||||
handPoseStart.Invoke();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
poseStateActive = false;
|
||||
if (handPoseStart != null)
|
||||
{
|
||||
handPoseEnd.Invoke();
|
||||
}
|
||||
}
|
||||
poseStateHoldTime = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (poseStateHold)
|
||||
{
|
||||
poseStateHoldTime += Time.deltaTime;
|
||||
handPoseUpdate.Invoke(poseStateHoldTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool HoldCheck(bool holdState, float holdDuration, bool resultState, ref float holdTime)
|
||||
{
|
||||
if (resultState != holdState)
|
||||
{
|
||||
holdTime += Time.deltaTime;
|
||||
if (holdTime >= holdDuration)
|
||||
{
|
||||
resultState = holdState;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
holdTime = 0;
|
||||
}
|
||||
return resultState;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
shapesHoldDuration = config.shapesRecognizer.holdDuration;
|
||||
|
||||
bones = config.bonesRecognizer.Bones;
|
||||
bonesHoldDuration = config.bonesRecognizer.holdDuration;
|
||||
|
||||
transTrackAxis = config.transRecognizer.trackAxis;
|
||||
transSpaceType = config.transRecognizer.spaceType;
|
||||
transTrackTarget = config.transRecognizer.trackTarget;
|
||||
transHoldDuration = config.transRecognizer.holdDuration;
|
||||
transAngleThreshold = config.transRecognizer.angleThreshold;
|
||||
transThresholdWidth = config.transRecognizer.thresholdWidth;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (config == null) return;
|
||||
|
||||
InputDevices.GetDeviceAtXRNode(XRNode.Head).TryGetFeatureValue(CommonUsages.devicePosition, out HMDpose);
|
||||
|
||||
if (trackType == TrackType.Right || trackType == TrackType.Any)
|
||||
{
|
||||
PXR_HandTracking.GetJointLocations(HandType.HandRight, ref rightHandJointLocations);
|
||||
|
||||
for (int i = 0; i < rightJointPos.Count; ++i)
|
||||
{
|
||||
if (rightHandJointLocations.jointLocations == null) break;
|
||||
|
||||
rightJointPos[i] = rightHandJointLocations.jointLocations[i].pose.Position.ToVector3();
|
||||
|
||||
if (i == (int)HandJoint.JointWrist)
|
||||
{
|
||||
rightWirstPos = rightHandJointLocations.jointLocations[i].pose.Position.ToVector3();
|
||||
rightWirstRot = rightHandJointLocations.jointLocations[i].pose.Orientation.ToQuat();
|
||||
}
|
||||
}
|
||||
rightShapesHold = ShapesRecognizerCheck(rightJointPos, rightWirstRot * Vector3.left, rightWirstRot * Vector3.back);
|
||||
rightShapesActive = HoldCheck(rightShapesHold, shapesHoldDuration, rightShapesActive, ref rightShapesHoldTime);
|
||||
|
||||
rightBonesHold = BonesCheck(HandType.HandRight);
|
||||
rightBonesActive = HoldCheck(rightBonesHold, bonesHoldDuration, rightBonesActive, ref rightBonesHoldTime);
|
||||
|
||||
rightTransHold = TransCheck(TrackType.Right, rightWirstPos, rightWirstRot, HMDpose, rightTransHold);
|
||||
rightTransActive = HoldCheck(rightTransHold, transHoldDuration, rightTransActive, ref rightTransHoldTime);
|
||||
}
|
||||
|
||||
if (trackType == TrackType.Left || trackType == TrackType.Any)
|
||||
{
|
||||
PXR_HandTracking.GetJointLocations(HandType.HandLeft, ref leftHandJointLocations);
|
||||
|
||||
for (int i = 0; i < leftJointPos.Count; ++i)
|
||||
{
|
||||
if (leftHandJointLocations.jointLocations == null) break;
|
||||
|
||||
leftJointPos[i] = leftHandJointLocations.jointLocations[i].pose.Position.ToVector3();
|
||||
|
||||
if (i == (int)HandJoint.JointWrist)
|
||||
{
|
||||
leftWirstPos = leftHandJointLocations.jointLocations[i].pose.Position.ToVector3();
|
||||
leftWirstRot = leftHandJointLocations.jointLocations[i].pose.Orientation.ToQuat();
|
||||
}
|
||||
}
|
||||
leftShapesHold = ShapesRecognizerCheck(leftJointPos, leftWirstRot * Vector3.right, leftWirstRot * Vector3.forward, -1);
|
||||
leftShapesActive = HoldCheck(leftShapesHold, shapesHoldDuration, leftShapesActive, ref leftShapesHoldTime);
|
||||
|
||||
leftBonesHold = BonesCheck(HandType.HandLeft);
|
||||
leftBonesActive = HoldCheck(leftBonesHold, bonesHoldDuration, leftBonesActive, ref leftBonesHoldTime);
|
||||
|
||||
leftTransHold = TransCheck(TrackType.Left, leftWirstPos, leftWirstRot, HMDpose, leftTransHold);
|
||||
leftTransActive = HoldCheck(leftTransHold, transHoldDuration, leftTransActive, ref leftTransHoldTime);
|
||||
}
|
||||
|
||||
HandPoseEventCheck();
|
||||
}
|
||||
|
||||
#region ShapesRecognizer
|
||||
private float shapesHoldDuration = 0.09f;
|
||||
|
||||
private bool leftShapesHold;
|
||||
private bool leftShapesActive;
|
||||
private float leftShapesHoldTime;
|
||||
|
||||
private bool rightShapesActive;
|
||||
private bool rightShapesHold;
|
||||
private float rightShapesHoldTime;
|
||||
|
||||
private bool angleCheckValid = false;
|
||||
private bool abducCheckOpen = false;
|
||||
|
||||
private Vector3 leftWirstPos;
|
||||
private Vector3 rightWirstPos;
|
||||
private Quaternion leftWirstRot;
|
||||
private Quaternion rightWirstRot;
|
||||
|
||||
private Vector3 thumb0, thumb1, thumb2, thumb3;
|
||||
private Vector3 index0, index1, index2, index3;
|
||||
private Vector3 middle0, middle1, middle2, middle3;
|
||||
private Vector3 ring0, ring1, ring2, ring3;
|
||||
private Vector3 pinky0, pinky1, pinky2, pinky3;
|
||||
|
||||
private bool thumbFlex, indexFlex, middleFlex, ringFlex, pinkyFlex;
|
||||
private bool thumbCurl, indexCurl, middleCurl, ringCurl, pinkyCurl;
|
||||
private bool thumbAbduc, indexAbduc, middleAbduc, ringAbduc, pinkyAbduc;
|
||||
|
||||
private bool ShapesRecognizerCheck(List<Vector3> jointPos, Vector3 wirstRight, Vector3 wirstForward, int wirstDirect = 1)
|
||||
{
|
||||
thumb0 = jointPos[(int)HandJoint.JointThumbTip];
|
||||
thumb1 = jointPos[(int)HandJoint.JointThumbDistal];
|
||||
thumb2 = jointPos[(int)HandJoint.JointThumbProximal];
|
||||
thumb3 = jointPos[(int)HandJoint.JointThumbMetacarpal];
|
||||
|
||||
index0 = jointPos[(int)HandJoint.JointIndexTip];
|
||||
index1 = jointPos[(int)HandJoint.JointIndexDistal];
|
||||
index2 = jointPos[(int)HandJoint.JointIndexIntermediate];
|
||||
index3 = jointPos[(int)HandJoint.JointIndexProximal];
|
||||
|
||||
middle0 = jointPos[(int)HandJoint.JointMiddleTip];
|
||||
middle1 = jointPos[(int)HandJoint.JointMiddleDistal];
|
||||
middle2 = jointPos[(int)HandJoint.JointMiddleIntermediate];
|
||||
middle3 = jointPos[(int)HandJoint.JointMiddleProximal];
|
||||
|
||||
ring0 = jointPos[(int)HandJoint.JointRingTip];
|
||||
ring1 = jointPos[(int)HandJoint.JointRingDistal];
|
||||
ring2 = jointPos[(int)HandJoint.JointRingIntermediate];
|
||||
ring3 = jointPos[(int)HandJoint.JointRingProximal];
|
||||
|
||||
pinky0 = jointPos[(int)HandJoint.JointLittleTip];
|
||||
pinky1 = jointPos[(int)HandJoint.JointLittleDistal];
|
||||
pinky2 = jointPos[(int)HandJoint.JointLittleIntermediate];
|
||||
pinky3 = jointPos[(int)HandJoint.JointLittleProximal];
|
||||
|
||||
thumbFlex = FlexionCheck(config.shapesRecognizer.thumb, wirstDirect * wirstRight, wirstDirect * wirstForward);
|
||||
indexFlex = FlexionCheck(config.shapesRecognizer.index, wirstRight, wirstForward);
|
||||
middleFlex = FlexionCheck(config.shapesRecognizer.middle, wirstRight, wirstForward);
|
||||
ringFlex = FlexionCheck(config.shapesRecognizer.ring, wirstRight, wirstForward);
|
||||
pinkyFlex = FlexionCheck(config.shapesRecognizer.pinky, wirstRight, wirstForward);
|
||||
|
||||
thumbCurl = CurlCheck(config.shapesRecognizer.thumb);
|
||||
indexCurl = CurlCheck(config.shapesRecognizer.index);
|
||||
middleCurl = CurlCheck(config.shapesRecognizer.middle);
|
||||
ringCurl = CurlCheck(config.shapesRecognizer.ring);
|
||||
pinkyCurl = CurlCheck(config.shapesRecognizer.pinky);
|
||||
|
||||
thumbAbduc = AbductionCheck(config.shapesRecognizer.thumb);
|
||||
indexAbduc = AbductionCheck(config.shapesRecognizer.index);
|
||||
middleAbduc = AbductionCheck(config.shapesRecognizer.middle);
|
||||
ringAbduc = AbductionCheck(config.shapesRecognizer.ring);
|
||||
pinkyAbduc = AbductionCheck(config.shapesRecognizer.pinky);
|
||||
|
||||
return thumbFlex && indexFlex && middleFlex && ringFlex && pinkyFlex
|
||||
&& thumbCurl && indexCurl && middleCurl && ringCurl && pinkyCurl
|
||||
&& thumbAbduc && indexAbduc && middleAbduc && ringAbduc && pinkyAbduc;
|
||||
}
|
||||
private bool FlexionCheck(ShapesRecognizer.Finger finger, Vector3 wirstRight, Vector3 wirstForward)
|
||||
{
|
||||
if (finger.flexion == ShapesRecognizer.Flexion.Any) return true;
|
||||
else
|
||||
{
|
||||
float flexAngle = 0;
|
||||
switch (finger.handFinger)
|
||||
{
|
||||
case HandFinger.Thumb:
|
||||
Vector3 thumb23 = (thumb2 - thumb3);
|
||||
Vector3 thumb23_project = Vector3.ProjectOnPlane(thumb23, wirstRight);
|
||||
flexAngle = Vector3.Angle(thumb23_project, wirstForward);
|
||||
break;
|
||||
case HandFinger.Index:
|
||||
Vector3 index23 = (index2 - index3);
|
||||
Vector3 index_project = Vector3.ProjectOnPlane(index23, wirstForward);
|
||||
flexAngle = Vector3.Angle(index_project, wirstRight);
|
||||
break;
|
||||
case HandFinger.Middle:
|
||||
Vector3 middle23 = (middle2 - middle3);
|
||||
Vector3 middle_project = Vector3.ProjectOnPlane(middle23, wirstForward);
|
||||
flexAngle = Vector3.Angle(middle_project, wirstRight);
|
||||
break;
|
||||
case HandFinger.Ring:
|
||||
Vector3 ring23 = (ring2 - ring3);
|
||||
Vector3 ring_project = Vector3.ProjectOnPlane(ring23, wirstForward);
|
||||
flexAngle = Vector3.Angle(ring_project, wirstRight);
|
||||
break;
|
||||
case HandFinger.Pinky:
|
||||
Vector3 pinky23 = (pinky2 - pinky3);
|
||||
Vector3 pinky_project = Vector3.ProjectOnPlane(pinky23, wirstForward);
|
||||
flexAngle = Vector3.Angle(pinky_project, wirstRight);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return AngleCheck(flexAngle, finger.fingerConfigs.flexionConfigs.min, finger.fingerConfigs.flexionConfigs.max, finger.fingerConfigs.flexionConfigs.width,
|
||||
ShapesRecognizer.flexionMin, ShapesRecognizer.flexionMax);
|
||||
}
|
||||
|
||||
}
|
||||
private bool CurlCheck(ShapesRecognizer.Finger finger)
|
||||
{
|
||||
if (finger.curl == ShapesRecognizer.Curl.Any) return true;
|
||||
else
|
||||
{
|
||||
float curlAngle = 0;
|
||||
switch (finger.handFinger)
|
||||
{
|
||||
case HandFinger.Thumb:
|
||||
Vector3 thumb01 = (thumb0 - thumb1);
|
||||
Vector3 thumb32 = (thumb3 - thumb2);
|
||||
curlAngle = Vector3.Angle(thumb01, thumb32);
|
||||
break;
|
||||
case HandFinger.Index:
|
||||
Vector3 index01 = (index0 - index1);
|
||||
Vector3 index32 = (index3 - index2);
|
||||
curlAngle = Vector3.Angle(index32, index01);
|
||||
break;
|
||||
case HandFinger.Middle:
|
||||
Vector3 middle01 = (middle0 - middle1);
|
||||
Vector3 middle32 = (middle3 - middle2);
|
||||
curlAngle = Vector3.Angle(middle32, middle01);
|
||||
break;
|
||||
case HandFinger.Ring:
|
||||
Vector3 ring01 = (ring0 - ring1);
|
||||
Vector3 ring32 = (ring3 - ring2);
|
||||
curlAngle = Vector3.Angle(ring32, ring01);
|
||||
break;
|
||||
case HandFinger.Pinky:
|
||||
Vector3 pinky01 = (pinky0 - pinky1);
|
||||
Vector3 pinky32 = (pinky3 - pinky2);
|
||||
curlAngle = Vector3.Angle(pinky32, pinky01);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return AngleCheck(curlAngle, finger.fingerConfigs.curlConfigs.min, finger.fingerConfigs.curlConfigs.max, finger.fingerConfigs.curlConfigs.width,
|
||||
ShapesRecognizer.curlMin, ShapesRecognizer.curlMax);
|
||||
}
|
||||
}
|
||||
private bool AbductionCheck(ShapesRecognizer.Finger finger)
|
||||
{
|
||||
if (finger.abduction == ShapesRecognizer.Abduction.Any) return true;
|
||||
else
|
||||
{
|
||||
float abducAngle = 0;
|
||||
Vector3 thumb12 = (thumb1 - thumb2);
|
||||
Vector3 index23 = (index2 - index3);
|
||||
Vector3 middle23 = (middle2 - middle3);
|
||||
Vector3 ring23 = (ring2 - ring3);
|
||||
Vector3 pinky23 = (pinky2 - pinky3);
|
||||
switch (finger.handFinger)
|
||||
{
|
||||
case HandFinger.Thumb:
|
||||
abducAngle = Vector3.Angle(thumb12, index23);
|
||||
break;
|
||||
case HandFinger.Index:
|
||||
abducAngle = Vector3.Angle(index23, middle23);
|
||||
break;
|
||||
case HandFinger.Middle:
|
||||
abducAngle = Vector3.Angle(middle23, ring23);
|
||||
break;
|
||||
case HandFinger.Ring:
|
||||
abducAngle = Vector3.Angle(ring23, pinky23);
|
||||
break;
|
||||
case HandFinger.Pinky:
|
||||
abducAngle = Vector3.Angle(pinky23, ring23);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
bool result = false;
|
||||
if (finger.abduction == ShapesRecognizer.Abduction.Open)
|
||||
{
|
||||
result = AbducCheck(abducAngle, finger.fingerConfigs.abductionConfigs.mid, finger.fingerConfigs.abductionConfigs.width); ;
|
||||
}
|
||||
else if (finger.abduction == ShapesRecognizer.Abduction.Close)
|
||||
{
|
||||
result = !AbducCheck(abducAngle, finger.fingerConfigs.abductionConfigs.mid, finger.fingerConfigs.abductionConfigs.width); ;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
private bool AngleCheck(float angle, float min, float max, float width, float rangeMin, float rangeMax)
|
||||
{
|
||||
if (angle > min && angle < max)
|
||||
{
|
||||
angleCheckValid = true;
|
||||
}
|
||||
if (min - rangeMin <= 1f)
|
||||
{
|
||||
angleCheckValid = angle < max;
|
||||
}
|
||||
else if (angle < (min - width))
|
||||
{
|
||||
angleCheckValid = false;
|
||||
}
|
||||
|
||||
if (rangeMax - max <= 1f)
|
||||
{
|
||||
angleCheckValid = angle > min;
|
||||
}
|
||||
else if ((angle > (max + width)))
|
||||
{
|
||||
angleCheckValid = false;
|
||||
}
|
||||
|
||||
return angleCheckValid;
|
||||
}
|
||||
private bool AbducCheck(float angle, float mid, float width)
|
||||
{
|
||||
if (angle > mid + width / 2)
|
||||
{
|
||||
abducCheckOpen = true;
|
||||
}
|
||||
if (angle < mid - width / 2)
|
||||
{
|
||||
abducCheckOpen = false;
|
||||
}
|
||||
return abducCheckOpen;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region BonesRecognizer
|
||||
private List<BonesRecognizer.BonesGroup> bones;
|
||||
private bool leftBonesHold;
|
||||
private bool leftBonesActive;
|
||||
private float leftBonesHoldTime;
|
||||
|
||||
private bool rightBonesHold;
|
||||
private bool rightBonesActive;
|
||||
private float rightBonesHoldTime;
|
||||
|
||||
private float bonesHoldDuration;
|
||||
private bool BonesCheck(HandType handType)
|
||||
{
|
||||
for (int i = 0; i < bones.Count; i++)
|
||||
{
|
||||
float distance = Vector3.Distance(GetHandJoint(handType, bones[i].bone1), GetHandJoint(handType, bones[i].bone2));
|
||||
if (distance < bones[i].distance - bones[i].thresholdWidth / 2)
|
||||
{
|
||||
bones[i].activeState = true;
|
||||
}
|
||||
else if (distance > bones[i].distance + bones[i].thresholdWidth / 2)
|
||||
{
|
||||
bones[i].activeState = false;
|
||||
}
|
||||
|
||||
if (!bones[i].activeState)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private Vector3 GetHandJoint(HandType hand, BonesRecognizer.HandBones bone)
|
||||
{
|
||||
if (hand == HandType.HandLeft)
|
||||
{
|
||||
return leftHandJointLocations.jointLocations[(int)bone].pose.Position.ToVector3();
|
||||
}
|
||||
else
|
||||
{
|
||||
return rightHandJointLocations.jointLocations[(int)bone].pose.Position.ToVector3();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region TransRecognizer
|
||||
private bool leftTransHold;
|
||||
private bool leftTransActive;
|
||||
private float leftTransHoldTime;
|
||||
|
||||
private bool rightTransHold;
|
||||
private bool rightTransActive;
|
||||
private float rightTransHoldTime;
|
||||
|
||||
private TransRecognizer.TrackAxis transTrackAxis;
|
||||
private TransRecognizer.SpaceType transSpaceType;
|
||||
private TransRecognizer.TrackTarget transTrackTarget;
|
||||
|
||||
private float transAngleThreshold;
|
||||
private float transThresholdWidth;
|
||||
private float transHoldDuration;
|
||||
|
||||
private Vector3 HMDpose;
|
||||
private Vector3 palmPos;
|
||||
private Vector3 palmAxis;
|
||||
private Vector3 targetPos;
|
||||
private bool TransCheck(TrackType trackType, Vector3 wristPos, Quaternion wristRot, Vector3 headPose, bool holdState)
|
||||
{
|
||||
GetTrackAxis(trackType, wristRot);
|
||||
GetProjectedTarget(headPose, wristRot, wristPos);
|
||||
|
||||
float errorAngle = Vector3.Angle(palmAxis, targetPos);
|
||||
|
||||
if (errorAngle < transAngleThreshold - transThresholdWidth / 2)
|
||||
{
|
||||
holdState = true;
|
||||
}
|
||||
if (errorAngle > transAngleThreshold + transThresholdWidth / 2)
|
||||
{
|
||||
holdState = false;
|
||||
}
|
||||
return holdState;
|
||||
}
|
||||
private Vector3 GetTrackAxis(TrackType trackType, Quaternion wristRot)
|
||||
{
|
||||
switch (transTrackAxis)
|
||||
{
|
||||
case TransRecognizer.TrackAxis.Fingers:
|
||||
palmAxis = wristRot * Vector3.forward;
|
||||
break;
|
||||
case TransRecognizer.TrackAxis.Palm:
|
||||
palmAxis = wristRot * Vector3.down;
|
||||
break;
|
||||
case TransRecognizer.TrackAxis.Thumb:
|
||||
palmAxis = trackType == TrackType.Right ? wristRot * Vector3.left : wristRot * Vector3.right;
|
||||
break;
|
||||
}
|
||||
|
||||
return palmAxis;
|
||||
}
|
||||
private Vector3 GetProjectedTarget(Vector3 headPose, Quaternion wristRot, Vector3 wristPos)
|
||||
{
|
||||
palmPos = wristRot * (trackType == TrackType.Right ? new Vector3(0.08f, 0, 0) : new Vector3(-0.08f, 0, 0)) + wristPos;
|
||||
switch (transTrackTarget)
|
||||
{
|
||||
case TransRecognizer.TrackTarget.TowardsFace:
|
||||
targetPos = headPose;
|
||||
break;
|
||||
case TransRecognizer.TrackTarget.AwayFromFace:
|
||||
targetPos = palmPos * 2 - headPose;
|
||||
break;
|
||||
case TransRecognizer.TrackTarget.WorldUp:
|
||||
targetPos = palmPos + Vector3.up;
|
||||
break;
|
||||
case TransRecognizer.TrackTarget.WorldDown:
|
||||
targetPos = palmPos + Vector3.down;
|
||||
break;
|
||||
}
|
||||
targetPos -= palmPos;
|
||||
switch (transSpaceType)
|
||||
{
|
||||
case TransRecognizer.SpaceType.WorldSpace:
|
||||
break;
|
||||
case TransRecognizer.SpaceType.LocalXY:
|
||||
targetPos = Vector3.ProjectOnPlane(targetPos, wristRot * Vector3.forward);
|
||||
break;
|
||||
case TransRecognizer.SpaceType.LocalXZ:
|
||||
targetPos = Vector3.ProjectOnPlane(targetPos, wristRot * Vector3.up);
|
||||
break;
|
||||
case TransRecognizer.SpaceType.LocalYZ:
|
||||
targetPos = Vector3.ProjectOnPlane(targetPos, wristRot * Vector3.right);
|
||||
break;
|
||||
}
|
||||
return targetPos;
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Serializable]
|
||||
public class UpdateEvent : UnityEvent<float> { }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35bed5e2884b6cb4a8f47d89e0bc7401
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,275 @@
|
||||
#if !PICO_OPENXR_SDK
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
[Serializable]
|
||||
public class PXR_HandPoseConfig : ScriptableObject
|
||||
{
|
||||
[DisplayOnly]
|
||||
public ShapesRecognizer shapesRecognizer;
|
||||
[DisplayOnly]
|
||||
public BonesRecognizer bonesRecognizer;
|
||||
[DisplayOnly]
|
||||
public TransRecognizer transRecognizer;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ShapesRecognizer
|
||||
{
|
||||
public Finger thumb = new Finger(HandFinger.Thumb);
|
||||
public Finger index = new Finger(HandFinger.Index);
|
||||
public Finger middle = new Finger(HandFinger.Middle);
|
||||
public Finger ring = new Finger(HandFinger.Ring);
|
||||
public Finger pinky = new Finger(HandFinger.Pinky);
|
||||
public float holdDuration = 0.09f;
|
||||
[Serializable]
|
||||
public class Finger
|
||||
{
|
||||
[HideInInspector]
|
||||
public HandFinger handFinger;
|
||||
public Flexion flexion;
|
||||
public Curl curl;
|
||||
public Abduction abduction;
|
||||
public FingerConfigs fingerConfigs;
|
||||
|
||||
public Finger(HandFinger finger)
|
||||
{
|
||||
handFinger = finger;
|
||||
flexion = Flexion.Any;
|
||||
curl = Curl.Any;
|
||||
abduction = Abduction.Any;
|
||||
fingerConfigs = new FingerConfigs(finger);
|
||||
}
|
||||
}
|
||||
[Serializable]
|
||||
public class FingerConfigs
|
||||
{
|
||||
public RangeConfigs flexionConfigs;
|
||||
public RangeConfigs curlConfigs;
|
||||
public RangeConfigsAbduction abductionConfigs;
|
||||
|
||||
public FingerConfigs(HandFinger finger)
|
||||
{
|
||||
flexionConfigs = new RangeConfigs(flexionMin, flexionMax, defaultFlexionWidth);
|
||||
if (finger == HandFinger.Thumb)
|
||||
{
|
||||
curlConfigs = new RangeConfigs(curlThumbMin, curlThumbMax, defaultCurlWidth);
|
||||
abductionConfigs = new RangeConfigsAbduction(abductionThumbMid, abductionThumbWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
curlConfigs = new RangeConfigs(curlMin, curlMax, defaultCurlWidth);
|
||||
abductionConfigs = new RangeConfigsAbduction(abductionMid, abductionWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ShapeType
|
||||
{
|
||||
flexion,
|
||||
curl,
|
||||
abduction
|
||||
}
|
||||
|
||||
public enum Flexion
|
||||
{
|
||||
Any,
|
||||
Open,
|
||||
Close,
|
||||
//Custom
|
||||
}
|
||||
|
||||
public enum Curl
|
||||
{
|
||||
Any,
|
||||
Open,
|
||||
Close,
|
||||
//Custom
|
||||
}
|
||||
|
||||
public enum Abduction
|
||||
{
|
||||
Any,
|
||||
Open,
|
||||
Close,
|
||||
}
|
||||
[Serializable]
|
||||
public class RangeConfigs
|
||||
{
|
||||
public float min;
|
||||
public float max;
|
||||
public float width;
|
||||
public RangeConfigs(float n, float m, float w)
|
||||
{
|
||||
min = n;
|
||||
max = m;
|
||||
width =w;
|
||||
}
|
||||
}
|
||||
[Serializable]
|
||||
public class RangeConfigsAbduction
|
||||
{
|
||||
public float mid;
|
||||
public float width;
|
||||
public RangeConfigsAbduction(float m, float w)
|
||||
{
|
||||
mid = m;
|
||||
width = w;
|
||||
}
|
||||
}
|
||||
|
||||
public const float defaultFlexionWidth = 10f;
|
||||
|
||||
public const float flexionThumbOpenMin = 155f;
|
||||
public const float flexionThumbOpenMax = 180f;
|
||||
public const float flexionThumbCloseMin = 90f;
|
||||
public const float flexionThumbCloseMax = 120f;
|
||||
|
||||
public const float flexionOpenMin = 144f;
|
||||
public const float flexionOpenMax = 180f;
|
||||
public const float flexionCloseMin = 90f;
|
||||
public const float flexionCloseMax = 126f;
|
||||
public const float flexionMin = 90f;
|
||||
public const float flexionMax = 180f;
|
||||
|
||||
public const float defaultCurlWidth = 20f;
|
||||
|
||||
public const float curlThumbOpenMin = 90f;
|
||||
public const float curlThumbOpenMax = 180f;
|
||||
public const float curlThumbCloseMin = 45f;
|
||||
public const float curlThumbCloseMax = 90f;
|
||||
public const float curlThumbMin = 45f;
|
||||
public const float curlThumbMax = 180f;
|
||||
|
||||
public const float curlOpenMin = 107f;
|
||||
public const float curlOpenMax = 180f;
|
||||
public const float curlCloseMin = 0f;
|
||||
public const float curlCloseMax = 73f;
|
||||
public const float curlMin = 0f;
|
||||
public const float curlMax = 180f;
|
||||
|
||||
public const float abductionThumbMid = 13f;
|
||||
public const float abductionThumbWidth = 6f;
|
||||
|
||||
public const float abductionMid = 10f;
|
||||
public const float abductionWidth = 6f;
|
||||
public const float abductionMin = 0f;
|
||||
public const float abductionMax = 90f;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class BonesRecognizer
|
||||
{
|
||||
public List<BonesGroup> Bones = new List<BonesGroup>();
|
||||
|
||||
public float holdDuration = 0.022f;
|
||||
[Serializable]
|
||||
public class BonesGroup
|
||||
{
|
||||
[LabelAttribute("Joint 1")]
|
||||
public HandBones bone1 = HandBones.Wrist;
|
||||
[LabelAttribute("Joint 2")]
|
||||
public HandBones bone2 = HandBones.Wrist;
|
||||
public float distance = 0.025f;
|
||||
[LabelAttribute("Margin")]
|
||||
public float thresholdWidth = 0.003f;
|
||||
|
||||
[HideInInspector]
|
||||
public bool activeState;
|
||||
}
|
||||
public enum HandBones
|
||||
{
|
||||
Palm = 0,
|
||||
Wrist = 1,
|
||||
|
||||
Thumb_Metacarpal = 2,
|
||||
Thumb_Proximal = 3,
|
||||
Thumb_Distal = 4,
|
||||
Thumb_Tip = 5,
|
||||
|
||||
Index_Metacarpal = 6,
|
||||
Index_Proximal = 7,
|
||||
Index_Intermediate = 8,
|
||||
Index_Distal = 9,
|
||||
Index_Tip = 10,
|
||||
|
||||
Middle_Metacarpal = 11,
|
||||
Middle_Proximal = 12,
|
||||
Middle_Intermediate = 13,
|
||||
Middle_Distal = 14,
|
||||
Middle_Tip = 15,
|
||||
|
||||
Ring_Metacarpal = 16,
|
||||
Ring_Proximal = 17,
|
||||
Ring_Intermediate = 18,
|
||||
Ring_Distal = 19,
|
||||
Ring_Tip = 20,
|
||||
|
||||
Little_Metacarpal = 21,
|
||||
Little_Proximal = 22,
|
||||
Little_Intermediate = 23,
|
||||
Little_Distal = 24,
|
||||
Little_Tip = 25
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class TransRecognizer
|
||||
{
|
||||
public TrackAxis trackAxis;
|
||||
public SpaceType spaceType;
|
||||
public TrackTarget trackTarget;
|
||||
|
||||
public enum SpaceType
|
||||
{
|
||||
WorldSpace,
|
||||
LocalXY,
|
||||
LocalYZ,
|
||||
LocalXZ
|
||||
}
|
||||
|
||||
public enum TrackAxis
|
||||
{
|
||||
Fingers, Palm, Thumb
|
||||
}
|
||||
|
||||
public enum TrackTarget
|
||||
{
|
||||
TowardsFace,
|
||||
AwayFromFace,
|
||||
WorldUp,
|
||||
WorldDown,
|
||||
}
|
||||
|
||||
public float angleThreshold = 35f;
|
||||
public float thresholdWidth = 10f;
|
||||
public float holdDuration = 0.022f;
|
||||
}
|
||||
|
||||
public class DisplayOnly : PropertyAttribute { }
|
||||
public class LabelAttribute : PropertyAttribute
|
||||
{
|
||||
public string name;
|
||||
public LabelAttribute(string name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fea894361bde054fbfc4de741aa3483
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
#if !PICO_OPENXR_SDK
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
public class PXR_HandPoseGenerator : MonoBehaviour
|
||||
{
|
||||
|
||||
public PXR_HandPoseConfig config;
|
||||
public PXR_HandPosePreview preview;
|
||||
|
||||
//Shapes
|
||||
public ShapesRecognizer.Finger thumb = new ShapesRecognizer.Finger(HandFinger.Thumb);
|
||||
public ShapesRecognizer.Finger index = new ShapesRecognizer.Finger(HandFinger.Index);
|
||||
public ShapesRecognizer.Finger middle = new ShapesRecognizer.Finger(HandFinger.Middle);
|
||||
public ShapesRecognizer.Finger ring = new ShapesRecognizer.Finger(HandFinger.Ring);
|
||||
public ShapesRecognizer.Finger pinky = new ShapesRecognizer.Finger(HandFinger.Pinky);
|
||||
|
||||
public float shapesholdDuration = 0.09f;
|
||||
|
||||
//Bones
|
||||
public List<BonesRecognizer.BonesGroup> Bones = new List<BonesRecognizer.BonesGroup>();
|
||||
|
||||
public float bonesHoldDuration = 0.022f;
|
||||
|
||||
//Trans
|
||||
public TransRecognizer.TrackAxis trackAxis;
|
||||
public TransRecognizer.SpaceType spaceType;
|
||||
public TransRecognizer.TrackTarget trackTarget;
|
||||
|
||||
public float angleThreshold = 35f;
|
||||
public float thresholdWidth = 10f;
|
||||
public float transHoldDuration = 0.022f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cbe7cced81af1f46a0aef054af159be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,363 @@
|
||||
#if !PICO_OPENXR_SDK
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.XR.PXR;
|
||||
using System;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class PXR_HandPosePreview : MonoBehaviour
|
||||
{
|
||||
[HideInInspector]public List<Transform> handJoints = new List<Transform>(new Transform[(int)HandJoint.JointMax]);
|
||||
[HideInInspector] public Vector3[] jointAngles = new Vector3[(int)HandJoint.JointMax];
|
||||
[HideInInspector] public Transform posePreviewX;
|
||||
[HideInInspector] public Transform posePreviewY;
|
||||
[HideInInspector] public Transform handModel;
|
||||
[HideInInspector] public SkinnedMeshRenderer handAxis;
|
||||
[HideInInspector] public Transform headModel;
|
||||
[HideInInspector] public Transform handShadow;
|
||||
|
||||
[HideInInspector] public ModelFinger modelThumb = new ModelFinger(ModelFinger.FingerType.thumb);
|
||||
[HideInInspector] public ModelFinger modelIndex = new ModelFinger(ModelFinger.FingerType.index);
|
||||
[HideInInspector] public ModelFinger modelMiddle = new ModelFinger(ModelFinger.FingerType.middle);
|
||||
[HideInInspector] public ModelFinger modelRing = new ModelFinger(ModelFinger.FingerType.ring);
|
||||
[HideInInspector] public ModelFinger modelLittle = new ModelFinger(ModelFinger.FingerType.little);
|
||||
|
||||
[HideInInspector] public Material openMaterial;
|
||||
[HideInInspector] public Material anyMaterial;
|
||||
[HideInInspector] public Material openFadeMaterial;
|
||||
[HideInInspector] public Material anyFadeMaterial;
|
||||
[HideInInspector] public Material highLightMaterial;
|
||||
|
||||
private Vector4 highLightBlendPower;
|
||||
private int blendPower = Shader.PropertyToID("_BlendPower");
|
||||
|
||||
public void UpdateShapeState(ShapesRecognizer shapesConfig)
|
||||
{
|
||||
var thumb = shapesConfig.thumb;
|
||||
var index = shapesConfig.index;
|
||||
var middle = shapesConfig.middle;
|
||||
var ring = shapesConfig.ring;
|
||||
var little = shapesConfig.pinky;
|
||||
|
||||
int joint = 0;
|
||||
Vector3 angle = Vector3.zero;
|
||||
//thumb
|
||||
joint = (int)HandJoint.JointThumbProximal;
|
||||
angle =
|
||||
thumb.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(52f, -37, -8) :
|
||||
thumb.abduction == ShapesRecognizer.Abduction.Close ? new Vector3(58f, 16, 1) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointThumbDistal;
|
||||
angle =
|
||||
thumb.curl == ShapesRecognizer.Curl.Close ? new Vector3(36, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
modelThumb.HighlightModelJoints(this,thumb.flexion, thumb.curl);
|
||||
|
||||
//index
|
||||
joint = (int)HandJoint.JointIndexProximal;
|
||||
angle =
|
||||
index.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(jointAngles[joint].x + 68, jointAngles[joint].y, jointAngles[joint].z) :
|
||||
index.abduction == ShapesRecognizer.Abduction.Close ? new Vector3(jointAngles[joint].x, 18, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointIndexIntermediate;
|
||||
angle = index.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 60, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointIndexDistal;
|
||||
angle = index.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 65, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
modelIndex.HighlightModelJoints(this, index.flexion, index.curl);
|
||||
|
||||
//middle
|
||||
joint = (int)HandJoint.JointMiddleProximal;
|
||||
angle =
|
||||
middle.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(jointAngles[joint].x + 68, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointMiddleIntermediate;
|
||||
angle = middle.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 60, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointMiddleDistal;
|
||||
angle = middle.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 65, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
modelMiddle.HighlightModelJoints(this, middle.flexion, middle.curl);
|
||||
|
||||
//ring
|
||||
joint = (int)HandJoint.JointRingProximal;
|
||||
angle =
|
||||
ring.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(jointAngles[joint].x + 68, jointAngles[joint].y, jointAngles[joint].z) :
|
||||
middle.abduction == ShapesRecognizer.Abduction.Close ? new Vector3(jointAngles[joint].x, -18, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointRingIntermediate;
|
||||
angle = ring.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 60, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointRingDistal;
|
||||
angle = ring.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 65, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
modelRing.HighlightModelJoints(this, ring.flexion, ring.curl);
|
||||
|
||||
//little
|
||||
joint = (int)HandJoint.JointLittleProximal;
|
||||
angle =
|
||||
little.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(jointAngles[joint].x + 68, jointAngles[joint].y, jointAngles[joint].z) :
|
||||
ring.abduction == ShapesRecognizer.Abduction.Close ? new Vector3(jointAngles[joint].x, -18, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointLittleIntermediate;
|
||||
angle = little.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 60, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
joint = (int)HandJoint.JointLittleDistal;
|
||||
angle = little.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 65, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
|
||||
handJoints[joint].localEulerAngles = angle;
|
||||
|
||||
modelLittle.HighlightModelJoints(this, little.flexion, little.curl);
|
||||
|
||||
//abduction highlight
|
||||
highLightBlendPower.w = thumb.abduction == ShapesRecognizer.Abduction.Any ? 0 : 1;
|
||||
highLightBlendPower.x = index.abduction == ShapesRecognizer.Abduction.Any ? 0 : 1;
|
||||
highLightBlendPower.y = middle.abduction == ShapesRecognizer.Abduction.Any ? 0 : 1;
|
||||
highLightBlendPower.z = ring.abduction == ShapesRecognizer.Abduction.Any ? 0 : 1;
|
||||
|
||||
highLightMaterial.SetVector(blendPower, highLightBlendPower);
|
||||
}
|
||||
|
||||
public void ResetShapeState()
|
||||
{
|
||||
for (int i = 0; i < handJoints.Count; i++)
|
||||
{
|
||||
handJoints[i].localEulerAngles = jointAngles[i];
|
||||
}
|
||||
|
||||
modelThumb.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
|
||||
modelIndex.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
|
||||
modelMiddle.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
|
||||
modelRing.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
|
||||
modelLittle.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
|
||||
|
||||
highLightMaterial.SetVector(blendPower, Vector4.zero);
|
||||
}
|
||||
|
||||
public void ResetTransformState()
|
||||
{
|
||||
headModel.gameObject.SetActive(false);
|
||||
handAxis.gameObject.SetActive(false);
|
||||
handModel.localEulerAngles = new Vector3(-90, 180, 0);
|
||||
}
|
||||
|
||||
public void UpdateTransformState(TransRecognizer transRecognizer)
|
||||
{
|
||||
handAxis.gameObject.SetActive(true);
|
||||
|
||||
switch (transRecognizer.trackAxis)
|
||||
{
|
||||
case TransRecognizer.TrackAxis.Fingers:
|
||||
handAxis.SetBlendShapeWeight(0, 100);
|
||||
handAxis.SetBlendShapeWeight(1, 0);
|
||||
handAxis.SetBlendShapeWeight(2, 0);
|
||||
break;
|
||||
case TransRecognizer.TrackAxis.Palm:
|
||||
handAxis.SetBlendShapeWeight(0, 0);
|
||||
handAxis.SetBlendShapeWeight(1, 0);
|
||||
handAxis.SetBlendShapeWeight(2, 100);
|
||||
break;
|
||||
case TransRecognizer.TrackAxis.Thumb:
|
||||
handAxis.SetBlendShapeWeight(0, 0);
|
||||
handAxis.SetBlendShapeWeight(1, 100);
|
||||
handAxis.SetBlendShapeWeight(2, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (transRecognizer.trackTarget)
|
||||
{
|
||||
case TransRecognizer.TrackTarget.TowardsFace:
|
||||
headModel.gameObject.SetActive(true);
|
||||
headModel.localPosition = new Vector3(0, 0.05f, -0.24f);
|
||||
headModel.localEulerAngles = Vector3.zero;
|
||||
|
||||
handModel.localEulerAngles =
|
||||
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Fingers ? new Vector3(0, 180, 0) :
|
||||
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Palm ? new Vector3(-90, 180, 0) : new Vector3(-90, 0, -90);
|
||||
break;
|
||||
case TransRecognizer.TrackTarget.AwayFromFace:
|
||||
headModel.gameObject.SetActive(true);
|
||||
headModel.localPosition = new Vector3(0, 0.05f, 0.24f);
|
||||
headModel.localEulerAngles = new Vector3(0, 180, 0);
|
||||
|
||||
handModel.localEulerAngles =
|
||||
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Fingers ? new Vector3(0, 180, 0) :
|
||||
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Palm ? new Vector3(-90, 180, 0) : new Vector3(-90, 0, -90);
|
||||
break;
|
||||
case TransRecognizer.TrackTarget.WorldUp:
|
||||
headModel.gameObject.SetActive(false);
|
||||
|
||||
handModel.localEulerAngles =
|
||||
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Fingers ? new Vector3(-90, 0, 0) :
|
||||
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Palm ? new Vector3(0, 0, 180) : new Vector3(0, 0, -90);
|
||||
break;
|
||||
case TransRecognizer.TrackTarget.WorldDown:
|
||||
headModel.gameObject.SetActive(false);
|
||||
|
||||
handModel.localEulerAngles =
|
||||
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Fingers ? new Vector3(90, 0, 0) :
|
||||
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Palm ? Vector3.zero : new Vector3(0, 0, 90);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (handModel.localEulerAngles.x == 0)
|
||||
{
|
||||
handShadow.GetChild(0).gameObject.SetActive(false);
|
||||
handShadow.GetChild(1).gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
handShadow.GetChild(0).gameObject.SetActive(true);
|
||||
handShadow.GetChild(1).gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ModelFinger
|
||||
{
|
||||
public FingerType Type;
|
||||
|
||||
public List<Transform> flexionTransforms = new List<Transform>();
|
||||
public List<MeshRenderer> flexionMeshRenderers = new List<MeshRenderer>();
|
||||
|
||||
public List<Transform> curlTransforms = new List<Transform>();
|
||||
public List<MeshRenderer> curlMeshRenderers = new List<MeshRenderer>();
|
||||
|
||||
public enum ModelJoint
|
||||
{
|
||||
metacarpal = 0,
|
||||
proximal = 1,
|
||||
intermediate = 2,
|
||||
distal = 3,
|
||||
tip = 4
|
||||
}
|
||||
public enum FingerType
|
||||
{
|
||||
thumb,
|
||||
index,
|
||||
middle,
|
||||
ring,
|
||||
little
|
||||
}
|
||||
|
||||
public ModelFinger(FingerType type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public void RefreshModelJoints(Transform transform)
|
||||
{
|
||||
if (flexionTransforms.Count == 0 || curlTransforms.Count == 0)
|
||||
{
|
||||
flexionTransforms.Clear();
|
||||
curlTransforms.Clear();
|
||||
|
||||
flexionMeshRenderers.Clear();
|
||||
curlMeshRenderers.Clear();
|
||||
|
||||
var baseTransform = transform.GetChild(1);
|
||||
for (int i = 0; i < baseTransform.childCount; i++)
|
||||
{
|
||||
if (baseTransform.GetChild(i).name.EndsWith($"{Type}_{ModelJoint.metacarpal}"))
|
||||
{
|
||||
baseTransform = baseTransform.GetChild(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
flexionTransforms.Add(GetModelJoint(baseTransform, ModelJoint.proximal));
|
||||
|
||||
curlTransforms.Add(GetModelJoint(baseTransform, ModelJoint.intermediate));
|
||||
|
||||
if (Type != FingerType.thumb)
|
||||
{
|
||||
curlTransforms.Add(GetModelJoint(baseTransform, ModelJoint.distal));
|
||||
}
|
||||
|
||||
foreach (var flexionTransform in flexionTransforms)
|
||||
{
|
||||
flexionMeshRenderers.Add(flexionTransform.Find("Bone").GetComponent<MeshRenderer>());
|
||||
flexionMeshRenderers.Add(flexionTransform.Find("Pointer").GetComponent<MeshRenderer>());
|
||||
flexionMeshRenderers.Add(flexionTransform.parent.Find("Bone").GetComponent<MeshRenderer>());
|
||||
}
|
||||
|
||||
foreach (var curlTransform in curlTransforms)
|
||||
{
|
||||
var mesh = curlTransform.Find("Bone").GetComponent<MeshRenderer>();
|
||||
if (!curlMeshRenderers.Contains(mesh)) curlMeshRenderers.Add(mesh);
|
||||
|
||||
mesh = curlTransform.Find("Pointer").GetComponent<MeshRenderer>();
|
||||
if (!curlMeshRenderers.Contains(mesh)) curlMeshRenderers.Add(mesh);
|
||||
|
||||
mesh = curlTransform.parent.Find("Bone").GetComponent<MeshRenderer>();
|
||||
if (!curlMeshRenderers.Contains(mesh)) curlMeshRenderers.Add(mesh);
|
||||
}
|
||||
|
||||
if (Type != FingerType.thumb)
|
||||
{
|
||||
var m = GetModelJoint(baseTransform, ModelJoint.tip).Find("Pointer")
|
||||
.GetComponent<MeshRenderer>();
|
||||
if (!curlMeshRenderers.Contains(m)) curlMeshRenderers.Add(m);
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = GetModelJoint(baseTransform, ModelJoint.distal).Find("Pointer")
|
||||
.GetComponent<MeshRenderer>();
|
||||
if (!curlMeshRenderers.Contains(m)) curlMeshRenderers.Add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HighlightModelJoints(PXR_HandPosePreview handPosePreview, ShapesRecognizer.Flexion flexion, ShapesRecognizer.Curl curl)
|
||||
{
|
||||
foreach (var mesh in flexionMeshRenderers)
|
||||
{
|
||||
mesh.material = flexion != ShapesRecognizer.Flexion.Any ? handPosePreview.openMaterial : handPosePreview.anyMaterial;
|
||||
}
|
||||
foreach (var mesh in curlMeshRenderers)
|
||||
{
|
||||
mesh.material = curl != ShapesRecognizer.Curl.Any ? handPosePreview.openMaterial : handPosePreview.anyMaterial;
|
||||
}
|
||||
flexionMeshRenderers[2].material = flexion != ShapesRecognizer.Flexion.Any ? handPosePreview.openFadeMaterial : handPosePreview.anyFadeMaterial;
|
||||
}
|
||||
|
||||
private Transform GetModelJoint(Transform tran, ModelJoint type)
|
||||
{
|
||||
for (int i = 0; i < (int)type; i++)
|
||||
{
|
||||
tran = tran.GetChild(2);
|
||||
}
|
||||
return tran;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea4ea412f6917124397eeba0f097ec6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,622 @@
|
||||
#if !PICO_OPENXR_SDK
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Scripting;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine.XR.Management;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.XR;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.XR;
|
||||
|
||||
|
||||
#if XR_HANDS
|
||||
using UnityEngine.XR.Hands;
|
||||
using UnityEngine.XR.Hands.ProviderImplementation;
|
||||
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
[Preserve]
|
||||
/// <summary>
|
||||
/// Implement Unity XRHandSubSystem
|
||||
/// Reference: https://docs.unity3d.com/Packages/com.unity.xr.hands@1.1/manual/implement-a-provider.html
|
||||
/// </summary>
|
||||
public class PXR_HandSubSystem : XRHandSubsystem
|
||||
{
|
||||
XRHandProviderUtility.SubsystemUpdater m_Updater;
|
||||
|
||||
// This method registers the subsystem descriptor with the SubsystemManager
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
static void RegisterDescriptor()
|
||||
{
|
||||
var handsSubsystemCinfo = new XRHandSubsystemDescriptor.Cinfo
|
||||
{
|
||||
id = "PICO Hands",
|
||||
providerType = typeof(PXRHandSubsystemProvider),
|
||||
subsystemTypeOverride = typeof(PXR_HandSubSystem)
|
||||
};
|
||||
XRHandSubsystemDescriptor.Register(handsSubsystemCinfo);
|
||||
}
|
||||
|
||||
protected override void OnCreate()
|
||||
{
|
||||
base.OnCreate();
|
||||
m_Updater = new XRHandProviderUtility.SubsystemUpdater(this);
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
Debug.Log("PXR_HandSubSystem Start");
|
||||
m_Updater.Start();
|
||||
base.OnStart();
|
||||
}
|
||||
|
||||
protected override void OnStop()
|
||||
{
|
||||
m_Updater.Stop();
|
||||
base.OnStop();
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
m_Updater.Destroy();
|
||||
m_Updater = null;
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
class PXRHandSubsystemProvider : XRHandSubsystemProvider
|
||||
{
|
||||
|
||||
HandJointLocations jointLocations = new HandJointLocations();
|
||||
readonly HandLocationStatus AllStatus = HandLocationStatus.PositionTracked | HandLocationStatus.PositionValid |
|
||||
HandLocationStatus.OrientationTracked | HandLocationStatus.OrientationValid;
|
||||
|
||||
bool isValid = false;
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
CreateHands();
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
DestroyHands();
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mapping the PICO Joint Index To Unity Joint Index
|
||||
/// </summary>
|
||||
static int[] pxrJointIndexToUnityJointIndexMapping;
|
||||
|
||||
static void Initialize()
|
||||
{
|
||||
if (pxrJointIndexToUnityJointIndexMapping == null)
|
||||
{
|
||||
pxrJointIndexToUnityJointIndexMapping = new int[(int)HandJoint.JointMax];
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointPalm] = XRHandJointID.Palm.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointWrist] = XRHandJointID.Wrist.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbMetacarpal] = XRHandJointID.ThumbMetacarpal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbProximal] = XRHandJointID.ThumbProximal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbDistal] = XRHandJointID.ThumbDistal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbTip] = XRHandJointID.ThumbTip.ToIndex();
|
||||
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexMetacarpal] = XRHandJointID.IndexMetacarpal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexProximal] = XRHandJointID.IndexProximal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexIntermediate] = XRHandJointID.IndexIntermediate.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexDistal] = XRHandJointID.IndexDistal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexTip] = XRHandJointID.IndexTip.ToIndex();
|
||||
|
||||
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleMetacarpal] = XRHandJointID.MiddleMetacarpal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleProximal] = XRHandJointID.MiddleProximal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleIntermediate] = XRHandJointID.MiddleIntermediate.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleDistal] = XRHandJointID.MiddleDistal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleTip] = XRHandJointID.MiddleTip.ToIndex();
|
||||
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingMetacarpal] = XRHandJointID.RingMetacarpal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingProximal] = XRHandJointID.RingProximal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingIntermediate] = XRHandJointID.RingIntermediate.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingDistal] = XRHandJointID.RingDistal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingTip] = XRHandJointID.RingTip.ToIndex();
|
||||
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleMetacarpal] = XRHandJointID.LittleMetacarpal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleProximal] = XRHandJointID.LittleProximal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleIntermediate] = XRHandJointID.LittleIntermediate.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleDistal] = XRHandJointID.LittleDistal.ToIndex();
|
||||
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleTip] = XRHandJointID.LittleTip.ToIndex();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layout of hand joints for this provider, by having the
|
||||
/// provider mark each index corresponding to a <see cref="XRHandJointID"/>
|
||||
/// get marked as <see langword="true"/> if the provider attempts to track
|
||||
/// that joint.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Called once on creation so that before the subsystem is even started,
|
||||
/// so the user can immediately create a valid hierarchical structure as
|
||||
/// soon as they get a reference to the subsystem without even needing to
|
||||
/// start it.
|
||||
/// </remarks>
|
||||
/// <param name="handJointsInLayout">
|
||||
/// Each index corresponds to a <see cref="XRHandJointID"/>. For each
|
||||
/// joint that the provider will attempt to track, mark that spot as
|
||||
/// <see langword="true"/> by calling <c>.ToIndex()</c> on that ID.
|
||||
/// </param>
|
||||
public override void GetHandLayout(NativeArray<bool> handJointsInLayout)
|
||||
{
|
||||
|
||||
Initialize();
|
||||
handJointsInLayout[XRHandJointID.Palm.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.Wrist.ToIndex()] = true;
|
||||
|
||||
handJointsInLayout[XRHandJointID.ThumbMetacarpal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.ThumbProximal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.ThumbDistal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.ThumbTip.ToIndex()] = true;
|
||||
|
||||
handJointsInLayout[XRHandJointID.IndexMetacarpal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.IndexProximal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.IndexIntermediate.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.IndexDistal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.IndexTip.ToIndex()] = true;
|
||||
|
||||
handJointsInLayout[XRHandJointID.MiddleMetacarpal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.MiddleProximal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.MiddleIntermediate.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.MiddleDistal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.MiddleTip.ToIndex()] = true;
|
||||
|
||||
handJointsInLayout[XRHandJointID.RingMetacarpal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.RingProximal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.RingIntermediate.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.RingDistal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.RingTip.ToIndex()] = true;
|
||||
|
||||
handJointsInLayout[XRHandJointID.LittleMetacarpal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.LittleProximal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.LittleIntermediate.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.LittleDistal.ToIndex()] = true;
|
||||
handJointsInLayout[XRHandJointID.LittleTip.ToIndex()] = true;
|
||||
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieve current hand-tracking data from the provider.
|
||||
/// </summary>
|
||||
public override UpdateSuccessFlags TryUpdateHands(
|
||||
UpdateType updateType,
|
||||
ref Pose leftHandRootPose,
|
||||
NativeArray<XRHandJoint> leftHandJoints,
|
||||
ref Pose rightHandRootPose,
|
||||
NativeArray<XRHandJoint> rightHandJoints)
|
||||
{
|
||||
if (!isValid)
|
||||
return UpdateSuccessFlags.None;
|
||||
|
||||
UpdateSuccessFlags ret = UpdateSuccessFlags.None;
|
||||
|
||||
const int handRootIndex = (int)HandJoint.JointWrist;
|
||||
if (PXR_HandTracking.GetJointLocations(HandType.HandLeft, ref jointLocations))
|
||||
{
|
||||
if (jointLocations.isActive != 0U)
|
||||
{
|
||||
for (int index = 0, jointCount = (int)jointLocations.jointCount; index < jointCount; ++index)
|
||||
{
|
||||
ref HandJointLocation joint = ref jointLocations.jointLocations[index];
|
||||
int unityHandJointIndex = pxrJointIndexToUnityJointIndexMapping[index];
|
||||
|
||||
leftHandJoints[unityHandJointIndex] = CreateXRHandJoint(Handedness.Left, unityHandJointIndex, joint);
|
||||
|
||||
if (index == handRootIndex)
|
||||
{
|
||||
leftHandRootPose = PXRPosefToUnityPose(joint.pose);
|
||||
ret |= UpdateSuccessFlags.LeftHandRootPose;
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
ret |= UpdateSuccessFlags.LeftHandJoints;
|
||||
#else
|
||||
if (PicoAimHand.left.UpdateHand(HandType.HandLeft, (ret & UpdateSuccessFlags.LeftHandRootPose) != 0))
|
||||
{
|
||||
ret |= UpdateSuccessFlags.LeftHandJoints;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (PXR_HandTracking.GetJointLocations(HandType.HandRight, ref jointLocations))
|
||||
{
|
||||
if (jointLocations.isActive != 0U)
|
||||
{
|
||||
for (int index = 0, jointCount = (int)jointLocations.jointCount; index < jointCount; ++index)
|
||||
{
|
||||
ref HandJointLocation joint = ref jointLocations.jointLocations[index];
|
||||
int unityHandJointIndex = pxrJointIndexToUnityJointIndexMapping[index];
|
||||
rightHandJoints[unityHandJointIndex] = CreateXRHandJoint(Handedness.Right, unityHandJointIndex, joint);
|
||||
|
||||
if (index == handRootIndex)
|
||||
{
|
||||
rightHandRootPose = PXRPosefToUnityPose(joint.pose);
|
||||
ret |= UpdateSuccessFlags.RightHandRootPose;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
ret |= UpdateSuccessFlags.RightHandJoints;
|
||||
#else
|
||||
if (PicoAimHand.right.UpdateHand(HandType.HandRight, (ret & UpdateSuccessFlags.RightHandRootPose) != 0))
|
||||
{
|
||||
ret |= UpdateSuccessFlags.RightHandJoints;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CreateHands()
|
||||
{
|
||||
if (PicoAimHand.left == null)
|
||||
PicoAimHand.left = PicoAimHand.CreateHand(InputDeviceCharacteristics.Left);
|
||||
|
||||
if (PicoAimHand.right == null)
|
||||
PicoAimHand.right = PicoAimHand.CreateHand(InputDeviceCharacteristics.Right);
|
||||
}
|
||||
|
||||
void DestroyHands()
|
||||
{
|
||||
if (PicoAimHand.left != null)
|
||||
{
|
||||
InputSystem.RemoveDevice(PicoAimHand.left);
|
||||
PicoAimHand.left = null;
|
||||
}
|
||||
|
||||
if (PicoAimHand.right != null)
|
||||
{
|
||||
InputSystem.RemoveDevice(PicoAimHand.right);
|
||||
PicoAimHand.right = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create Unity XRHandJoint From PXR HandJointLocation
|
||||
/// </summary>
|
||||
/// <param name="handedness"></param>
|
||||
/// <param name="unityHandJointIndex"></param>
|
||||
/// <param name="joint"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
XRHandJoint CreateXRHandJoint(Handedness handedness, int unityHandJointIndex, in HandJointLocation joint)
|
||||
{
|
||||
|
||||
Pose pose = Pose.identity;
|
||||
XRHandJointTrackingState state = XRHandJointTrackingState.None;
|
||||
if ((joint.locationStatus & AllStatus) == AllStatus)
|
||||
{
|
||||
state = (XRHandJointTrackingState.Pose | XRHandJointTrackingState.Radius);
|
||||
pose = PXRPosefToUnityPose(joint.pose);
|
||||
}
|
||||
return XRHandProviderUtility.CreateJoint(handedness,
|
||||
state,
|
||||
XRHandJointIDUtility.FromIndex(unityHandJointIndex),
|
||||
pose, joint.radius
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PXR's Posef to Unity'Pose
|
||||
/// </summary>
|
||||
/// <param name="pxrPose"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
Pose PXRPosefToUnityPose(in Posef pxrPose)
|
||||
{
|
||||
Vector3 position = pxrPose.Position.ToVector3();
|
||||
Quaternion orientation = pxrPose.Orientation.ToQuat();
|
||||
return new Pose(position, orientation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// The <see cref="TrackedDevice.devicePosition"/> and
|
||||
/// <see cref="TrackedDevice.deviceRotation"/> inherited from <see cref="TrackedDevice"/>
|
||||
/// represent the aim pose. You can use these values to discover the target for pinch gestures,
|
||||
/// when appropriate.
|
||||
///
|
||||
/// Use the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin) in the scene to position and orient
|
||||
/// the device properly. If you are using this data to set the Transform of a GameObject in
|
||||
/// the scene hierarchy, you can set the local position and rotation of the Transform and make
|
||||
/// it a child of the <c>CameraOffset</c> object below the <c>XROrigin</c>. Otherwise, you can use the
|
||||
/// Transform of the <c>CameraOffset</c> to transform the data into world space.
|
||||
/// </remarks>
|
||||
#if UNITY_EDITOR
|
||||
[UnityEditor.InitializeOnLoad]
|
||||
#endif
|
||||
[Preserve, InputControlLayout(displayName = "Pico Aim Hand", commonUsages = new[] { "LeftHand", "RightHand" })]
|
||||
public partial class PicoAimHand : TrackedDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// The left-hand <see cref="InputDevice"/> that contains
|
||||
/// <see cref="InputControl"/>s that surface data in the Pico Hand
|
||||
/// Tracking Aim extension.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is recommended that you treat this as read-only, and do not set
|
||||
/// it yourself. It will be set for you if hand-tracking has been
|
||||
/// enabled and if you are running with either the OpenXR or Oculus
|
||||
/// plug-in.
|
||||
/// </remarks>
|
||||
public static PicoAimHand left { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The right-hand <see cref="InputDevice"/> that contains
|
||||
/// <see cref="InputControl"/>s that surface data in the Pico Hand
|
||||
/// Tracking Aim extension.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is recommended that you treat this as read-only, and do not set
|
||||
/// it yourself. It will be set for you if hand-tracking has been
|
||||
/// enabled and if you are running with either the OpenXR or Oculus
|
||||
/// plug-in.
|
||||
/// </remarks>
|
||||
public static PicoAimHand right { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The pinch amount required to register as being pressed for the
|
||||
/// purposes of <see cref="indexPressed"/>, <see cref="middlePressed"/>,
|
||||
/// <see cref="ringPressed"/>, and <see cref="littlePressed"/>.
|
||||
/// </summary>
|
||||
public const float pressThreshold = 0.8f;
|
||||
|
||||
/// <summary>
|
||||
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl)
|
||||
/// that represents whether the pinch between the index finger and
|
||||
/// the thumb is mostly pressed (greater than a threshold of <c>0.8</c>
|
||||
/// contained in <see cref="pressThreshold"/>).
|
||||
/// </summary>
|
||||
[Preserve, InputControl(offset = 0)]
|
||||
public ButtonControl indexPressed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cast the result of reading this to <see cref="PicoAimFlags"/> to examine the value.
|
||||
/// </summary>
|
||||
[Preserve, InputControl]
|
||||
public IntegerControl aimFlags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// An [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl)
|
||||
/// that represents the pinch strength between the index finger and
|
||||
/// the thumb.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A value of <c>0</c> denotes no pinch at all, while a value of
|
||||
/// <c>1</c> denotes a full pinch.
|
||||
/// </remarks>
|
||||
[Preserve, InputControl]
|
||||
public AxisControl pinchStrengthIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Perform final initialization tasks after the control hierarchy has been put into place.
|
||||
/// </summary>
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
|
||||
indexPressed = GetChildControl<ButtonControl>(nameof(indexPressed));
|
||||
aimFlags = GetChildControl<IntegerControl>(nameof(aimFlags));
|
||||
pinchStrengthIndex = GetChildControl<AxisControl>(nameof(pinchStrengthIndex));
|
||||
|
||||
var deviceDescriptor = XRDeviceDescriptor.FromJson(description.capabilities);
|
||||
if (deviceDescriptor != null)
|
||||
{
|
||||
if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Left) != 0)
|
||||
InputSystem.SetDeviceUsage(this, UnityEngine.InputSystem.CommonUsages.LeftHand);
|
||||
else if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Right) != 0)
|
||||
InputSystem.SetDeviceUsage(this, UnityEngine.InputSystem.CommonUsages.RightHand);
|
||||
}
|
||||
PXR_Plugin.System.FocusStateAcquired += OnFocusStateAcquired;
|
||||
}
|
||||
|
||||
private void OnFocusStateAcquired()
|
||||
{
|
||||
m_WasTracked = false;
|
||||
}
|
||||
|
||||
protected override void OnRemoved()
|
||||
{
|
||||
PXR_Plugin.System.FocusStateAcquired -= OnFocusStateAcquired;
|
||||
base.OnRemoved();
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PicoAimHand"/> and adds it to the Input System.
|
||||
/// </summary>
|
||||
/// <param name="extraCharacteristics">
|
||||
/// Additional characteristics to build the hand device with besides
|
||||
/// <see cref="InputDeviceCharacteristics.HandTracking"/> and <see cref="InputDeviceCharacteristics.TrackedDevice"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="PicoAimHand"/> retrieved from
|
||||
/// <see cref="InputSystem.AddDevice(InputDeviceDescription)"/>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// It is recommended that you do not call this yourself. It will be
|
||||
/// called for you at the appropriate time if hand-tracking has been
|
||||
/// enabled and if you are running with either the OpenXR or Oculus
|
||||
/// plug-in.
|
||||
/// </remarks>
|
||||
public static PicoAimHand CreateHand(InputDeviceCharacteristics extraCharacteristics)
|
||||
{
|
||||
var desc = new InputDeviceDescription
|
||||
{
|
||||
product = k_PicoAimHandDeviceProductName,
|
||||
capabilities = new XRDeviceDescriptor
|
||||
{
|
||||
characteristics = InputDeviceCharacteristics.HandTracking | InputDeviceCharacteristics.TrackedDevice | extraCharacteristics,
|
||||
inputFeatures = new List<XRFeatureDescriptor>
|
||||
{
|
||||
new XRFeatureDescriptor
|
||||
{
|
||||
name = "index_pressed",
|
||||
featureType = FeatureType.Binary
|
||||
},
|
||||
new XRFeatureDescriptor
|
||||
{
|
||||
name = "aim_flags",
|
||||
featureType = FeatureType.DiscreteStates
|
||||
},
|
||||
new XRFeatureDescriptor
|
||||
{
|
||||
name = "aim_pose_position",
|
||||
featureType = FeatureType.Axis3D
|
||||
},
|
||||
new XRFeatureDescriptor
|
||||
{
|
||||
name = "aim_pose_rotation",
|
||||
featureType = FeatureType.Rotation
|
||||
},
|
||||
new XRFeatureDescriptor
|
||||
{
|
||||
name = "pinch_strength_index",
|
||||
featureType = FeatureType.Axis1D
|
||||
}
|
||||
}
|
||||
}.ToJson()
|
||||
};
|
||||
return InputSystem.AddDevice(desc) as PicoAimHand;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues update events in the Input System based on the supplied hand.
|
||||
/// It is not recommended that you call this directly. This will be called
|
||||
/// for you when appropriate.
|
||||
/// </summary>
|
||||
/// <param name="isHandRootTracked">
|
||||
/// Whether the hand root pose is valid.
|
||||
/// </param>
|
||||
/// <param name="aimFlags">
|
||||
/// The aim flags to update in the Input System.
|
||||
/// </param>
|
||||
/// <param name="aimPose">
|
||||
/// The aim pose to update in the Input System. Used if the hand root is tracked.
|
||||
/// </param>
|
||||
/// <param name="pinchIndex">
|
||||
/// The pinch strength for the index finger to update in the Input System.
|
||||
/// </param>
|
||||
public void UpdateHand(bool isHandRootTracked, HandAimStatus aimFlags, Posef aimPose, float pinchIndex)
|
||||
{
|
||||
if (aimFlags != m_PreviousFlags)
|
||||
{
|
||||
InputSystem.QueueDeltaStateEvent(this.aimFlags, (int)aimFlags);
|
||||
m_PreviousFlags = aimFlags;
|
||||
}
|
||||
|
||||
bool isIndexPressed = pinchIndex > pressThreshold;
|
||||
if (isIndexPressed != m_WasIndexPressed)
|
||||
{
|
||||
InputSystem.QueueDeltaStateEvent(indexPressed, isIndexPressed);
|
||||
m_WasIndexPressed = isIndexPressed;
|
||||
}
|
||||
|
||||
InputSystem.QueueDeltaStateEvent(pinchStrengthIndex, pinchIndex);
|
||||
|
||||
if ((aimFlags & HandAimStatus.AimComputed) == 0)
|
||||
{
|
||||
if (m_WasTracked)
|
||||
{
|
||||
InputSystem.QueueDeltaStateEvent(isTracked, false);
|
||||
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.None);
|
||||
m_WasTracked = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isHandRootTracked)
|
||||
{
|
||||
InputSystem.QueueDeltaStateEvent(devicePosition, aimPose.Position.ToVector3());
|
||||
InputSystem.QueueDeltaStateEvent(deviceRotation, aimPose.Orientation.ToQuat());
|
||||
|
||||
if (!m_WasTracked)
|
||||
{
|
||||
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.Position | InputTrackingState.Rotation);
|
||||
InputSystem.QueueDeltaStateEvent(isTracked, true);
|
||||
}
|
||||
|
||||
m_WasTracked = true;
|
||||
}
|
||||
else if (m_WasTracked)
|
||||
{
|
||||
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.None);
|
||||
InputSystem.QueueDeltaStateEvent(isTracked, false);
|
||||
m_WasTracked = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool UpdateHand(HandType handType, bool isHandRootTracked)
|
||||
{
|
||||
|
||||
HandAimState handAimState = new HandAimState();
|
||||
PXR_HandTracking.GetAimState(handType, ref handAimState);
|
||||
|
||||
UpdateHand(
|
||||
isHandRootTracked,
|
||||
handAimState.aimStatus,
|
||||
handAimState.aimRayPose,
|
||||
handAimState.touchStrengthRay);
|
||||
|
||||
return (handAimState.aimStatus&HandAimStatus.AimComputed) != 0;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
static PicoAimHand() => RegisterLayout();
|
||||
#endif
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
static void RegisterLayout()
|
||||
{
|
||||
InputSystem.RegisterLayout<PicoAimHand>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithProduct(k_PicoAimHandDeviceProductName));
|
||||
}
|
||||
|
||||
const string k_PicoAimHandDeviceProductName = "Pico Aim Hand Tracking";
|
||||
|
||||
HandAimStatus m_PreviousFlags;
|
||||
bool m_WasTracked;
|
||||
bool m_WasIndexPressed;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //XR_HANDS
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d52208075b354ec4b91ede460034a741
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user