HandTouch.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. using EZXR.Glass.Core;
  2. using UnityEngine;
  3. namespace EZXR.Glass.Inputs
  4. {
  5. /// <summary>
  6. /// 近距离触碰交互
  7. /// </summary>
  8. [RequireComponent(typeof(HandInfo))]
  9. public class HandTouch : MonoBehaviour
  10. {
  11. /// <summary>
  12. /// 食指指尖圆环的Prefab
  13. /// </summary>
  14. GameObject prefab_IndexRing;
  15. IndexRing indexRing;
  16. ///// <summary>
  17. ///// 旋转握把和缩放角所在的Layer,可以被射线射到但是不会被射线拖动
  18. ///// </summary>
  19. //public LayerMask layerMask_Handler;
  20. ///// <summary>
  21. ///// ARUI的Layer,可以被射线射到但是不会被射线拖动
  22. ///// </summary>
  23. //public LayerMask layerMask_ARUI;
  24. HandInfo handInfo;
  25. /// <summary>
  26. /// 抓取状态,0为拇指和食指中间的Trigger区域没有碰到任何物体,1为拇指和食指中间的Trigger区域触碰到了物体(待抓取),2为已经被手抓起来了
  27. /// </summary>
  28. int grabState;
  29. /// <summary>
  30. /// 抓取状态,0为拇指和食指中间的Trigger区域没有碰到任何物体,1为拇指和食指中间的Trigger区域触碰到了物体(待抓取),2为已经被手抓起来了
  31. /// </summary>
  32. int GrabState
  33. {
  34. get
  35. {
  36. return grabState;
  37. }
  38. set
  39. {
  40. grabState = value;
  41. if (value == 2)
  42. {
  43. handInfo.isDragging = true;
  44. }
  45. else
  46. {
  47. handInfo.isDragging = false;
  48. }
  49. }
  50. }
  51. /// <summary>
  52. /// 当前手正在Trigger的物体
  53. /// </summary>
  54. Transform touchingObj;
  55. /// <summary>
  56. /// 子物体在父物体下的LocalRotation
  57. /// </summary>
  58. Quaternion q_UnderPalm;
  59. /// <summary>
  60. /// 子物体在父物体坐标系下的LocalPosition
  61. /// </summary>
  62. Vector3 p_UnderPalm;
  63. #region 双手操作
  64. /// <summary>
  65. /// 左手射线起始点在被抓物体坐标系下的坐标,用于双手操作
  66. /// </summary>
  67. static Vector3 leftRaypointInLocalSpace;
  68. /// <summary>
  69. /// 在物体被捏住的时刻,右手射线起始点向左手射线起始点做向量,用于计算两手的旋转四元数
  70. /// </summary>
  71. static Vector3 hitDirection;
  72. /// <summary>
  73. /// 在物体被捏住的时刻,物体在相机父物体下的localScale,用于双手缩放
  74. /// </summary>
  75. static Vector3 hitLocalScale;
  76. /// <summary>
  77. /// 在物体被双手捏住的时刻,双手射线起始点的距离
  78. /// </summary>
  79. static float distanceOfTwoRaypoint;
  80. #endregion
  81. // Start is called before the first frame update
  82. void Awake()
  83. {
  84. handInfo = GetComponent<HandInfo>();
  85. //显示食指指尖圆环
  86. prefab_IndexRing = ResourcesManager.Load<GameObject>("Touch/IndexRing");
  87. indexRing = Instantiate(prefab_IndexRing, transform).GetComponent<IndexRing>();
  88. indexRing.SetUp(handInfo);
  89. }
  90. private void OnDisable()
  91. {
  92. handInfo.CurCloseGrabbingTarget = null;
  93. GrabState = 0;
  94. indexRing.SetStatus(IndexRingStatus.Ring);
  95. if (handInfo.CurCloseContactingTarget != null)
  96. {
  97. handInfo.CurCloseContactingTarget = null;
  98. }
  99. }
  100. // Update is called once per frame
  101. void Update()
  102. {
  103. //当前眼镜视野中是否存在手
  104. if (handInfo.Exist)
  105. {
  106. if (handInfo.isPinching)//手指是捏合状态
  107. {
  108. switch (GrabState)
  109. {
  110. case 1://手正在触碰物体
  111. handInfo.CurCloseGrabbingTarget = touchingObj;
  112. ////如果当前握持的是普通物体,不是旋转手柄或者缩放角
  113. //if (1 << touchingObj.gameObject.layer != layerMask_Handler.value && 1 << touchingObj.gameObject.layer != layerMask_ARUI.value)
  114. {
  115. GrabState = 2;
  116. indexRing.SetStatus(IndexRingStatus.Solid);
  117. //取食指指尖位置和食指挨着指尖的关节的位置的中心为捏合点
  118. handInfo.grabLocalPoint = touchingObj.InverseTransformPoint((handInfo.GetJointData(HandJointType.Thumb_3).position + handInfo.GetJointData(HandJointType.Index_4).position) / 2.0f);
  119. //得到子物体在父物体下的LocalRotation
  120. q_UnderPalm = new Quaternion(-handInfo.palm.rotation.x, -handInfo.palm.rotation.y, -handInfo.palm.rotation.z, handInfo.palm.rotation.w) * touchingObj.rotation;
  121. //得到子物体在父物体坐标系下的LocalPosition
  122. p_UnderPalm = handInfo.palm.InverseTransformPoint(touchingObj.position);
  123. if (HandInfo.isTwoHandCloseGrabbing)
  124. {
  125. //得到左手射线点在物体坐标系下的坐标,用于物体位置的计算
  126. leftRaypointInLocalSpace = touchingObj.InverseTransformPoint(InputSystem.leftHand.rayPoint_Start);
  127. //用于双手旋转,得到物体被捏住的时刻,右手射线起始点向左手射线起始点做向量,用于计算两手的旋转四元数
  128. hitDirection = (InputSystem.leftHand.rayPoint_Start) - (InputSystem.rightHand.rayPoint_Start);
  129. //用于双手缩放,得到击中物体的localScale,后面缩放都是基于此值
  130. hitLocalScale = touchingObj.localScale;
  131. //用于双手缩放,得到物体被捏住时刻左右手射线起始点的距离,后面缩放都是基于此值
  132. distanceOfTwoRaypoint = Vector3.Distance(InputSystem.leftHand.rayPoint_Start, InputSystem.rightHand.rayPoint_Start);
  133. }
  134. }
  135. break;
  136. case 2://手正在执行拖拽
  137. ////如果当前握持的是普通物体,不是旋转手柄或者缩放角
  138. //if (1 << touchingObj.gameObject.layer != layerMask_Handler.value && 1 << touchingObj.gameObject.layer != layerMask_ARUI.value)
  139. {
  140. //双手操作:如果当前双手在操作同一个物体的话,物体的位置放在左手逻辑中来计算(避免在两个手的逻辑中各计算一次)
  141. if (HandInfo.isTwoHandCloseGrabbing)
  142. {
  143. if (handInfo.handType == HandType.Left)
  144. {
  145. //计算缩放
  146. float dis = Vector3.Distance(InputSystem.leftHand.rayPoint_Start, InputSystem.rightHand.rayPoint_Start);
  147. handInfo.CurCloseGrabbingSpatialObject.SetScale(dis / distanceOfTwoRaypoint * hitLocalScale);
  148. //计算旋转
  149. Vector3 newHitDirection = InputSystem.leftHand.rayPoint_Start - InputSystem.rightHand.rayPoint_Start;
  150. Quaternion q = Quaternion.FromToRotation(hitDirection, newHitDirection);
  151. hitDirection = newHitDirection;
  152. //设置目标物体的旋转
  153. handInfo.CurCloseGrabbingSpatialObject.SetRotation(q * touchingObj.rotation);
  154. //设置目标物体的位置(必须先计算rotation才能计算position),通过左手射线起始点的当前位置和刚捏住的时候得到的“物体坐标点到左手射线起始点的射线”来算出物体的当前坐标点
  155. handInfo.CurCloseGrabbingSpatialObject.SetPosition(InputSystem.leftHand.rayPoint_Start - (touchingObj.TransformPoint(leftRaypointInLocalSpace) - touchingObj.position));
  156. }
  157. //得到子物体在父物体下的LocalRotation
  158. q_UnderPalm = new Quaternion(-handInfo.palm.rotation.x, -handInfo.palm.rotation.y, -handInfo.palm.rotation.z, handInfo.palm.rotation.w) * touchingObj.rotation;
  159. //得到子物体在父物体坐标系下的LocalPosition
  160. p_UnderPalm = handInfo.palm.InverseTransformPoint(touchingObj.position);
  161. }
  162. else
  163. {
  164. ////给手的位置加滤波
  165. //NativeSwapManager.Point3 temp = new NativeSwapManager.Point3(handInfo.rayPoint_Start + grabOffset);
  166. //NativeSwapManager.filterPoint(ref temp, touchingObj.GetInstanceID());
  167. //Vector3 tarPos = new Vector3(temp.x, temp.y, temp.z);
  168. handInfo.CurCloseGrabbingSpatialObject.SetRotation(handInfo.palm.rotation * q_UnderPalm);
  169. handInfo.CurCloseGrabbingSpatialObject.SetPosition(handInfo.palm.position + handInfo.palm.rotation * p_UnderPalm);
  170. }
  171. }
  172. break;
  173. }
  174. }
  175. else
  176. {
  177. //Debug.Log("HandTouch - handInfo.isPinching: " + handInfo.isPinching + ", " + grabState);
  178. //根据拇指食指触碰物体的情况来决定圆环的显示与否
  179. indexRing.gameObject.SetActive(handInfo.preCloseContacting | handInfo.IsCloseContacting);
  180. handInfo.CurCloseGrabbingTarget = null;
  181. if (GrabState == 2)
  182. {
  183. //Debug.Log("HandTouch - grabState: " + grabState);
  184. GrabState = 0;
  185. indexRing.SetStatus(IndexRingStatus.Ring);
  186. touchingObj = null;
  187. }
  188. //if (handInfo.CurCloseContactingTarget == null)
  189. //{
  190. // handInfo.isCloseContacting = false;
  191. //}
  192. }
  193. }
  194. else
  195. {
  196. OnDisable();
  197. }
  198. }
  199. public void ForOnTriggerEnter(Collider other)
  200. {
  201. ForOnTriggerStay(other);
  202. }
  203. public void ForOnTriggerStay(Collider other)
  204. {
  205. if (enabled && !handInfo.isPinching)
  206. {
  207. GrabState = 1;
  208. indexRing.SetStatus(IndexRingStatus.Ring);
  209. touchingObj = other.transform;
  210. }
  211. }
  212. public void ForOnTriggerExit(Collider other)
  213. {
  214. if (enabled && !handInfo.isPinching)
  215. {
  216. handInfo.CurCloseGrabbingTarget = null;
  217. GrabState = 0;
  218. indexRing.SetStatus(IndexRingStatus.Ring);
  219. touchingObj = null;
  220. }
  221. }
  222. }
  223. }