using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.LowLevel; using UnityEngine.InputSystem.Utilities; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.Controls; using Ximmerse.XR.InputSystems.GazeAndGestureInteraction; namespace Ximmerse.XR.InputSystems { /// /// gesture state for input system to couple with input action properties system. /// public struct HandState : IInputStateTypeInfo { public FourCC format => new FourCC('X', 'M', 'G', 'T'); #region Properties represents any hand [InputControl(name = "anyHandIsTracked", layout = "Button")] public bool anyHandIsTracked; /// /// 0 = left, 1 = right /// [InputControl(name = "handness", layout = "Integer")] public int handness; /// /// 0 = none, 3 (1+2) = position + rotation /// [InputControl(name = "trackingState", layout = "Integer")] public uint trackingState; /// /// Palm position /// [InputControl(name = "palmPosition", layout = "Vector3")] public Vector3 palmPosition; [InputControl(name = "gazeRayState", layout = "Integer")] public uint gazeRayState; [InputControl(name = "gazeRayOrigin", layout = "Vector3")] public Vector3 gazeRayOrigin; [InputControl(name = "gazeRayRotation", layout = "Quaternion")] public Quaternion gazeRayRotation; /// /// 手掌沿手指前向的法线 /// [InputControl(name = "palmRotation", layout = "Quaternion")] public Quaternion palmRotation; [InputControl(name = "palmScale", layout = "Vector3")] public Vector3 palmScale; /// /// 掌心向上法线 /// [InputControl(name = "palmNormal", layout = "Vector3")] public Vector3 palmNormal; /// /// 手势类型 : 抓取 /// [InputControl(name = "isGrasp", layout = "Button")] public bool isGrasp; /// /// 手势类型 : 张开手掌 /// [InputControl(name = "isOpenHand", layout = "Button")] public bool isOpenHand; /// /// 手势类型 : 握拳 /// [InputControl(name = "isClosedHand", layout = "Button")] public bool isClosedHand; /// /// 手势类型 : 握拳 /// [InputControl(name = "gripValue", layout = "Axis")] public float gripValue; #endregion } /// /// Hand gesture input device /// [InputControlLayout(stateType = typeof(HandState))] public class XimmerseXRGesture : InputDevice, IInputUpdateCallbackReceiver { [InputControl(name = "HandState/anyHandIsTracked")] public ButtonControl anyHandIsTracked { get; internal set; } /// /// Tracking state, the value mapped to UnityEngine.XR.InputTrackingState: /// None = 0, Position = 1, Rotation = 2,Velocity = 4,AngularVelocity = 8, /// Acceleration = 16,AngularAcceleration = 32, All = 63 /// [InputControl(name = "HandState/trackingState")] public IntegerControl trackingState { get; internal set; } /// /// 0 = left, 1 = right /// [InputControl(name = "HandState/handness")] public IntegerControl handness { get; internal set; } [InputControl(name = "HandState/palmPosition")] public Vector3Control palmPosition { get; internal set; } [InputControl(name = "HandState/palmRotation")] public QuaternionControl palmRotation { get; internal set; } [InputControl(name = "HandState/palmScale")] public Vector3Control palmScale { get; internal set; } [InputControl(name = "HandState/gazeRayState")] public IntegerControl gazeRayState { get; internal set; } [InputControl(name = "HandState/gazeRayOrigin")] public Vector3Control gazeRayOrigin { get; internal set; } [InputControl(name = "HandState/gazeRayRotation")] public QuaternionControl gazeRayRotation { get; internal set; } [InputControl(name = "HandState/palmNormal")] public Vector3Control palmNormal { get; internal set; } [InputControl(name = "HandState/isGrasp")] public ButtonControl isGrasp { get; internal set; } [InputControl(name = "HandState/isOpenHand")] public ButtonControl isOpenHand { get; internal set; } [InputControl(name = "HandState/isClosedHand")] public ButtonControl isClosedHand { get; internal set; } [InputControl(name = "HandState/gripValue")] public AxisControl gripValue { get; internal set; } /// /// The native hand track info data. /// public HandTrackingInfo handTrackInfo { get => HandTracking.HandTrackingInfo; } public XimmerseXRGesture() : base() { displayName = "Ximmerse Gesture Input Device"; } protected override void FinishSetup() { base.FinishSetup(); anyHandIsTracked = GetChildControl("anyHandIsTracked"); handness = GetChildControl("handness"); trackingState = GetChildControl("trackingState"); palmPosition = GetChildControl("palmPosition"); palmRotation = GetChildControl("palmRotation"); gazeRayState = GetChildControl("gazeRayState"); gazeRayOrigin = GetChildControl("gazeRayOrigin"); gazeRayRotation = GetChildControl("gazeRayRotation"); palmScale = GetChildControl("palmScale"); palmNormal = GetChildControl("palmNormal"); isGrasp = GetChildControl("isGrasp"); isOpenHand = GetChildControl("isOpenHand"); isClosedHand = GetChildControl("isClosedHand"); gripValue = GetChildControl("gripValue"); } public void OnUpdate() { var _state = new HandState(); GazeAndHandInteractionSystem gazeInterSys = GazeAndHandInteractionSystem.instance; var _handTrackInfo = this.handTrackInfo; _state.anyHandIsTracked = _handTrackInfo.IsValid; _state.handness = (int)_handTrackInfo.Handness; _state.trackingState = _handTrackInfo.IsValid ? 3u : 0u; _state.palmPosition = _handTrackInfo.PalmLocalPosition; _state.palmRotation = _handTrackInfo.PalmLocalRotation; GazeAndHandInteractionSystem.GetEyeReticleLocalPose(out Pose eyeReticlePose); _state.gazeRayState = 3u; _state.gazeRayOrigin = eyeReticlePose.position; _state.gazeRayRotation = eyeReticlePose.rotation; _state.palmNormal = _handTrackInfo.PalmLocalNormal; _state.palmScale = _handTrackInfo.PalmScale; //如果 gaze interaction system 存在, 采用其抛出的优化值: bool isclosepinch = _handTrackInfo.NativeGestureType == (int)TouchlessA3D.GestureType.CLOSED_PINCH; bool isclosehand = _handTrackInfo.gestureFistOpenHand == GestureType_Fist_OpenHand.Fist; if (_handTrackInfo.IsTracking) { if (isclosepinch || isclosehand) { _state.isGrasp = true; } else { _state.isGrasp = false; } _state.isOpenHand = _handTrackInfo.gestureFistOpenHand == GestureType_Fist_OpenHand.Opened; _state.isClosedHand = _handTrackInfo.gestureFistOpenHand == GestureType_Fist_OpenHand.Fist; _state.gripValue = _state.isGrasp ? 1 : 0; } else { _state.isGrasp = false; _state.isOpenHand = true; _state.isClosedHand = false; _state.gripValue = 0; } InputSystem.QueueStateEvent(this, _state); } } }