using EZXR.Glass.Core; using UnityEngine; namespace EZXR.Glass.Inputs { /// /// 近距离触碰交互 /// [RequireComponent(typeof(HandInfo))] public class HandTouch : MonoBehaviour { /// /// 食指指尖圆环的Prefab /// GameObject prefab_IndexRing; IndexRing indexRing; ///// ///// 旋转握把和缩放角所在的Layer,可以被射线射到但是不会被射线拖动 ///// //public LayerMask layerMask_Handler; ///// ///// ARUI的Layer,可以被射线射到但是不会被射线拖动 ///// //public LayerMask layerMask_ARUI; HandInfo handInfo; /// /// 抓取状态,0为拇指和食指中间的Trigger区域没有碰到任何物体,1为拇指和食指中间的Trigger区域触碰到了物体(待抓取),2为已经被手抓起来了 /// int grabState; /// /// 抓取状态,0为拇指和食指中间的Trigger区域没有碰到任何物体,1为拇指和食指中间的Trigger区域触碰到了物体(待抓取),2为已经被手抓起来了 /// int GrabState { get { return grabState; } set { grabState = value; if (value == 2) { handInfo.isDragging = true; } else { handInfo.isDragging = false; } } } /// /// 当前手正在Trigger的物体 /// Transform touchingObj; /// /// 子物体在父物体下的LocalRotation /// Quaternion q_UnderPalm; /// /// 子物体在父物体坐标系下的LocalPosition /// Vector3 p_UnderPalm; #region 双手操作 /// /// 左手射线起始点在被抓物体坐标系下的坐标,用于双手操作 /// static Vector3 leftRaypointInLocalSpace; /// /// 在物体被捏住的时刻,右手射线起始点向左手射线起始点做向量,用于计算两手的旋转四元数 /// static Vector3 hitDirection; /// /// 在物体被捏住的时刻,物体在相机父物体下的localScale,用于双手缩放 /// static Vector3 hitLocalScale; /// /// 在物体被双手捏住的时刻,双手射线起始点的距离 /// static float distanceOfTwoRaypoint; #endregion // Start is called before the first frame update void Awake() { handInfo = GetComponent(); //显示食指指尖圆环 prefab_IndexRing = ResourcesManager.Load("Touch/IndexRing"); indexRing = Instantiate(prefab_IndexRing, transform).GetComponent(); indexRing.SetUp(handInfo); } private void OnDisable() { handInfo.CurCloseGrabbingTarget = null; GrabState = 0; indexRing.SetStatus(IndexRingStatus.Ring); if (handInfo.CurCloseContactingTarget != null) { handInfo.CurCloseContactingTarget = null; } } // Update is called once per frame void Update() { //当前眼镜视野中是否存在手 if (handInfo.Exist) { if (handInfo.isPinching)//手指是捏合状态 { switch (GrabState) { case 1://手正在触碰物体 handInfo.CurCloseGrabbingTarget = touchingObj; ////如果当前握持的是普通物体,不是旋转手柄或者缩放角 //if (1 << touchingObj.gameObject.layer != layerMask_Handler.value && 1 << touchingObj.gameObject.layer != layerMask_ARUI.value) { GrabState = 2; indexRing.SetStatus(IndexRingStatus.Solid); //取食指指尖位置和食指挨着指尖的关节的位置的中心为捏合点 handInfo.grabLocalPoint = touchingObj.InverseTransformPoint((handInfo.GetJointData(HandJointType.Thumb_3).position + handInfo.GetJointData(HandJointType.Index_4).position) / 2.0f); //得到子物体在父物体下的LocalRotation q_UnderPalm = new Quaternion(-handInfo.palm.rotation.x, -handInfo.palm.rotation.y, -handInfo.palm.rotation.z, handInfo.palm.rotation.w) * touchingObj.rotation; //得到子物体在父物体坐标系下的LocalPosition p_UnderPalm = handInfo.palm.InverseTransformPoint(touchingObj.position); if (HandInfo.isTwoHandCloseGrabbing) { //得到左手射线点在物体坐标系下的坐标,用于物体位置的计算 leftRaypointInLocalSpace = touchingObj.InverseTransformPoint(InputSystem.leftHand.rayPoint_Start); //用于双手旋转,得到物体被捏住的时刻,右手射线起始点向左手射线起始点做向量,用于计算两手的旋转四元数 hitDirection = (InputSystem.leftHand.rayPoint_Start) - (InputSystem.rightHand.rayPoint_Start); //用于双手缩放,得到击中物体的localScale,后面缩放都是基于此值 hitLocalScale = touchingObj.localScale; //用于双手缩放,得到物体被捏住时刻左右手射线起始点的距离,后面缩放都是基于此值 distanceOfTwoRaypoint = Vector3.Distance(InputSystem.leftHand.rayPoint_Start, InputSystem.rightHand.rayPoint_Start); } } break; case 2://手正在执行拖拽 ////如果当前握持的是普通物体,不是旋转手柄或者缩放角 //if (1 << touchingObj.gameObject.layer != layerMask_Handler.value && 1 << touchingObj.gameObject.layer != layerMask_ARUI.value) { //双手操作:如果当前双手在操作同一个物体的话,物体的位置放在左手逻辑中来计算(避免在两个手的逻辑中各计算一次) if (HandInfo.isTwoHandCloseGrabbing) { if (handInfo.handType == HandType.Left) { //计算缩放 float dis = Vector3.Distance(InputSystem.leftHand.rayPoint_Start, InputSystem.rightHand.rayPoint_Start); handInfo.CurCloseGrabbingSpatialObject.SetScale(dis / distanceOfTwoRaypoint * hitLocalScale); //计算旋转 Vector3 newHitDirection = InputSystem.leftHand.rayPoint_Start - InputSystem.rightHand.rayPoint_Start; Quaternion q = Quaternion.FromToRotation(hitDirection, newHitDirection); hitDirection = newHitDirection; //设置目标物体的旋转 handInfo.CurCloseGrabbingSpatialObject.SetRotation(q * touchingObj.rotation); //设置目标物体的位置(必须先计算rotation才能计算position),通过左手射线起始点的当前位置和刚捏住的时候得到的“物体坐标点到左手射线起始点的射线”来算出物体的当前坐标点 handInfo.CurCloseGrabbingSpatialObject.SetPosition(InputSystem.leftHand.rayPoint_Start - (touchingObj.TransformPoint(leftRaypointInLocalSpace) - touchingObj.position)); } //得到子物体在父物体下的LocalRotation q_UnderPalm = new Quaternion(-handInfo.palm.rotation.x, -handInfo.palm.rotation.y, -handInfo.palm.rotation.z, handInfo.palm.rotation.w) * touchingObj.rotation; //得到子物体在父物体坐标系下的LocalPosition p_UnderPalm = handInfo.palm.InverseTransformPoint(touchingObj.position); } else { ////给手的位置加滤波 //NativeSwapManager.Point3 temp = new NativeSwapManager.Point3(handInfo.rayPoint_Start + grabOffset); //NativeSwapManager.filterPoint(ref temp, touchingObj.GetInstanceID()); //Vector3 tarPos = new Vector3(temp.x, temp.y, temp.z); handInfo.CurCloseGrabbingSpatialObject.SetRotation(handInfo.palm.rotation * q_UnderPalm); handInfo.CurCloseGrabbingSpatialObject.SetPosition(handInfo.palm.position + handInfo.palm.rotation * p_UnderPalm); } } break; } } else { //Debug.Log("HandTouch - handInfo.isPinching: " + handInfo.isPinching + ", " + grabState); //根据拇指食指触碰物体的情况来决定圆环的显示与否 indexRing.gameObject.SetActive(handInfo.preCloseContacting | handInfo.IsCloseContacting); handInfo.CurCloseGrabbingTarget = null; if (GrabState == 2) { //Debug.Log("HandTouch - grabState: " + grabState); GrabState = 0; indexRing.SetStatus(IndexRingStatus.Ring); touchingObj = null; } //if (handInfo.CurCloseContactingTarget == null) //{ // handInfo.isCloseContacting = false; //} } } else { OnDisable(); } } public void ForOnTriggerEnter(Collider other) { ForOnTriggerStay(other); } public void ForOnTriggerStay(Collider other) { if (enabled && !handInfo.isPinching) { GrabState = 1; indexRing.SetStatus(IndexRingStatus.Ring); touchingObj = other.transform; } } public void ForOnTriggerExit(Collider other) { if (enabled && !handInfo.isPinching) { handInfo.CurCloseGrabbingTarget = null; GrabState = 0; indexRing.SetStatus(IndexRingStatus.Ring); touchingObj = null; } } } }