Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
6.6 KiB

  1. namespace VRTK
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEngine.EventSystems;
  7. using UnityEngine.UI;
  8. /// This script allows VRTK to interact cleanly with Unity Canvases.
  9. /// It is mostly a duplicate of Unity's default GraphicsRaycaster:
  10. /// https://bitbucket.org/Unity-Technologies/ui/src/0155c39e05ca5d7dcc97d9974256ef83bc122586/UnityEngine.UI/UI/Core/GraphicRaycaster.c
  11. /// However, it allows for graphics to be hit when they are not in view of a camera.
  12. /// Note: Not intended for direct use. VRTK will intelligently replace the default GraphicsRaycaster
  13. /// on canvases with this raycaster.
  14. public class VRTK_UIGraphicRaycaster : GraphicRaycaster
  15. {
  16. protected Canvas currentCanvas;
  17. protected Vector2 lastKnownPosition;
  18. protected const float UI_CONTROL_OFFSET = 0.00001f;
  19. [NonSerialized]
  20. // Use a static to prevent list reallocation. We only need one of these globally (single main thread), and only to hold temporary data
  21. private static List<RaycastResult> s_RaycastResults = new List<RaycastResult>();
  22. public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
  23. {
  24. if (canvas == null || eventCamera == null)
  25. {
  26. return;
  27. }
  28. Ray ray = new Ray(eventData.pointerCurrentRaycast.worldPosition, eventData.pointerCurrentRaycast.worldNormal);
  29. Raycast(canvas, eventCamera, eventData, ray, ref s_RaycastResults);
  30. SetNearestRaycast(ref eventData, ref resultAppendList, ref s_RaycastResults);
  31. s_RaycastResults.Clear();
  32. }
  33. //[Pure]
  34. protected virtual void SetNearestRaycast(ref PointerEventData eventData, ref List<RaycastResult> resultAppendList, ref List<RaycastResult> raycastResults)
  35. {
  36. RaycastResult? nearestRaycast = null;
  37. for (int index = 0; index < raycastResults.Count; index++)
  38. {
  39. RaycastResult castResult = raycastResults[index];
  40. castResult.index = resultAppendList.Count;
  41. if (!nearestRaycast.HasValue || castResult.distance < nearestRaycast.Value.distance)
  42. {
  43. nearestRaycast = castResult;
  44. }
  45. VRTK_SharedMethods.AddListValue(resultAppendList, castResult);
  46. }
  47. if (nearestRaycast.HasValue)
  48. {
  49. eventData.position = nearestRaycast.Value.screenPosition;
  50. eventData.delta = eventData.position - lastKnownPosition;
  51. lastKnownPosition = eventData.position;
  52. eventData.pointerCurrentRaycast = nearestRaycast.Value;
  53. }
  54. }
  55. //[Pure]
  56. protected virtual float GetHitDistance(Ray ray, float hitDistance)
  57. {
  58. if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None)
  59. {
  60. float maxDistance = Vector3.Distance(ray.origin, canvas.transform.position);
  61. if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All)
  62. {
  63. RaycastHit hit;
  64. Physics.Raycast(ray, out hit, maxDistance, m_BlockingMask);
  65. if (hit.collider != null && !VRTK_PlayerObject.IsPlayerObject(hit.collider.gameObject))
  66. {
  67. hitDistance = hit.distance;
  68. }
  69. }
  70. if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All)
  71. {
  72. RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxDistance);
  73. if (hit.collider != null && !VRTK_PlayerObject.IsPlayerObject(hit.collider.gameObject))
  74. {
  75. hitDistance = hit.fraction * maxDistance;
  76. }
  77. }
  78. }
  79. return hitDistance;
  80. }
  81. //[Pure]
  82. protected virtual void Raycast(Canvas canvas, Camera eventCamera, PointerEventData eventData, Ray ray, ref List<RaycastResult> results)
  83. {
  84. float hitDistance = GetHitDistance(ray, VRTK_UIPointer.GetPointerLength(eventData.pointerId));
  85. IList<Graphic> canvasGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas);
  86. for (int i = 0; i < canvasGraphics.Count; ++i)
  87. {
  88. Graphic graphic = canvasGraphics[i];
  89. if (graphic.depth == -1 || !graphic.raycastTarget)
  90. {
  91. continue;
  92. }
  93. Transform graphicTransform = graphic.transform;
  94. Vector3 graphicForward = graphicTransform.forward;
  95. float distance = Vector3.Dot(graphicForward, graphicTransform.position - ray.origin) / Vector3.Dot(graphicForward, ray.direction);
  96. if (distance < 0)
  97. {
  98. continue;
  99. }
  100. //Prevents "flickering hover" on items near canvas center.
  101. if ((distance - UI_CONTROL_OFFSET) > hitDistance)
  102. {
  103. continue;
  104. }
  105. Vector3 position = ray.GetPoint(distance);
  106. Vector2 pointerPosition = eventCamera.WorldToScreenPoint(position);
  107. if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera))
  108. {
  109. continue;
  110. }
  111. if (graphic.Raycast(pointerPosition, eventCamera))
  112. {
  113. RaycastResult result = new RaycastResult()
  114. {
  115. gameObject = graphic.gameObject,
  116. module = this,
  117. distance = distance,
  118. screenPosition = pointerPosition,
  119. worldPosition = position,
  120. depth = graphic.depth,
  121. sortingLayer = canvas.sortingLayerID,
  122. sortingOrder = canvas.sortingOrder,
  123. };
  124. VRTK_SharedMethods.AddListValue(results, result);
  125. }
  126. }
  127. results.Sort((g1, g2) => g2.depth.CompareTo(g1.depth));
  128. }
  129. protected virtual Canvas canvas
  130. {
  131. get
  132. {
  133. if (currentCanvas != null)
  134. {
  135. return currentCanvas;
  136. }
  137. currentCanvas = gameObject.GetComponent<Canvas>();
  138. return currentCanvas;
  139. }
  140. }
  141. }
  142. }