BaseRayCaster.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using UnityEngine.EventSystems;
  4. using System.Collections.Generic;
  5. using System;
  6. using static UnityEngine.EventSystems.PointerEventData;
  7. using Rokid.UXR.Utility;
  8. namespace Rokid.UXR.Interaction
  9. {
  10. public abstract class BaseRayCaster : MonoBehaviour
  11. {
  12. /// <summary>
  13. /// Threshold for determining whether to start dragging
  14. /// </summary>
  15. public float m_DragThreshold = 0.01f;
  16. /// <summary>
  17. /// Cache the current hovering object
  18. /// </summary>
  19. [SerializeField]
  20. protected GameObject m_HoveringObj;
  21. /// <summary>
  22. /// Cache selected object
  23. /// </summary>
  24. [SerializeField]
  25. protected GameObject m_SelectedObj;
  26. [SerializeField]
  27. protected GameObject m_FirstSelectedObj;
  28. [Tooltip("This attribute only affects UI graphics, detecting the front and back sides of the UI")]
  29. [SerializeField]
  30. private bool ignoreReversedGraphics = true;
  31. [Tooltip("Is detect UI graphics")]
  32. [SerializeField]
  33. private bool raycastGraphic = true;
  34. [Tooltip("Is detect physical collisions")]
  35. [SerializeField]
  36. private bool raycastPhysical = true;
  37. [SerializeField]
  38. protected Transform rayOrigin;
  39. protected Ray ray;
  40. protected Vector3 oriHitPoint;
  41. /// <summary> The hits. </summary>
  42. private static readonly RaycastHit[] hits = new RaycastHit[64];
  43. /// <summary>
  44. /// 点击的阈值
  45. /// </summary>
  46. protected float clickTime = 0.5f;
  47. protected float pressTime = 0;
  48. /// <summary>
  49. /// 是否正在在拖拽中
  50. /// </summary>
  51. [SerializeField]
  52. protected bool dragging = false;
  53. /// <summary>
  54. /// 缓存开始拖拽的时候射线原点到触碰点的距离
  55. /// </summary>
  56. protected float oriHitPointDis = 0;
  57. [SerializeField]
  58. protected BaseInput m_InputOverride;
  59. private BaseInput m_DefaultInput;
  60. [SerializeField]
  61. protected RaycastResult result;
  62. [SerializeField]
  63. protected PointerEventData pointerEventData;
  64. [SerializeField]
  65. protected RayInteractor rayInteractor;
  66. [SerializeField]
  67. protected Camera eventCamera;
  68. [SerializeField]
  69. protected bool sendGlobalEvent = true;
  70. protected Vector2 screenCenterPoint = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f);
  71. public LayerMask raycastMask = (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7);
  72. private static readonly Comparison<RaycastResult> s_RaycastComparer = RaycastComparer;
  73. protected readonly List<RaycastResult> sortedRaycastResults = new List<RaycastResult>();
  74. #region Event names can be overwritten
  75. protected string pointerEnter = "OnRayPointerEnter";
  76. protected string pointerExit = "OnRayPointerExit";
  77. protected string pointerHover = "OnRayPointerHover";
  78. protected string pointerClick = "OnRayPointerClick";
  79. protected string dragBegin = "OnRayBeginDrag";
  80. protected string drag = "OnRayDrag";
  81. protected string dragEnd = "OnRayEndDrag";
  82. #endregion
  83. public BaseInput input
  84. {
  85. get
  86. {
  87. if (m_InputOverride != null)
  88. {
  89. return m_InputOverride;
  90. }
  91. if (m_DefaultInput == null)
  92. {
  93. BaseInput[] components = GetComponents<BaseInput>();
  94. foreach (BaseInput baseInput in components)
  95. {
  96. if (baseInput != null && baseInput.GetType() == typeof(BaseInput))
  97. {
  98. m_DefaultInput = baseInput;
  99. break;
  100. }
  101. }
  102. if (m_DefaultInput == null)
  103. {
  104. m_DefaultInput = base.gameObject.AddComponent<BaseInput>();
  105. }
  106. }
  107. return m_DefaultInput;
  108. }
  109. }
  110. public BaseInput inputOverride
  111. {
  112. get
  113. {
  114. return m_InputOverride;
  115. }
  116. set
  117. {
  118. m_InputOverride = value;
  119. }
  120. }
  121. protected virtual void Init()
  122. {
  123. pointerEventData = new PointerEventData(EventSystem.current);
  124. pointerEventData.button = InputButton.Left;
  125. if (rayInteractor == null)
  126. {
  127. rayInteractor = GetComponent<RayInteractor>();
  128. }
  129. }
  130. private int GetRayIdentifier()
  131. {
  132. if (rayInteractor == null)
  133. {
  134. return 0;
  135. }
  136. else
  137. {
  138. return rayInteractor.realId;
  139. }
  140. }
  141. protected virtual void Start()
  142. {
  143. Init();
  144. if (eventCamera == null)
  145. {
  146. eventCamera = GetEventCamera();
  147. }
  148. }
  149. protected virtual Camera GetEventCamera()
  150. {
  151. return MainCameraCache.mainCamera;
  152. }
  153. protected virtual void OnDestroy()
  154. {
  155. }
  156. protected virtual void OnDisable()
  157. {
  158. if (dragging)
  159. {
  160. RKLog.Debug("====BaseRayCaster====: dragEnd");
  161. if (!ProcessEndDrag(ray))
  162. m_SelectedObj?.SendMessageUpwards(dragEnd, SendMessageOptions.DontRequireReceiver);
  163. }
  164. else
  165. {
  166. if (pressTime < clickTime && m_SelectedObj == result.gameObject && result.gameObject != null)
  167. //发送点击事件
  168. m_SelectedObj?.SendMessageUpwards(pointerClick, SendMessageOptions.DontRequireReceiver);
  169. }
  170. dragging = false;
  171. m_SelectedObj = null;
  172. m_FirstSelectedObj = null;
  173. }
  174. protected void UpdatePointerEventData()
  175. {
  176. pointerEventData.pointerCurrentRaycast = result;
  177. pointerEventData.pointerId = GetRayIdentifier();
  178. }
  179. private void Update()
  180. {
  181. if (rayOrigin != null)
  182. {
  183. ray.origin = rayOrigin.position;
  184. ray.direction = rayOrigin.forward;
  185. }
  186. else
  187. {
  188. ray.origin = transform.position;
  189. ray.direction = transform.forward;
  190. }
  191. #if UNITY_EDITOR
  192. Debug.DrawRay(ray.origin, ray.direction, Color.red);
  193. #endif
  194. if (input.GetMouseButtonDown(0))
  195. {
  196. if (!TriggerPointerDown())
  197. {
  198. pressTime = 0;
  199. Raycast(ray, Mathf.Infinity, sortedRaycastResults);
  200. result = FirstRaycastResult();
  201. UpdatePointerEventData();
  202. if (result.gameObject != null)
  203. {
  204. m_FirstSelectedObj = result.gameObject;
  205. OnFirstSelect();
  206. }
  207. else
  208. {
  209. m_FirstSelectedObj = null;
  210. ProcessNothingDownEvent(pointerEventData);
  211. }
  212. }
  213. }
  214. else if (!dragging)
  215. {
  216. Raycast(ray, Mathf.Infinity, sortedRaycastResults);
  217. result = FirstRaycastResult();
  218. UpdatePointerEventData();
  219. if (input.GetMouseButtonUp(0) && result.gameObject == null)
  220. {
  221. ProcessNothingUpEvent(pointerEventData);
  222. }
  223. if (result.gameObject != null)
  224. {
  225. if (m_HoveringObj == null)
  226. {
  227. m_HoveringObj = result.gameObject;
  228. RKLog.Debug($"====BaseRayCaster====: pointerEnter:{m_HoveringObj.name}");
  229. m_HoveringObj.SendMessageUpwards(pointerEnter, SendMessageOptions.DontRequireReceiver);
  230. if (sendGlobalEvent)
  231. {
  232. RKPointerLisener.OnPointerEnter?.Invoke(pointerEventData);
  233. }
  234. }
  235. else
  236. {
  237. if (m_HoveringObj != result.gameObject)
  238. {
  239. RKLog.Debug($"====BaseRayCaster====: pointerExit: {m_HoveringObj.name}");
  240. m_HoveringObj.SendMessageUpwards(pointerExit, SendMessageOptions.DontRequireReceiver);
  241. if (sendGlobalEvent)
  242. {
  243. RKPointerLisener.OnPointerExit?.Invoke(pointerEventData, m_HoveringObj);
  244. }
  245. m_HoveringObj = result.gameObject;
  246. RKLog.Debug($"====BaseRayCaster====: pointerEnter {m_HoveringObj.name}");
  247. m_HoveringObj.SendMessageUpwards(pointerEnter, SendMessageOptions.DontRequireReceiver);
  248. if (sendGlobalEvent)
  249. {
  250. RKPointerLisener.OnPointerEnter?.Invoke(pointerEventData);
  251. }
  252. }
  253. m_HoveringObj.SendMessageUpwards(pointerHover, result, SendMessageOptions.DontRequireReceiver);
  254. if (sendGlobalEvent)
  255. RKPointerLisener.OnPointerHover?.Invoke(pointerEventData);
  256. if (input.GetMouseButton(0) && !dragging)
  257. {
  258. pressTime += Time.deltaTime;
  259. if (m_FirstSelectedObj == m_HoveringObj)
  260. {
  261. m_SelectedObj = m_HoveringObj;
  262. Vector3 delta = CalDragDelta();//拖拽移动的向量
  263. RKLog.Debug($"====BaseRayCaster====: JudgeDrag {delta},{m_DragThreshold}");
  264. if (CanDrag(delta))
  265. {
  266. OnBeginDrag();
  267. RKLog.Debug("====BaseRayCaster====: dragBegin");
  268. if (!ProcessBeginDrag(ray))
  269. {
  270. m_SelectedObj.SendMessageUpwards(dragBegin, pointerEventData, SendMessageOptions.DontRequireReceiver);
  271. if (sendGlobalEvent)
  272. RKPointerLisener.OnPointerDragBegin?.Invoke(pointerEventData);
  273. }
  274. dragging = true;
  275. }
  276. }
  277. }
  278. }
  279. }
  280. else if (m_HoveringObj != null)
  281. {
  282. RKLog.Debug($"====BaseRayCaster====: pointerExit: {m_HoveringObj.name}");
  283. m_HoveringObj.SendMessageUpwards(pointerExit, SendMessageOptions.DontRequireReceiver);
  284. RKPointerLisener.OnPointerExit?.Invoke(pointerEventData, m_HoveringObj);
  285. result.gameObject = null;
  286. m_HoveringObj = null;
  287. }
  288. }
  289. if (dragging)
  290. {
  291. ProcessDrag(ray);
  292. if (sendGlobalEvent)
  293. RKPointerLisener.OnPointerDrag?.Invoke(pointerEventData);
  294. }
  295. //处理点击释放逻辑
  296. if (input.GetMouseButtonUp(0))
  297. {
  298. if (dragging == false)
  299. {
  300. if (pressTime < clickTime && m_SelectedObj == result.gameObject && result.gameObject != null)
  301. {
  302. //发送点击事件
  303. m_SelectedObj.SendMessageUpwards(pointerClick, SendMessageOptions.DontRequireReceiver);
  304. }
  305. m_SelectedObj = null;
  306. }
  307. }
  308. //处理拖拽释放逻辑
  309. if (dragging && DragRelease())
  310. {
  311. if (m_SelectedObj != null)
  312. {
  313. RKLog.Debug("====BaseRayCaster====: dragEnd 2");
  314. if (!ProcessEndDrag(ray))
  315. {
  316. m_SelectedObj.SendMessageUpwards(dragEnd, SendMessageOptions.DontRequireReceiver);
  317. if (sendGlobalEvent)
  318. RKPointerLisener.OnPointerDragEnd?.Invoke(pointerEventData);
  319. }
  320. m_SelectedObj = null;
  321. }
  322. dragging = false;
  323. }
  324. }
  325. protected virtual bool CanDrag(Vector3 delta)
  326. {
  327. return !dragging && Vector3.SqrMagnitude(delta) >= m_DragThreshold * m_DragThreshold;
  328. }
  329. protected virtual bool DragRelease()
  330. {
  331. return !input.GetMouseButton(0);
  332. }
  333. protected virtual bool TriggerPointerDown()
  334. {
  335. return false;
  336. }
  337. protected virtual void OnFirstSelect()
  338. {
  339. oriHitPoint = result.worldPosition;
  340. }
  341. protected virtual Vector3 CalDragDelta()
  342. {
  343. RKLog.Debug($"====BaseRayCaster==== dragDelta:{result.worldPosition - oriHitPoint}");
  344. return result.worldPosition - oriHitPoint;//拖拽移动的向量
  345. }
  346. protected virtual void OnBeginDrag()
  347. {
  348. oriHitPointDis = Vector3.Distance(result.worldPosition, ray.origin);
  349. oriHitPoint = result.worldPosition;
  350. }
  351. protected virtual bool ProcessBeginDrag(Ray ray) { return false; }
  352. protected virtual bool ProcessEndDrag(Ray ray) { return false; }
  353. protected virtual bool ProcessDrag(Ray ray) { return false; }
  354. protected virtual void ProcessNothingUpEvent(PointerEventData eventData)
  355. {
  356. if (sendGlobalEvent)
  357. RKPointerLisener.OnPointerNothingUp?.Invoke(eventData);
  358. }
  359. protected virtual void ProcessNothingDownEvent(PointerEventData eventData)
  360. {
  361. if (sendGlobalEvent)
  362. RKPointerLisener.OnPointerNothingDown?.Invoke(eventData);
  363. }
  364. private static int RaycastComparer(RaycastResult lhs, RaycastResult rhs)
  365. {
  366. if (lhs.module != rhs.module)
  367. {
  368. var lhsEventCamera = lhs.module.eventCamera;
  369. var rhsEventCamera = rhs.module.eventCamera;
  370. if (lhsEventCamera != null && rhsEventCamera != null && lhsEventCamera.depth != rhsEventCamera.depth)
  371. {
  372. // need to reverse the standard compareTo
  373. if (lhsEventCamera.depth < rhsEventCamera.depth)
  374. return 1;
  375. if (lhsEventCamera.depth == rhsEventCamera.depth)
  376. return 0;
  377. return -1;
  378. }
  379. if (lhs.module.sortOrderPriority != rhs.module.sortOrderPriority)
  380. return rhs.module.sortOrderPriority.CompareTo(lhs.module.sortOrderPriority);
  381. if (lhs.module.renderOrderPriority != rhs.module.renderOrderPriority)
  382. return rhs.module.renderOrderPriority.CompareTo(lhs.module.renderOrderPriority);
  383. }
  384. if (lhs.sortingLayer != rhs.sortingLayer)
  385. {
  386. // Uses the layer value to properly compare the relative order of the layers.
  387. var rid = SortingLayer.GetLayerValueFromID(rhs.sortingLayer);
  388. var lid = SortingLayer.GetLayerValueFromID(lhs.sortingLayer);
  389. return rid.CompareTo(lid);
  390. }
  391. if (lhs.sortingOrder != rhs.sortingOrder)
  392. return rhs.sortingOrder.CompareTo(lhs.sortingOrder);
  393. // comparing depth only makes sense if the two raycast results have the same root canvas (case 912396)
  394. if (lhs.module != null && rhs.module != null)
  395. {
  396. if (lhs.depth != rhs.depth && lhs.module.rootRaycaster == rhs.module.rootRaycaster)
  397. return rhs.depth.CompareTo(lhs.depth);
  398. }
  399. if (lhs.distance != rhs.distance)
  400. return lhs.distance.CompareTo(rhs.distance);
  401. return lhs.index.CompareTo(rhs.index);
  402. }
  403. /// <summary> Raycasts. </summary>
  404. /// <param name="ray"> The ray.</param>
  405. /// <param name="distance"> The distance.</param>
  406. /// <param name="raycastResults"> The raycast results.</param>
  407. public void Raycast(Ray ray, float distance, List<RaycastResult> raycastResults)
  408. {
  409. raycastResults.Clear();
  410. if (raycastGraphic)
  411. GraphicRaycast(ignoreReversedGraphics, ray, distance, raycastResults);
  412. if (raycastPhysical)
  413. PhysicsRaycast(ray, distance, raycastResults);
  414. raycastResults.Sort(s_RaycastComparer);
  415. }
  416. /// <summary> Physics raycast. </summary>
  417. /// <param name="ray"> The ray.</param>
  418. /// <param name="distance"> The distance.</param>
  419. /// <param name="raycastResults"> The raycast results.</param>
  420. public virtual void PhysicsRaycast(Ray ray, float distance, List<RaycastResult> raycastResults)
  421. {
  422. var hitCount = Physics.RaycastNonAlloc(ray, hits, distance, raycastMask);
  423. for (int i = 0; i < hitCount; ++i)
  424. {
  425. RKLog.Debug("=====BaseRayCast==== Physical Raycast:" + hits[i].collider.gameObject.name);
  426. if (!hits[i].collider.GetComponent<RayInteractable>() && !hits[i].collider.GetComponentInParent<RayInteractable>())
  427. continue;
  428. raycastResults.Add(new RaycastResult
  429. {
  430. gameObject = hits[i].collider.gameObject,
  431. distance = hits[i].distance,
  432. worldPosition = hits[i].point,
  433. worldNormal = hits[i].normal,
  434. screenPosition = screenCenterPoint,
  435. index = raycastResults.Count,
  436. sortingLayer = 0,
  437. sortingOrder = 0
  438. });
  439. }
  440. }
  441. public RaycastResult FirstRaycastResult()
  442. {
  443. for (int i = 0, imax = sortedRaycastResults.Count; i < imax; ++i)
  444. {
  445. RKLog.Debug("=====BaseRayCast==== FirstRaycastResult:" + sortedRaycastResults[i].gameObject.name);
  446. return sortedRaycastResults[i];
  447. }
  448. return default(RaycastResult);
  449. }
  450. public RaycastResult FirstRaycastResult(List<RaycastResult> sortedRaycastResults)
  451. {
  452. for (int i = 0, imax = sortedRaycastResults.Count; i < imax; ++i)
  453. {
  454. // if (!sortedRaycastResults[i].isValid)
  455. // continue;
  456. return sortedRaycastResults[i];
  457. }
  458. return default(RaycastResult);
  459. }
  460. /// <summary>
  461. /// 获取事件位置
  462. /// </summary>
  463. protected virtual Vector2 GetEventPosition(Ray ray, Camera eventCamera, Graphic graphic)
  464. {
  465. if (Utils.GetWorldPointInRectangle(graphic, ray, out Vector3 worldPoint))
  466. {
  467. return eventCamera.WorldToScreenPoint(worldPoint);
  468. }
  469. return screenCenterPoint;
  470. }
  471. /// <summary> Graphic raycast. </summary>
  472. /// <param name="canvas"> The canvas.</param>
  473. /// <param name="ignoreReversedGraphics"> True to ignore reversed graphics.</param>
  474. /// <param name="ray"> The ray.</param>
  475. /// <param name="distance"> The distance.</param>
  476. /// <param name="raycaster"> The raycaster.</param>
  477. /// <param name="raycastResults"> The raycast results.</param>
  478. public virtual void GraphicRaycast(bool ignoreReversedGraphics, Ray ray, float distance, List<RaycastResult> raycastResults)
  479. {
  480. foreach (Canvas canvas in CanvasRegister.canvasList)
  481. {
  482. var graphics = GraphicRegistry.GetGraphicsForCanvas(canvas);
  483. for (int i = 0; i < graphics.Count; ++i)
  484. {
  485. var graphic = graphics[i];
  486. // -1 means it hasn't been processed by the canvas, which means it isn't actually drawn
  487. if (graphic.depth == -1 || !graphic.raycastTarget || graphic.canvasRenderer.cull)
  488. continue;
  489. Vector2 screenPoint = GetEventPosition(ray, eventCamera, graphic);
  490. if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, screenPoint, eventCamera))
  491. continue;
  492. if (eventCamera != null && eventCamera.WorldToScreenPoint(graphic.rectTransform.position).z > eventCamera.farClipPlane)
  493. continue;
  494. if (eventCamera != null && ignoreReversedGraphics && Vector3.Dot(eventCamera.transform.forward, graphic.transform.forward) < 0)
  495. continue;
  496. float dist;
  497. //平面和射线的交点
  498. new Plane(graphic.transform.forward, graphic.transform.position).Raycast(ray, out dist);
  499. if (float.IsNaN(dist) || dist > distance)
  500. continue;
  501. if (graphic.Raycast(screenPoint, eventCamera))
  502. {
  503. raycastResults.Add(new RaycastResult
  504. {
  505. gameObject = graphic.gameObject,
  506. distance = dist,
  507. worldPosition = ray.GetPoint(dist),
  508. worldNormal = -graphic.transform.forward,
  509. screenPosition = screenCenterPoint,
  510. index = raycastResults.Count,
  511. depth = graphic.depth,
  512. sortingLayer = canvas.sortingLayerID,
  513. sortingOrder = canvas.sortingOrder
  514. });
  515. }
  516. }
  517. }
  518. }
  519. }
  520. }