GazeInputModule.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. // The MIT License (MIT)
  2. // Copyright 2016 Nibiru. All rights reserved.
  3. // Copyright (c) 2015, Unity Technologies & Google, Inc.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. using NibiruAxis;
  23. using NibiruTask;
  24. using System.Collections.Generic;
  25. using UnityEngine;
  26. using UnityEngine.EventSystems;
  27. using UnityEngine.UI;
  28. /// This script provides an implemention of Unity's `BaseInputModule` class, so
  29. /// that Canvas-based (_uGUI_) UI elements can be selected by looking at them and
  30. /// pulling the viewer's trigger or touching the screen.
  31. /// This uses the player's gaze and the trigger as a raycast generator.
  32. ///
  33. /// To use, attach to the scene's **EventSystem** object. Be sure to move it above the
  34. /// other modules, such as _TouchInputModule_ and _StandaloneInputModule_, in order
  35. /// for the user's gaze to take priority in the event system.
  36. ///
  37. /// Next, set the **Canvas** object's _Render Mode_ to **World Space**, and set its _Event Camera_
  38. /// to a (mono) camera that is controlled by a NxrHead. If you'd like gaze to work
  39. /// with 3D scene objects, add a _PhysicsRaycaster_ to the gazing camera, and add a
  40. /// component that implements one of the _Event_ interfaces (_EventTrigger_ will work nicely).
  41. /// The objects must have colliders too.
  42. ///
  43. /// GazeInputModule emits the following events: _Enter_, _Exit_, _Down_, _Up_, _Click_, _Select_,
  44. /// _Deselect_, and _UpdateSelected_. Scroll, move, and submit/cancel events are not emitted.
  45. namespace Nxr.Internal
  46. {
  47. [AddComponentMenu("NXR/GazeInputModule")]
  48. public class GazeInputModule : BaseInputModule
  49. {
  50. public static List<NxrUIPointer> pointers = new List<NxrUIPointer>();
  51. public static void AddPoint(NxrUIPointer point)
  52. {
  53. if (!pointers.Contains(point))
  54. pointers.Add(point);
  55. }
  56. public static void RemovePoint(NxrUIPointer point)
  57. {
  58. if (pointers.Contains(point))
  59. pointers.Remove(point);
  60. }
  61. private static Vector3 raycastResultPosition = Vector3.zero;
  62. public static Vector3 GetRaycastResultPosition()
  63. {
  64. return raycastResultPosition;
  65. }
  66. /// Determines whether gaze input is active in AR Mode only (`true`), or all of the
  67. /// time (`false`). Set to false if you plan to use direct screen taps or other
  68. /// input when not in Split Mode.
  69. [Tooltip("Whether gaze input is active in Split Mode only (true), or all the time (false).")]
  70. private bool splitModeOnly = false;
  71. /// The INxrGazePointer which will be responding to gaze events.
  72. public static INxrGazePointer gazePointer;
  73. private PointerEventData pointerData;
  74. private Vector2 lastHeadPose;
  75. // Active state
  76. private bool isActive = false;
  77. /// Time in seconds between the pointer down and up events sent by a trigger.
  78. /// Allows time for the UI elements to make their state transitions.
  79. private const float clickTime = 0.1f; // Based on default time for a button to animate to Pressed.
  80. private Vector2 screenCenterVec = Vector2.zero;
  81. bool isShowGaze = true;
  82. /// @cond
  83. public override bool ShouldActivateModule()
  84. {
  85. bool activeState = base.ShouldActivateModule();
  86. // AR模式 或者 splitMoreOnly关闭
  87. activeState = activeState && (NxrViewer.Instance.SplitScreenModeEnabled || !splitModeOnly);
  88. if (activeState != isActive)
  89. {
  90. isActive = activeState;
  91. // Activate gaze pointer
  92. if (gazePointer != null)
  93. {
  94. if (isActive)
  95. {
  96. gazePointer.OnGazeEnabled();
  97. }
  98. }
  99. }
  100. return activeState;
  101. }
  102. /// @endcond
  103. public override void DeactivateModule()
  104. {
  105. Debug.Log("DeactivateModule");
  106. DisableGazePointer();
  107. base.DeactivateModule();
  108. if (pointerData != null)
  109. {
  110. HandlePendingClick();
  111. HandlePointerExitAndEnter(pointerData, null);
  112. pointerData = null;
  113. }
  114. eventSystem.SetSelectedGameObject(null, pointerData);
  115. Debug.Log("DeactivateModule");
  116. }
  117. private void OnApplicationFocus(bool focus)
  118. {
  119. if (focus)
  120. {
  121. NxrViewer.Instance.Triggered = false;
  122. if (pointerData != null && pointerData.selectedObject != null)
  123. {
  124. HandlePointerExitAndEnter(pointerData, null);
  125. eventSystem.SetSelectedGameObject(null, pointerData);
  126. pointerData.Reset();
  127. }
  128. }
  129. }
  130. public override bool IsPointerOverGameObject(int pointerId)
  131. {
  132. return pointerData != null && pointerData.pointerEnter != null;
  133. }
  134. public override void Process()
  135. {
  136. //when ime show unity is still running, disable input process
  137. if (TouchScreenKeyboard.visible)
  138. {
  139. NxrViewer.Instance.Triggered = false;
  140. pointerData.eligibleForClick = false;
  141. return;
  142. }
  143. #if UNITY_ANDROID && !ANDROID_REMOTE_NRR
  144. if ((NxrPlayerCtrl.Instance.GamepadEnabled && NibiruTaskApi.IsQuatConn()) || ControllerAndroid.IsNoloConn())
  145. #elif UNITY_STANDALONE_WIN || ANDROID_REMOTE_NRR
  146. if (NxrControllerHelper.IsLeftNoloControllerConnected || NxrControllerHelper.IsRightNoloControllerConnected)
  147. {
  148. CastRayFromController(true);
  149. if (isShowGaze)
  150. {
  151. NxrViewer.Instance.GazeApi(GazeTag.Hide, "");
  152. isShowGaze = false;
  153. }
  154. }
  155. else if (NxrControllerHelper.Is3DofControllerConnected)
  156. #else
  157. if(true)
  158. #endif
  159. {
  160. // 3dof/6dof controller
  161. CastRayFromGamepad();
  162. if (isShowGaze)
  163. {
  164. NxrViewer.Instance.SwitchControllerMode(true);
  165. isShowGaze = false;
  166. }
  167. }
  168. else
  169. {
  170. if (!isShowGaze)
  171. {
  172. NxrViewer.Instance.SwitchControllerMode(false);
  173. isShowGaze = true;
  174. pointerData.pointerPress = null;
  175. HandlePointerExitAndEnter(pointerData, null);
  176. }
  177. // Save the previous Game Object
  178. GameObject gazeObjectPrevious = GetCurrentGameObject();
  179. CastRayFromGaze();
  180. UpdateCurrentObject();
  181. UpdateReticle(gazeObjectPrevious);
  182. }
  183. if (!pointerData.eligibleForClick && NxrViewer.Instance.Triggered)
  184. {
  185. // New trigger action. ok键->click
  186. HandleTrigger();
  187. NxrViewer.Instance.Triggered = false;
  188. }
  189. else if (!NxrViewer.Instance.Triggered)
  190. {
  191. // Check if there is a pending click to handle.
  192. HandlePendingClick();
  193. }
  194. else if (pointerData.eligibleForClick && NxrViewer.Instance.Triggered)
  195. {
  196. NxrViewer.Instance.Triggered = false;
  197. }
  198. SetRaycastResultPosition();
  199. }
  200. /// @endcond
  201. private void CastRayFromController(bool isNolo)
  202. {
  203. if (pointerData == null)
  204. {
  205. pointerData = new PointerEventData(eventSystem);
  206. }
  207. // Cast a ray into the scene
  208. pointerData.Reset();
  209. GameObject gameObject = isNolo ? NxrControllerHelper.ControllerRaycastObject : null;
  210. if (gameObject != null)
  211. {
  212. pointerData.pointerPress = gameObject;
  213. RaycastResult raycastResult = new RaycastResult();
  214. raycastResult.gameObject = gameObject;
  215. pointerData.pointerCurrentRaycast = raycastResult;
  216. HandlePointerExitAndEnter(pointerData, gameObject);
  217. }
  218. else
  219. {
  220. RaycastResult raycastResult = new RaycastResult();
  221. raycastResult.gameObject = null;
  222. pointerData.pointerCurrentRaycast = raycastResult;
  223. pointerData.pointerPress = null;
  224. HandlePointerExitAndEnter(pointerData, null);
  225. }
  226. }
  227. private void CastRayFromGamepad()
  228. {
  229. if (pointerData == null)
  230. {
  231. pointerData = new PointerEventData(eventSystem);
  232. }
  233. // Cast a ray into the scene
  234. pointerData.Reset();
  235. bool IsUICanvasObject = NxrControllerHelper.ControllerRaycastObject != null &&
  236. NxrControllerHelper.ControllerRaycastObject.GetComponent<NxrUICanvas>() != null;
  237. if (IsUICanvasObject)
  238. {
  239. for (int i = 0; i < pointers.Count; i++)
  240. {
  241. NxrUIPointer pointer = pointers[i];
  242. if (pointer.gameObject.activeInHierarchy && pointer.enabled && pointer.IsShow())
  243. {
  244. var raycastResult = new RaycastResult();
  245. raycastResult.worldPosition = pointer.transform.position;
  246. raycastResult.worldNormal = pointer.transform.forward;
  247. // pointerData.position = new Vector2(0.5f * Screen.width, 0.5f * Screen.height);
  248. pointerData.pointerCurrentRaycast = raycastResult;
  249. eventSystem.RaycastAll(pointerData, m_RaycastResultCache);
  250. if (m_RaycastResultCache.Count > 1)
  251. {
  252. if (m_RaycastResultCache[0].gameObject.GetComponent<Canvas>())
  253. {
  254. var raycastResultCache = m_RaycastResultCache[0];
  255. m_RaycastResultCache.RemoveAt(0);
  256. m_RaycastResultCache.Add(raycastResultCache);
  257. }
  258. }
  259. pointerData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
  260. if (m_RaycastResultCache.Count > 0)
  261. {
  262. HandlePointerExitAndEnter(pointerData, pointerData.pointerCurrentRaycast.gameObject);
  263. }
  264. else
  265. {
  266. HandlePointerExitAndEnter(pointerData, null);
  267. }
  268. m_RaycastResultCache.Clear();
  269. }
  270. }
  271. }
  272. else
  273. {
  274. pointerData.pointerPress = NxrControllerHelper.ControllerRaycastObject;
  275. RaycastResult raycastResult = new RaycastResult();
  276. raycastResult.gameObject = NxrControllerHelper.ControllerRaycastObject;
  277. pointerData.pointerCurrentRaycast = raycastResult;
  278. HandlePointerExitAndEnter(pointerData, NxrControllerHelper.ControllerRaycastObject);
  279. }
  280. if (pointerData.pointerCurrentRaycast.gameObject == null && eventSystem.currentSelectedGameObject != null)
  281. {
  282. Debug.LogError("Clear Seleted GameObject-Controller=>" + eventSystem.currentSelectedGameObject.name);
  283. eventSystem.SetSelectedGameObject(null);
  284. }
  285. }
  286. /// <summary>
  287. /// Search min index (gameobject is not ui canvas)
  288. /// </summary>
  289. /// <param name="candidates"></param>
  290. /// <returns></returns>
  291. protected static RaycastResult FindFirstRaycastCore(List<RaycastResult> candidates)
  292. {
  293. if (NibiruRemindBox.Instance.Showing())
  294. {
  295. float minDistance = 9999;
  296. int listIndex = candidates.Count + 1;
  297. for (int index = 0; index < candidates.Count; ++index)
  298. {
  299. if (!((UnityEngine.Object) candidates[index].gameObject == (UnityEngine.Object) null))
  300. {
  301. bool IsUICanvasObject = candidates[index].gameObject != null &&
  302. candidates[index].gameObject.GetComponent<NxrUICanvas>() != null;
  303. if (!IsUICanvasObject && candidates[index].distance <= minDistance)
  304. {
  305. minDistance = candidates[index].distance;
  306. listIndex = index;
  307. }
  308. }
  309. }
  310. if (listIndex < candidates.Count) return candidates[listIndex];
  311. }
  312. else
  313. {
  314. return FindFirstRaycast(candidates);
  315. }
  316. return new RaycastResult();
  317. }
  318. private bool isSpecial;
  319. private void CastRayFromGaze()
  320. {
  321. Vector2 headPose =
  322. NormalizedCartesianToSpherical(NxrViewer.Instance.HeadPose.Orientation * Vector3.forward);
  323. if (pointerData == null)
  324. {
  325. pointerData = new PointerEventData(eventSystem);
  326. lastHeadPose = headPose;
  327. }
  328. Vector2 diff = headPose - lastHeadPose;
  329. if (screenCenterVec.x == 0)
  330. {
  331. screenCenterVec = new Vector2(0.5f * Screen.width, 0.5f * Screen.height);
  332. }
  333. // Cast a ray into the scene
  334. pointerData.Reset();
  335. var raycastResult = new RaycastResult();
  336. raycastResult.Clear();
  337. Transform mTrans = NxrViewer.Instance.GetHead().GetTransform();
  338. raycastResult.worldPosition = mTrans.position;
  339. raycastResult.worldNormal = mTrans.forward;
  340. pointerData.pointerCurrentRaycast = raycastResult;
  341. pointerData.position = new Vector2(0.5f * Screen.width, 0.5f * Screen.height);
  342. eventSystem.RaycastAll(pointerData, m_RaycastResultCache);
  343. foreach (var mRaycastResult in m_RaycastResultCache)
  344. {
  345. if (mRaycastResult.gameObject.layer == 8)
  346. {
  347. pointerData.pointerCurrentRaycast = mRaycastResult;
  348. isSpecial = true;
  349. break;
  350. }
  351. }
  352. if (!isSpecial)
  353. {
  354. pointerData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
  355. foreach (RaycastResult mRaycastResult in m_RaycastResultCache)
  356. {
  357. bool IsUICanvasObject = mRaycastResult.gameObject != null &&
  358. mRaycastResult.gameObject.GetComponent<NxrUICanvas>() != null;
  359. if (!IsUICanvasObject)
  360. {
  361. pointerData.pointerCurrentRaycast = mRaycastResult;
  362. break;
  363. }
  364. }
  365. }
  366. isSpecial = false;
  367. m_RaycastResultCache.Clear();
  368. pointerData.delta = diff;
  369. lastHeadPose = headPose;
  370. if (pointerData.pointerCurrentRaycast.gameObject == null && eventSystem.currentSelectedGameObject != null)
  371. {
  372. Debug.LogError("Clear Seleted GameObject-Gaze=>" + eventSystem.currentSelectedGameObject.name);
  373. eventSystem.SetSelectedGameObject(null);
  374. }
  375. }
  376. private void SetRaycastResultPosition()
  377. {
  378. if (pointerData != null && pointerData.pointerCurrentRaycast.gameObject)
  379. {
  380. raycastResultPosition = pointerData.pointerCurrentRaycast.worldPosition;
  381. }
  382. else
  383. {
  384. raycastResultPosition = Vector3.zero;
  385. }
  386. }
  387. private void UpdateCurrentObject()
  388. {
  389. if (pointerData == null)
  390. {
  391. return;
  392. }
  393. // Send enter events and update the highlight.
  394. var go = pointerData.pointerCurrentRaycast.gameObject;
  395. HandlePointerExitAndEnter(pointerData, go);
  396. }
  397. float lastGazeZ = 0;
  398. void UpdateReticle(GameObject previousGazedObject)
  399. {
  400. if (pointerData == null)
  401. {
  402. return;
  403. }
  404. Camera camera = pointerData.enterEventCamera; // Get the camera
  405. Vector3 intersectionPosition = GetIntersectionPosition();
  406. GameObject gazeObject = GetCurrentGameObject(); // Get the gaze target
  407. if (gazeObject != null && NxrOverrideSettings.OnGazeEvent != null)
  408. {
  409. NxrOverrideSettings.OnGazeEvent(gazeObject);
  410. }
  411. float gazeZ = NxrGlobal.defaultGazeDistance;
  412. if (gazeObject != null)
  413. {
  414. gazeZ = intersectionPosition
  415. .z; // && gazeObject.transform != null &&gazeObject.transform.position.z != 0gazeObject.transform.position.z;
  416. }
  417. if (lastGazeZ != gazeZ)
  418. {
  419. lastGazeZ = gazeZ;
  420. // 点
  421. NxrViewer.Instance.GazeApi(Nxr.Internal.GazeTag.Set_Distance, (-1 * gazeZ).ToString());
  422. }
  423. // Debug.Log("--------gaze object " + (gazeObject == null ? "" : gazeObject.name));
  424. // 记录距离
  425. NxrGlobal.focusObjectDistance = (int) (Mathf.Abs(gazeZ) * 100) / 100.0f;
  426. if (gazePointer == null)
  427. {
  428. if (gazeObject != null)
  429. {
  430. INxrGazeResponder mGazeResponder = gazeObject.GetComponent<INxrGazeResponder>();
  431. if (mGazeResponder != null)
  432. {
  433. mGazeResponder.OnUpdateIntersectionPosition(intersectionPosition);
  434. }
  435. }
  436. else
  437. {
  438. // Debug.Log("--------------------------gazePointer && gazeObject is null !!!");
  439. }
  440. return;
  441. }
  442. bool isInteractive = pointerData.pointerPress == gazeObject ||
  443. ExecuteEvents.GetEventHandler<ISelectHandler>(gazeObject) != null;
  444. if (gazeObject != null && gazeObject != previousGazedObject)
  445. {
  446. // Debug.LogError("Enter GazeObject=" + gazeObject.name);
  447. if (previousGazedObject != null)
  448. {
  449. // Debug.LogError("Exit GazeObject=" + previousGazedObject.name);
  450. }
  451. }
  452. else if (gazeObject == null && previousGazedObject != null)
  453. {
  454. // Debug.LogError("Exit GazeObject=" + previousGazedObject.name);
  455. }
  456. if (gazeObject == previousGazedObject)
  457. {
  458. if (gazeObject != null && gazePointer != null)
  459. {
  460. gazePointer.OnGazeStay(camera, gazeObject, intersectionPosition, isInteractive);
  461. INxrGazeResponder mGazeResponder = gazeObject.GetComponent<INxrGazeResponder>();
  462. if (mGazeResponder != null)
  463. {
  464. mGazeResponder.OnUpdateIntersectionPosition(intersectionPosition);
  465. }
  466. }
  467. }
  468. else
  469. {
  470. if (previousGazedObject != null && gazePointer != null)
  471. {
  472. gazePointer.OnGazeExit(camera, previousGazedObject);
  473. if (NxrViewer.Instance != null)
  474. {
  475. if (NxrViewer.Instance.HeadControl == HeadControl.Hover)
  476. {
  477. if (NxrHeadControl.baseEventData != null)
  478. {
  479. NxrHeadControl.baseEventData = null;
  480. NxrHeadControl.eventGameObject = null;
  481. }
  482. }
  483. }
  484. }
  485. if (gazeObject != null && gazePointer != null)
  486. {
  487. gazePointer.OnGazeStart(camera, gazeObject, intersectionPosition, isInteractive);
  488. if (NxrViewer.Instance != null)
  489. {
  490. if (NxrViewer.Instance.HeadControl == HeadControl.Hover)
  491. {
  492. NxrHeadControl.baseEventData = pointerData;
  493. }
  494. }
  495. }
  496. }
  497. }
  498. private void HandleDrag()
  499. {
  500. bool moving = pointerData.IsPointerMoving();
  501. if (moving && pointerData.pointerDrag != null && !pointerData.dragging)
  502. {
  503. ExecuteEvents.Execute(pointerData.pointerDrag, pointerData,
  504. ExecuteEvents.beginDragHandler);
  505. pointerData.dragging = true;
  506. }
  507. // Drag notification
  508. if (pointerData.dragging && moving && pointerData.pointerDrag != null)
  509. {
  510. // Before doing drag we should cancel any pointer down state
  511. // And clear selection!
  512. if (pointerData.pointerPress != pointerData.pointerDrag)
  513. {
  514. ExecuteEvents.Execute(pointerData.pointerPress, pointerData, ExecuteEvents.pointerUpHandler);
  515. pointerData.eligibleForClick = false;
  516. pointerData.pointerPress = null;
  517. pointerData.rawPointerPress = null;
  518. }
  519. ExecuteEvents.Execute(pointerData.pointerDrag, pointerData, ExecuteEvents.dragHandler);
  520. }
  521. }
  522. private void HandlePendingClick()
  523. {
  524. if (!pointerData.eligibleForClick && !pointerData.dragging)
  525. {
  526. return;
  527. }
  528. if (gazePointer != null)
  529. {
  530. Camera camera = pointerData.enterEventCamera;
  531. gazePointer.OnGazeTriggerEnd(camera);
  532. }
  533. var go = pointerData.pointerCurrentRaycast.gameObject;
  534. // Send pointer up and click events.
  535. ExecuteEvents.Execute(pointerData.pointerPress, pointerData, ExecuteEvents.pointerUpHandler);
  536. // 符合资格的点击
  537. if (pointerData.eligibleForClick)
  538. {
  539. if (NxrViewer.Instance != null)
  540. {
  541. if (NxrViewer.Instance.HeadControl != HeadControl.Hover ||
  542. (NxrPlayerCtrl.Instance.IsQuatConn() || ControllerAndroid.IsNoloConn()))
  543. {
  544. ExecuteEvents.Execute(pointerData.pointerPress, pointerData, ExecuteEvents.pointerClickHandler);
  545. }
  546. }
  547. }
  548. else if (pointerData.dragging)
  549. {
  550. ExecuteEvents.ExecuteHierarchy(go, pointerData, ExecuteEvents.dropHandler);
  551. ExecuteEvents.Execute(pointerData.pointerDrag, pointerData, ExecuteEvents.endDragHandler);
  552. }
  553. // Clear the click state.
  554. pointerData.pointerPress = null;
  555. pointerData.rawPointerPress = null;
  556. pointerData.eligibleForClick = false;
  557. pointerData.clickCount = 0;
  558. pointerData.clickTime = 0;
  559. pointerData.pointerDrag = null;
  560. pointerData.dragging = false;
  561. }
  562. private void HandleTrigger()
  563. {
  564. var go = pointerData.pointerCurrentRaycast.gameObject;
  565. // Send pointer down event.
  566. pointerData.pressPosition = pointerData.position;
  567. pointerData.pointerPressRaycast = pointerData.pointerCurrentRaycast;
  568. pointerData.pointerPress =
  569. ExecuteEvents.ExecuteHierarchy(go, pointerData, ExecuteEvents.pointerDownHandler)
  570. ?? ExecuteEvents.GetEventHandler<IPointerClickHandler>(go);
  571. // Save the drag handler as well
  572. pointerData.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(go);
  573. if (pointerData.pointerDrag != null)
  574. {
  575. ExecuteEvents.Execute(pointerData.pointerDrag, pointerData, ExecuteEvents.initializePotentialDrag);
  576. }
  577. // Save the pending click state.
  578. pointerData.rawPointerPress = go;
  579. pointerData.eligibleForClick = true;
  580. pointerData.delta = Vector2.zero;
  581. pointerData.dragging = false;
  582. pointerData.useDragThreshold = true;
  583. pointerData.clickCount = 1;
  584. pointerData.clickTime = Time.unscaledTime;
  585. if (gazePointer != null)
  586. {
  587. gazePointer.OnGazeTriggerStart(pointerData.enterEventCamera);
  588. }
  589. }
  590. private Vector2 NormalizedCartesianToSpherical(Vector3 cartCoords)
  591. {
  592. cartCoords.Normalize();
  593. if (cartCoords.x == 0)
  594. cartCoords.x = Mathf.Epsilon;
  595. float outPolar = Mathf.Atan(cartCoords.z / cartCoords.x);
  596. if (cartCoords.x < 0)
  597. outPolar += Mathf.PI;
  598. float outElevation = Mathf.Asin(cartCoords.y);
  599. return new Vector2(outPolar, outElevation);
  600. }
  601. GameObject GetCurrentGameObject()
  602. {
  603. if (pointerData != null && pointerData.enterEventCamera != null)
  604. {
  605. return pointerData.pointerCurrentRaycast.gameObject;
  606. }
  607. return null;
  608. }
  609. Vector3 GetIntersectionPosition()
  610. {
  611. // Check for camera
  612. Camera cam = pointerData.enterEventCamera;
  613. if (cam == null)
  614. {
  615. return Vector3.zero;
  616. }
  617. float intersectionDistance = pointerData.pointerCurrentRaycast.distance + cam.nearClipPlane;
  618. Vector3 intersectionPosition = cam.transform.position + cam.transform.forward * intersectionDistance;
  619. return intersectionPosition;
  620. }
  621. void DisableGazePointer()
  622. {
  623. if (gazePointer == null)
  624. {
  625. return;
  626. }
  627. GameObject currentGameObject = GetCurrentGameObject();
  628. if (currentGameObject)
  629. {
  630. Camera camera = pointerData.enterEventCamera;
  631. gazePointer.OnGazeExit(camera, currentGameObject);
  632. if (NxrViewer.Instance != null)
  633. {
  634. if (NxrViewer.Instance.HeadControl == HeadControl.Hover)
  635. {
  636. if (NxrHeadControl.baseEventData != null)
  637. NxrHeadControl.baseEventData = null;
  638. }
  639. }
  640. }
  641. gazePointer.OnGazeDisabled();
  642. }
  643. }
  644. }