This commit is contained in:
2025-11-13 17:40:28 +08:00
parent 962ab49609
commit 10156da245
5503 changed files with 805282 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll 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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f753f52cc8c63524f9ace6fcab377a5b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,570 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll 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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 35bed5e2884b6cb4a8f47d89e0bc7401
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,275 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll 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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0fea894361bde054fbfc4de741aa3483
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll 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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5cbe7cced81af1f46a0aef054af159be
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,363 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll 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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea4ea412f6917124397eeba0f097ec6f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,622 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll 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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d52208075b354ec4b91ede460034a741
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: