using EZXR.Glass.Core; using EZXR.Glass.SixDof; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using Wheels.Unity; namespace EZXR.Glass.Inputs { public enum GestureType { Unknown = -1, OpenHand = 0, Grab, Pinch, Point, Victory, Call, } public enum HandJointType { Thumb_0, Thumb_1, Thumb_2, /// /// 拇指尖 /// Thumb_3, /// /// 食指根节点 /// Index_1, Index_2, Index_3, /// /// 食指尖 /// Index_4, /// /// 中指根节点 /// Middle_1, Middle_2, Middle_3, /// /// 中指指尖 /// Middle_4, Ring_1, Ring_2, Ring_3, /// /// 无名指指尖 /// Ring_4, Pinky_0, /// /// 小指根节点 /// Pinky_1, Pinky_2, Pinky_3, /// /// 小指指尖 /// Pinky_4, /// /// 掌心点 /// Palm, /// /// 手腕横切线,靠近拇指根节点的点 /// Wrist_Thumb, /// /// 手腕横切线,靠近小指根节点的点 /// Wrist_Pinky, /// /// 手腕横切线,中点 /// Wrist_Middle, } /// /// 包含单个手的各种状态信息,是个基础信息类,供其他类进行状态获取和协同 /// [ScriptExecutionOrder(-48)] public class HandInfo : InputInfoBase { /// /// 手的所有关节等物体的父节点 /// public Transform root { get { return transform; } } HandVisualization handVisualization; HandsVisualizationForModel handsVisualizationForModel; InputRaycast handRaycast; HandTouch handTouch; HandCollision handCollision; /// /// 初始化,设置当前HandInfo所属的手是左手还是右手 /// /// 0为左手,1为右手 public override void Init(HandType handType) { base.Init(handType); handVisualization = GetComponent(); handsVisualizationForModel = GetComponent(); handRaycast = GetComponent(); handTouch = GetComponent(); handCollision = GetComponent(); //设定肩部点,用于射线计算 shoulderPoint = new Vector3(handType == HandType.Left ? -0.15f : 0.15f, -0.15f, -0.1f); palm = new GameObject("Palm").transform; palm.parent = transform; } public void UpdateHandInfoData(NativeSwapManager.HandTrackingData handTrackingData) { this.handTrackingData = handTrackingData; if (handTrackingData.handJointData != null) { Pose pose; for (int i = 0; i < handTrackingData.handJointData.Length; i++) { NativeSwapManager.Mat4f mat4 = handTrackingData.handJointData[i].handJointPose; Matrix4x4 m = new Matrix4x4(); m.SetColumn(0, new Vector4(mat4.col0.x, mat4.col0.y, mat4.col0.z, mat4.col0.w)); m.SetColumn(1, new Vector4(mat4.col1.x, mat4.col1.y, mat4.col1.z, mat4.col1.w)); m.SetColumn(2, new Vector4(mat4.col2.x, mat4.col2.y, mat4.col2.z, mat4.col2.w)); m.SetColumn(3, new Vector4(mat4.col3.x, mat4.col3.y, mat4.col3.z, mat4.col3.w)); if (!m.ValidTRS()) { return; } pose.rotation = m.rotation;// XRMan.Instance == null ? m.rotation : (XRMan.Instance.transform.rotation * m.rotation); Vector3 pos = m.GetColumn(3); pose.position = pos;// XRMan.Instance == null ? pos : (XRMan.Instance.transform.TransformPoint(pos)); HandJointType handJointType = (HandJointType)i; if (jointsPose.ContainsKey(handJointType)) { jointsPose[handJointType] = pose; } else { jointsPose.Add(handJointType, pose); } } } } protected override void Update() { if (Exist) { UpdatePinching(); palm.position = GetJointData(HandJointType.Palm).position; palm.rotation = GetJointData(HandJointType.Palm).rotation; //掌心面向的方向 palmNormal = GetJointData(HandJointType.Palm).TransformDirection(Vector3.forward); //手掌指尖朝向 palmDirection = GetJointData(HandJointType.Palm).TransformDirection(Vector3.up); //射线方向 if (!(ARHandManager.SetRayDirByExternal != null && ARHandManager.SetRayDirByExternal(this, ref rayDirection))) { rayDirection = (GetJointData(HandJointType.Index_1).position - ARHandManager.head.TransformPoint(shoulderPoint)).normalized; } //射线起点 if (!(ARHandManager.SetRayStartPointByExternal != null && ARHandManager.SetRayStartPointByExternal(this, ref rayPoint_Start))) { rayPoint_Start = GetJointData(HandJointType.Index_1).position + rayDirection * rayStartDistance; } ////用于双手操作,得到左手加滤波之后的掌心点位置 //NativeSwapManager.Point3 temp = new NativeSwapManager.Point3(rayPoint_Start); //NativeSwapManager.filterPoint(ref temp, transform.GetInstanceID()); //Vector3 tarPos = new Vector3(temp.x, temp.y, temp.z); //rayPoint_Start_Left = tarPos; //从算法得到的预估的射线终点位置 //rayPoint_End = new Vector3(ray[1].x, Main.ray[1].y, ray[1].z); } } protected override void UpdatePinching() { bool curPinchState = handTrackingData.isTracked && (handTrackingData.gestureType == GestureType.Pinch || handTrackingData.gestureType == GestureType.Grab); if (isPinching) { if (curPinchState) { startPinch = false; } else { endPinch = true; } } else { if (curPinchState) { startPinch = true; } else { endPinch = false; } } isPinching = curPinchState; } #region 手交互能力开关 /// /// 设置或获得当前手的显示状态(仅仅影响显示,并不影响交互) /// public override bool Visibility { get { return handsVisualizationForModel ? handsVisualizationForModel.Visibility : false; } set { if (handsVisualizationForModel != null) { handsVisualizationForModel.Visibility = value; } } } /// /// 设置或获得远距离射线交互状态 /// public override bool RaycastInteraction { get { return handRaycast ? handRaycast.enabled : false; } set { if (handRaycast != null) { handRaycast.enabled = value; } } } /// /// 设置或获得近距离交互状态 /// public override bool TouchInteraction { get { return handTouch ? handTouch.enabled : false; } set { if (handTouch != null) { handTouch.enabled = value; } } } /// /// 设置或获得手部的物理碰撞交互状态 /// public override bool PhysicsInteraction { get { return handCollision ? handCollision.enabled : false; } set { if (handCollision != null) { handCollision.enabled = value; } } } #endregion #region 单手信息 /// /// 当前手节点是否在视野内 /// /// /// public bool InView(HandJointType jointType) { if (Application.isEditor) { Vector3 viewportPoint = HMDPoseTracker.Instance.centerCamera.WorldToViewportPoint(GetJointData(jointType).position); //Debug.Log(viewportPoint.ToString("0.##")); return viewportPoint.x > 0 && viewportPoint.x < 1 && viewportPoint.y > 0 && viewportPoint.y < 1 && viewportPoint.z > 0; } else { Vector3 viewportPoint_L = HMDPoseTracker.Instance.leftCamera.WorldToViewportPoint(GetJointData(jointType).position); Vector3 viewportPoint_R = HMDPoseTracker.Instance.rightCamera.WorldToViewportPoint(GetJointData(jointType).position); return (viewportPoint_L.x > 0 && viewportPoint_L.x < 1 && viewportPoint_L.y > 0 && viewportPoint_L.y < 1 && viewportPoint_L.z > 0) || (viewportPoint_R.x > 0 && viewportPoint_R.x < 1 && viewportPoint_R.y > 0 && viewportPoint_R.y < 1 && viewportPoint_R.z > 0); } } public bool InLeftView(HandJointType jointType) { Vector3 viewportPoint_L = HMDPoseTracker.Instance.leftCamera.WorldToViewportPoint(GetJointData(jointType).position); return (viewportPoint_L.x > 0 && viewportPoint_L.x < 1 && viewportPoint_L.y > 0 && viewportPoint_L.y < 1 && viewportPoint_L.z > 0); } public bool InRightView(HandJointType jointType) { Vector3 viewportPoint_R = HMDPoseTracker.Instance.rightCamera.WorldToViewportPoint(GetJointData(jointType).position); return (viewportPoint_R.x > 0 && viewportPoint_R.x < 1 && viewportPoint_R.y > 0 && viewportPoint_R.y < 1 && viewportPoint_R.z > 0); } /// /// 当前眼镜视野中是否存在这个手 /// public override bool Exist { get { return handTrackingData.isTracked; } } /// /// 手掌正在朝向头部,如果手掌朝向和手掌与头的连线的夹角小于angle则认为手掌是朝向了头部 /// /// 默认90 /// public override bool isPalmFacingHead(float angle = 90) { Pose palm = GetJointData(HandJointType.Palm); Vector3 palmNormal = palm.TransformDirection(Vector3.forward * 0.1f); Vector3 palmToHead = HMDPoseTracker.Instance.Head.position - palm.position; //求palmNormal和palmToHead的夹角 float includedAngle = Vector3.Angle(palmNormal, palmToHead); if (includedAngle < angle) { return true; } else { return false; } } /// /// 从算法得到的此手的原始关节点数据,单位为mm /// public NativeSwapManager.HandTrackingData handTrackingData = new NativeSwapManager.HandTrackingData(); /// /// 自行定义的一个肩部点,相对于头部坐标系的 /// Vector3 shoulderPoint; /// /// 手的动作 /// public GestureType gestureType { get { return handTrackingData.gestureType; } } /// /// 所有手指关节点的Pose /// public Dictionary jointsPose = new Dictionary(); /// /// 手掌面向的方向 /// [HideInInspector] public Vector3 palmNormal; /// /// 手掌指尖朝向(从手腕点到中指和无名指根节点中间点的朝向,世界坐标系) /// [HideInInspector] public Vector3 palmDirection; [HideInInspector] public Transform palm; public bool JointDataExist(HandJointType handJointType) { return jointsPose.ContainsKey(handJointType); } public Pose GetJointData(HandJointType handJointType) { if (jointsPose.ContainsKey(handJointType)) { return jointsPose[handJointType]; } return Pose.identity; } public Pose GetJointData(int handJointTypeID) { return GetJointData((HandJointType)handJointTypeID); } #endregion #region 当前预触碰的物体信息 /// /// 在手的近距离交互预判区内是否存在物体,只是在手的触发区域内但是还没有碰到食指指尖(主要用于避免在手即将触摸到旋转握把的时候会出现射线射到另外一个握把或者缩放角) /// [HideInInspector] public bool preCloseContacting; /// /// 手部近距离交互预判区(TriggerForFarNearSwitch中定义区域大小,此区域内则认为用户要近距离抓取)内存在的距离最近的物体 /// Transform preCloseContactingTarget; /// /// 手部近距离交互预判区内存在的距离最近的物体 /// public Transform PreCloseContactingTarget { get { return preCloseContactingTarget; } set { //if (preCloseContactingTarget != value) { //记录上一帧食指指尖的近距离交互预判区内存在的距离最近的物体 Last_PreCloseContactingTarget = preCloseContactingTarget; preCloseContactingTarget = value; preCloseContactingTarget_Renderer = (preCloseContactingTarget == null ? null : preCloseContactingTarget.GetComponent()); if (preCloseContactingTarget_Renderer != null) { if (preCloseContactingTarget_PropertyBlock == null) { preCloseContactingTarget_PropertyBlock = new MaterialPropertyBlock(); } preCloseContactingTarget_Renderer.GetPropertyBlock(preCloseContactingTarget_PropertyBlock); } if (preCloseContactingTarget == null) { preCloseContacting = false; } else { preCloseContacting = true; } } } } [HideInInspector] public Renderer preCloseContactingTarget_Renderer; [HideInInspector] public MaterialPropertyBlock preCloseContactingTarget_PropertyBlock; /// /// 上一帧手部近距离交互预判区内存在的距离最近的物体 /// Transform last_PreCloseContactingTarget; /// /// 上一帧手部近距离交互预判区内存在的距离最近的物体 /// public Transform Last_PreCloseContactingTarget { get { return last_PreCloseContactingTarget; } set { if (last_PreCloseContactingTarget != value) { last_PreCloseContactingTarget = value; last_PreCloseContactingTarget_Renderer = (last_PreCloseContactingTarget == null ? null : last_PreCloseContactingTarget.GetComponent()); if (last_PreCloseContactingTarget_Renderer != null) { if (last_PreCloseContactingTarget_PropertyBlock == null) { last_PreCloseContactingTarget_PropertyBlock = new MaterialPropertyBlock(); } last_PreCloseContactingTarget_Renderer.GetPropertyBlock(last_PreCloseContactingTarget_PropertyBlock); } } } } [HideInInspector] public Renderer last_PreCloseContactingTarget_Renderer; [HideInInspector] public MaterialPropertyBlock last_PreCloseContactingTarget_PropertyBlock; #endregion #region 当前正在触碰的物体信息 protected bool isCloseContacting; /// /// 指示手是否正在近距离触碰某个物体(被拇指和食指指尖的连线穿过) /// public bool IsCloseContacting { get { return isCloseContacting; } set { isCloseContacting = value; } } Collider curCloseContactingTarget; /// /// 当前正在被近距离触碰的物体 /// public Collider CurCloseContactingTarget { get { return curCloseContactingTarget; } set { if (curCloseContactingTarget != null && value != null) { if (curCloseContactingTarget != value) { SpatialObject.PerformOnHandTriggerExit(curCloseContactingTarget); SpatialObject.PerformOnHandTriggerEnter(curCloseContactingTarget); } else { SpatialObject.PerformOnHandTriggerStay(value); } } else if (curCloseContactingTarget == null && value != null) { SpatialObject.PerformOnHandTriggerEnter(value); } else if (curCloseContactingTarget != null && value == null) { SpatialObject.PerformOnHandTriggerExit(curCloseContactingTarget); } curCloseContactingTarget = value; if (curCloseContactingTarget == null) { IsCloseContacting = false; } else { IsCloseContacting = true; } } } /// /// 指示手是否正在近距离触碰某个物体或者射线是否正射在某个物体上 /// public bool IsContacting { get { return IsCloseContacting | isRayContacting; } } /// /// 当前正在被触碰的物体(无论射线还是近距离) /// public Collider CurContactingTarget { get { if (CurCloseContactingTarget == null) { if (curRayContactingTarget != null) { return curRayContactingTarget; } } else { return CurCloseContactingTarget; } return null; } } #endregion } }