HandInfo.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. using EZXR.Glass.Core;
  2. using EZXR.Glass.SixDof;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. using Wheels.Unity;
  8. namespace EZXR.Glass.Inputs
  9. {
  10. public enum GestureType
  11. {
  12. Unknown = -1,
  13. OpenHand = 0,
  14. Grab,
  15. Pinch,
  16. Point,
  17. Victory,
  18. Call,
  19. }
  20. public enum HandJointType
  21. {
  22. Thumb_0,
  23. Thumb_1,
  24. Thumb_2,
  25. /// <summary>
  26. /// 拇指尖
  27. /// </summary>
  28. Thumb_3,
  29. /// <summary>
  30. /// 食指根节点
  31. /// </summary>
  32. Index_1,
  33. Index_2,
  34. Index_3,
  35. /// <summary>
  36. /// 食指尖
  37. /// </summary>
  38. Index_4,
  39. /// <summary>
  40. /// 中指根节点
  41. /// </summary>
  42. Middle_1,
  43. Middle_2,
  44. Middle_3,
  45. /// <summary>
  46. /// 中指指尖
  47. /// </summary>
  48. Middle_4,
  49. Ring_1,
  50. Ring_2,
  51. Ring_3,
  52. /// <summary>
  53. /// 无名指指尖
  54. /// </summary>
  55. Ring_4,
  56. Pinky_0,
  57. /// <summary>
  58. /// 小指根节点
  59. /// </summary>
  60. Pinky_1,
  61. Pinky_2,
  62. Pinky_3,
  63. /// <summary>
  64. /// 小指指尖
  65. /// </summary>
  66. Pinky_4,
  67. /// <summary>
  68. /// 掌心点
  69. /// </summary>
  70. Palm,
  71. /// <summary>
  72. /// 手腕横切线,靠近拇指根节点的点
  73. /// </summary>
  74. Wrist_Thumb,
  75. /// <summary>
  76. /// 手腕横切线,靠近小指根节点的点
  77. /// </summary>
  78. Wrist_Pinky,
  79. /// <summary>
  80. /// 手腕横切线,中点
  81. /// </summary>
  82. Wrist_Middle,
  83. }
  84. /// <summary>
  85. /// 包含单个手的各种状态信息,是个基础信息类,供其他类进行状态获取和协同
  86. /// </summary>
  87. [ScriptExecutionOrder(-48)]
  88. public class HandInfo : InputInfoBase
  89. {
  90. /// <summary>
  91. /// 手的所有关节等物体的父节点
  92. /// </summary>
  93. public Transform root
  94. {
  95. get
  96. {
  97. return transform;
  98. }
  99. }
  100. HandVisualization handVisualization;
  101. HandsVisualizationForModel handsVisualizationForModel;
  102. InputRaycast handRaycast;
  103. HandTouch handTouch;
  104. HandCollision handCollision;
  105. /// <summary>
  106. /// 初始化,设置当前HandInfo所属的手是左手还是右手
  107. /// </summary>
  108. /// <param name="handType">0为左手,1为右手</param>
  109. public override void Init(HandType handType)
  110. {
  111. base.Init(handType);
  112. handVisualization = GetComponent<HandVisualization>();
  113. handsVisualizationForModel = GetComponent<HandsVisualizationForModel>();
  114. handRaycast = GetComponent<InputRaycast>();
  115. handTouch = GetComponent<HandTouch>();
  116. handCollision = GetComponent<HandCollision>();
  117. //设定肩部点,用于射线计算
  118. shoulderPoint = new Vector3(handType == HandType.Left ? -0.15f : 0.15f, -0.15f, -0.1f);
  119. palm = new GameObject("Palm").transform;
  120. palm.parent = transform;
  121. }
  122. public void UpdateHandInfoData(NativeSwapManager.HandTrackingData handTrackingData)
  123. {
  124. this.handTrackingData = handTrackingData;
  125. if (handTrackingData.handJointData != null)
  126. {
  127. Pose pose;
  128. for (int i = 0; i < handTrackingData.handJointData.Length; i++)
  129. {
  130. NativeSwapManager.Mat4f mat4 = handTrackingData.handJointData[i].handJointPose;
  131. Matrix4x4 m = new Matrix4x4();
  132. m.SetColumn(0, new Vector4(mat4.col0.x, mat4.col0.y, mat4.col0.z, mat4.col0.w));
  133. m.SetColumn(1, new Vector4(mat4.col1.x, mat4.col1.y, mat4.col1.z, mat4.col1.w));
  134. m.SetColumn(2, new Vector4(mat4.col2.x, mat4.col2.y, mat4.col2.z, mat4.col2.w));
  135. m.SetColumn(3, new Vector4(mat4.col3.x, mat4.col3.y, mat4.col3.z, mat4.col3.w));
  136. if (!m.ValidTRS())
  137. {
  138. return;
  139. }
  140. pose.rotation = m.rotation;// XRMan.Instance == null ? m.rotation : (XRMan.Instance.transform.rotation * m.rotation);
  141. Vector3 pos = m.GetColumn(3);
  142. pose.position = pos;// XRMan.Instance == null ? pos : (XRMan.Instance.transform.TransformPoint(pos));
  143. HandJointType handJointType = (HandJointType)i;
  144. if (jointsPose.ContainsKey(handJointType))
  145. {
  146. jointsPose[handJointType] = pose;
  147. }
  148. else
  149. {
  150. jointsPose.Add(handJointType, pose);
  151. }
  152. }
  153. }
  154. }
  155. protected override void Update()
  156. {
  157. if (Exist)
  158. {
  159. UpdatePinching();
  160. palm.position = GetJointData(HandJointType.Palm).position;
  161. palm.rotation = GetJointData(HandJointType.Palm).rotation;
  162. //掌心面向的方向
  163. palmNormal = GetJointData(HandJointType.Palm).TransformDirection(Vector3.forward);
  164. //手掌指尖朝向
  165. palmDirection = GetJointData(HandJointType.Palm).TransformDirection(Vector3.up);
  166. //射线方向
  167. if (!(ARHandManager.SetRayDirByExternal != null && ARHandManager.SetRayDirByExternal(this, ref rayDirection)))
  168. {
  169. rayDirection = (GetJointData(HandJointType.Index_1).position - ARHandManager.head.TransformPoint(shoulderPoint)).normalized;
  170. }
  171. //射线起点
  172. if (!(ARHandManager.SetRayStartPointByExternal != null && ARHandManager.SetRayStartPointByExternal(this, ref rayPoint_Start)))
  173. {
  174. rayPoint_Start = GetJointData(HandJointType.Index_1).position + rayDirection * rayStartDistance;
  175. }
  176. ////用于双手操作,得到左手加滤波之后的掌心点位置
  177. //NativeSwapManager.Point3 temp = new NativeSwapManager.Point3(rayPoint_Start);
  178. //NativeSwapManager.filterPoint(ref temp, transform.GetInstanceID());
  179. //Vector3 tarPos = new Vector3(temp.x, temp.y, temp.z);
  180. //rayPoint_Start_Left = tarPos;
  181. //从算法得到的预估的射线终点位置
  182. //rayPoint_End = new Vector3(ray[1].x, Main.ray[1].y, ray[1].z);
  183. }
  184. }
  185. protected override void UpdatePinching()
  186. {
  187. bool curPinchState = handTrackingData.isTracked && (handTrackingData.gestureType == GestureType.Pinch || handTrackingData.gestureType == GestureType.Grab);
  188. if (isPinching)
  189. {
  190. if (curPinchState)
  191. {
  192. startPinch = false;
  193. }
  194. else
  195. {
  196. endPinch = true;
  197. }
  198. }
  199. else
  200. {
  201. if (curPinchState)
  202. {
  203. startPinch = true;
  204. }
  205. else
  206. {
  207. endPinch = false;
  208. }
  209. }
  210. isPinching = curPinchState;
  211. }
  212. #region 手交互能力开关
  213. /// <summary>
  214. /// 设置或获得当前手的显示状态(仅仅影响显示,并不影响交互)
  215. /// </summary>
  216. public override bool Visibility
  217. {
  218. get
  219. {
  220. return handsVisualizationForModel ? handsVisualizationForModel.Visibility : false;
  221. }
  222. set
  223. {
  224. if (handsVisualizationForModel != null)
  225. {
  226. handsVisualizationForModel.Visibility = value;
  227. }
  228. }
  229. }
  230. /// <summary>
  231. /// 设置或获得远距离射线交互状态
  232. /// </summary>
  233. public override bool RaycastInteraction
  234. {
  235. get
  236. {
  237. return handRaycast ? handRaycast.enabled : false;
  238. }
  239. set
  240. {
  241. if (handRaycast != null)
  242. {
  243. handRaycast.enabled = value;
  244. }
  245. }
  246. }
  247. /// <summary>
  248. /// 设置或获得近距离交互状态
  249. /// </summary>
  250. public override bool TouchInteraction
  251. {
  252. get
  253. {
  254. return handTouch ? handTouch.enabled : false;
  255. }
  256. set
  257. {
  258. if (handTouch != null)
  259. {
  260. handTouch.enabled = value;
  261. }
  262. }
  263. }
  264. /// <summary>
  265. /// 设置或获得手部的物理碰撞交互状态
  266. /// </summary>
  267. public override bool PhysicsInteraction
  268. {
  269. get
  270. {
  271. return handCollision ? handCollision.enabled : false;
  272. }
  273. set
  274. {
  275. if (handCollision != null)
  276. {
  277. handCollision.enabled = value;
  278. }
  279. }
  280. }
  281. #endregion
  282. #region 单手信息
  283. /// <summary>
  284. /// 当前手节点是否在视野内
  285. /// </summary>
  286. /// <param name="jointType"></param>
  287. /// <returns></returns>
  288. public bool InView(HandJointType jointType)
  289. {
  290. if (Application.isEditor)
  291. {
  292. Vector3 viewportPoint = HMDPoseTracker.Instance.centerCamera.WorldToViewportPoint(GetJointData(jointType).position);
  293. //Debug.Log(viewportPoint.ToString("0.##"));
  294. return viewportPoint.x > 0 && viewportPoint.x < 1 && viewportPoint.y > 0 && viewportPoint.y < 1 && viewportPoint.z > 0;
  295. }
  296. else
  297. {
  298. Vector3 viewportPoint_L = HMDPoseTracker.Instance.leftCamera.WorldToViewportPoint(GetJointData(jointType).position);
  299. Vector3 viewportPoint_R = HMDPoseTracker.Instance.rightCamera.WorldToViewportPoint(GetJointData(jointType).position);
  300. 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);
  301. }
  302. }
  303. public bool InLeftView(HandJointType jointType)
  304. {
  305. Vector3 viewportPoint_L = HMDPoseTracker.Instance.leftCamera.WorldToViewportPoint(GetJointData(jointType).position);
  306. return (viewportPoint_L.x > 0 && viewportPoint_L.x < 1 && viewportPoint_L.y > 0 && viewportPoint_L.y < 1 && viewportPoint_L.z > 0);
  307. }
  308. public bool InRightView(HandJointType jointType)
  309. {
  310. Vector3 viewportPoint_R = HMDPoseTracker.Instance.rightCamera.WorldToViewportPoint(GetJointData(jointType).position);
  311. return (viewportPoint_R.x > 0 && viewportPoint_R.x < 1 && viewportPoint_R.y > 0 && viewportPoint_R.y < 1 && viewportPoint_R.z > 0);
  312. }
  313. /// <summary>
  314. /// 当前眼镜视野中是否存在这个手
  315. /// </summary>
  316. public override bool Exist
  317. {
  318. get
  319. {
  320. return handTrackingData.isTracked;
  321. }
  322. }
  323. /// <summary>
  324. /// 手掌正在朝向头部,如果手掌朝向和手掌与头的连线的夹角小于angle则认为手掌是朝向了头部
  325. /// </summary>
  326. /// <param name="angle">默认90</param>
  327. /// <returns></returns>
  328. public override bool isPalmFacingHead(float angle = 90)
  329. {
  330. Pose palm = GetJointData(HandJointType.Palm);
  331. Vector3 palmNormal = palm.TransformDirection(Vector3.forward * 0.1f);
  332. Vector3 palmToHead = HMDPoseTracker.Instance.Head.position - palm.position;
  333. //求palmNormal和palmToHead的夹角
  334. float includedAngle = Vector3.Angle(palmNormal, palmToHead);
  335. if (includedAngle < angle)
  336. {
  337. return true;
  338. }
  339. else
  340. {
  341. return false;
  342. }
  343. }
  344. /// <summary>
  345. /// 从算法得到的此手的原始关节点数据,单位为mm
  346. /// </summary>
  347. public NativeSwapManager.HandTrackingData handTrackingData = new NativeSwapManager.HandTrackingData();
  348. /// <summary>
  349. /// 自行定义的一个肩部点,相对于头部坐标系的
  350. /// </summary>
  351. Vector3 shoulderPoint;
  352. /// <summary>
  353. /// 手的动作
  354. /// </summary>
  355. public GestureType gestureType
  356. {
  357. get
  358. {
  359. return handTrackingData.gestureType;
  360. }
  361. }
  362. /// <summary>
  363. /// 所有手指关节点的Pose
  364. /// </summary>
  365. public Dictionary<HandJointType, Pose> jointsPose = new Dictionary<HandJointType, Pose>();
  366. /// <summary>
  367. /// 手掌面向的方向
  368. /// </summary>
  369. [HideInInspector]
  370. public Vector3 palmNormal;
  371. /// <summary>
  372. /// 手掌指尖朝向(从手腕点到中指和无名指根节点中间点的朝向,世界坐标系)
  373. /// </summary>
  374. [HideInInspector]
  375. public Vector3 palmDirection;
  376. [HideInInspector]
  377. public Transform palm;
  378. public bool JointDataExist(HandJointType handJointType)
  379. {
  380. return jointsPose.ContainsKey(handJointType);
  381. }
  382. public Pose GetJointData(HandJointType handJointType)
  383. {
  384. if (jointsPose.ContainsKey(handJointType))
  385. {
  386. return jointsPose[handJointType];
  387. }
  388. return Pose.identity;
  389. }
  390. public Pose GetJointData(int handJointTypeID)
  391. {
  392. return GetJointData((HandJointType)handJointTypeID);
  393. }
  394. #endregion
  395. #region 当前预触碰的物体信息
  396. /// <summary>
  397. /// 在手的近距离交互预判区内是否存在物体,只是在手的触发区域内但是还没有碰到食指指尖(主要用于避免在手即将触摸到旋转握把的时候会出现射线射到另外一个握把或者缩放角)
  398. /// </summary>
  399. [HideInInspector]
  400. public bool preCloseContacting;
  401. /// <summary>
  402. /// 手部近距离交互预判区(TriggerForFarNearSwitch中定义区域大小,此区域内则认为用户要近距离抓取)内存在的距离最近的物体
  403. /// </summary>
  404. Transform preCloseContactingTarget;
  405. /// <summary>
  406. /// 手部近距离交互预判区内存在的距离最近的物体
  407. /// </summary>
  408. public Transform PreCloseContactingTarget
  409. {
  410. get
  411. {
  412. return preCloseContactingTarget;
  413. }
  414. set
  415. {
  416. //if (preCloseContactingTarget != value)
  417. {
  418. //记录上一帧食指指尖的近距离交互预判区内存在的距离最近的物体
  419. Last_PreCloseContactingTarget = preCloseContactingTarget;
  420. preCloseContactingTarget = value;
  421. preCloseContactingTarget_Renderer = (preCloseContactingTarget == null ? null : preCloseContactingTarget.GetComponent<Renderer>());
  422. if (preCloseContactingTarget_Renderer != null)
  423. {
  424. if (preCloseContactingTarget_PropertyBlock == null)
  425. {
  426. preCloseContactingTarget_PropertyBlock = new MaterialPropertyBlock();
  427. }
  428. preCloseContactingTarget_Renderer.GetPropertyBlock(preCloseContactingTarget_PropertyBlock);
  429. }
  430. if (preCloseContactingTarget == null)
  431. {
  432. preCloseContacting = false;
  433. }
  434. else
  435. {
  436. preCloseContacting = true;
  437. }
  438. }
  439. }
  440. }
  441. [HideInInspector]
  442. public Renderer preCloseContactingTarget_Renderer;
  443. [HideInInspector]
  444. public MaterialPropertyBlock preCloseContactingTarget_PropertyBlock;
  445. /// <summary>
  446. /// 上一帧手部近距离交互预判区内存在的距离最近的物体
  447. /// </summary>
  448. Transform last_PreCloseContactingTarget;
  449. /// <summary>
  450. /// 上一帧手部近距离交互预判区内存在的距离最近的物体
  451. /// </summary>
  452. public Transform Last_PreCloseContactingTarget
  453. {
  454. get
  455. {
  456. return last_PreCloseContactingTarget;
  457. }
  458. set
  459. {
  460. if (last_PreCloseContactingTarget != value)
  461. {
  462. last_PreCloseContactingTarget = value;
  463. last_PreCloseContactingTarget_Renderer = (last_PreCloseContactingTarget == null ? null : last_PreCloseContactingTarget.GetComponent<Renderer>());
  464. if (last_PreCloseContactingTarget_Renderer != null)
  465. {
  466. if (last_PreCloseContactingTarget_PropertyBlock == null)
  467. {
  468. last_PreCloseContactingTarget_PropertyBlock = new MaterialPropertyBlock();
  469. }
  470. last_PreCloseContactingTarget_Renderer.GetPropertyBlock(last_PreCloseContactingTarget_PropertyBlock);
  471. }
  472. }
  473. }
  474. }
  475. [HideInInspector]
  476. public Renderer last_PreCloseContactingTarget_Renderer;
  477. [HideInInspector]
  478. public MaterialPropertyBlock last_PreCloseContactingTarget_PropertyBlock;
  479. #endregion
  480. #region 当前正在触碰的物体信息
  481. protected bool isCloseContacting;
  482. /// <summary>
  483. /// 指示手是否正在近距离触碰某个物体(被拇指和食指指尖的连线穿过)
  484. /// </summary>
  485. public bool IsCloseContacting
  486. {
  487. get
  488. {
  489. return isCloseContacting;
  490. }
  491. set
  492. {
  493. isCloseContacting = value;
  494. }
  495. }
  496. Collider curCloseContactingTarget;
  497. /// <summary>
  498. /// 当前正在被近距离触碰的物体
  499. /// </summary>
  500. public Collider CurCloseContactingTarget
  501. {
  502. get
  503. {
  504. return curCloseContactingTarget;
  505. }
  506. set
  507. {
  508. if (curCloseContactingTarget != null && value != null)
  509. {
  510. if (curCloseContactingTarget != value)
  511. {
  512. SpatialObject.PerformOnHandTriggerExit(curCloseContactingTarget);
  513. SpatialObject.PerformOnHandTriggerEnter(curCloseContactingTarget);
  514. }
  515. else
  516. {
  517. SpatialObject.PerformOnHandTriggerStay(value);
  518. }
  519. }
  520. else if (curCloseContactingTarget == null && value != null)
  521. {
  522. SpatialObject.PerformOnHandTriggerEnter(value);
  523. }
  524. else if (curCloseContactingTarget != null && value == null)
  525. {
  526. SpatialObject.PerformOnHandTriggerExit(curCloseContactingTarget);
  527. }
  528. curCloseContactingTarget = value;
  529. if (curCloseContactingTarget == null)
  530. {
  531. IsCloseContacting = false;
  532. }
  533. else
  534. {
  535. IsCloseContacting = true;
  536. }
  537. }
  538. }
  539. /// <summary>
  540. /// 指示手是否正在近距离触碰某个物体或者射线是否正射在某个物体上
  541. /// </summary>
  542. public bool IsContacting
  543. {
  544. get
  545. {
  546. return IsCloseContacting | isRayContacting;
  547. }
  548. }
  549. /// <summary>
  550. /// 当前正在被触碰的物体(无论射线还是近距离)
  551. /// </summary>
  552. public Collider CurContactingTarget
  553. {
  554. get
  555. {
  556. if (CurCloseContactingTarget == null)
  557. {
  558. if (curRayContactingTarget != null)
  559. {
  560. return curRayContactingTarget;
  561. }
  562. }
  563. else
  564. {
  565. return CurCloseContactingTarget;
  566. }
  567. return null;
  568. }
  569. }
  570. #endregion
  571. }
  572. }