diff options
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/GraphicRaycaster.cs')
-rw-r--r-- | Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/GraphicRaycaster.cs | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/GraphicRaycaster.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/GraphicRaycaster.cs new file mode 100644 index 0000000..303689a --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/GraphicRaycaster.cs @@ -0,0 +1,290 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine.EventSystems; +using UnityEngine.Serialization; + +namespace UnityEngine.UI +{ + [AddComponentMenu("Event/Graphic Raycaster")] + [RequireComponent(typeof(Canvas))] + public class GraphicRaycaster : BaseRaycaster + { + protected const int kNoEventMaskSet = -1; + public enum BlockingObjects + { + None = 0, + TwoD = 1, + ThreeD = 2, + All = 3, + } + + public override int sortOrderPriority + { + get + { + // We need to return the sorting order here as distance will all be 0 for overlay. + if (canvas.renderMode == RenderMode.ScreenSpaceOverlay) + return canvas.sortingOrder; + + return base.sortOrderPriority; + } + } + + public override int renderOrderPriority + { + get + { + // We need to return the sorting order here as distance will all be 0 for overlay. + if (canvas.renderMode == RenderMode.ScreenSpaceOverlay) + return canvas.rootCanvas.renderOrder; + + return base.renderOrderPriority; + } + } + + [FormerlySerializedAs("ignoreReversedGraphics")] + [SerializeField] + private bool m_IgnoreReversedGraphics = true; + [FormerlySerializedAs("blockingObjects")] + [SerializeField] + private BlockingObjects m_BlockingObjects = BlockingObjects.None; + + public bool ignoreReversedGraphics { get {return m_IgnoreReversedGraphics; } set { m_IgnoreReversedGraphics = value; } } + public BlockingObjects blockingObjects { get {return m_BlockingObjects; } set { m_BlockingObjects = value; } } + + [SerializeField] + protected LayerMask m_BlockingMask = kNoEventMaskSet; + + private Canvas m_Canvas; + + protected GraphicRaycaster() + {} + + private Canvas canvas + { + get + { + if (m_Canvas != null) + return m_Canvas; + + m_Canvas = GetComponent<Canvas>(); + return m_Canvas; + } + } + + [NonSerialized] private List<Graphic> m_RaycastResults = new List<Graphic>(); + public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList) + { + if (canvas == null) + return; + + // 拿到canvas下的所有graphic + var canvasGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas); + if (canvasGraphics == null || canvasGraphics.Count == 0) + return; + + int displayIndex; + var currentEventCamera = eventCamera; // Propery can call Camera.main, so cache the reference + + if (canvas.renderMode == RenderMode.ScreenSpaceOverlay || currentEventCamera == null) + displayIndex = canvas.targetDisplay; + else + displayIndex = currentEventCamera.targetDisplay; + + var eventPosition = Display.RelativeMouseAt(eventData.position); + if (eventPosition != Vector3.zero) + { + // We support multiple display and display identification based on event position. + + int eventDisplayIndex = (int)eventPosition.z; + + // Discard events that are not part of this display so the user does not interact with multiple displays at once. + if (eventDisplayIndex != displayIndex) + return; + } + else + { + // The multiple display system is not supported on all platforms, when it is not supported the returned position + // will be all zeros so when the returned index is 0 we will default to the event data to be safe. + eventPosition = eventData.position; + + // We dont really know in which display the event occured. We will process the event assuming it occured in our display. + } + + // Convert to view space + Vector2 pos; + if (currentEventCamera == null) + { + // Multiple display support only when not the main display. For display 0 the reported + // resolution is always the desktops resolution since its part of the display API, + // so we use the standard none multiple display method. (case 741751) + float w = Screen.width; + float h = Screen.height; + if (displayIndex > 0 && displayIndex < Display.displays.Length) + { + w = Display.displays[displayIndex].systemWidth; + h = Display.displays[displayIndex].systemHeight; + } + pos = new Vector2(eventPosition.x / w, eventPosition.y / h); + } + else + pos = currentEventCamera.ScreenToViewportPoint(eventPosition); + + // If it's outside the camera's viewport, do nothing + if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f) + return; + + float hitDistance = float.MaxValue; + + Ray ray = new Ray(); + + if (currentEventCamera != null) + ray = currentEventCamera.ScreenPointToRay(eventPosition); + + if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None) + { + float distanceToClipPlane = 100.0f; + + if (currentEventCamera != null) + { + float projectionDirection = ray.direction.z; + distanceToClipPlane = Mathf.Approximately(0.0f, projectionDirection) + ? Mathf.Infinity + : Mathf.Abs((currentEventCamera.farClipPlane - currentEventCamera.nearClipPlane) / projectionDirection); + } + + if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All) + { + if (ReflectionMethodsCache.Singleton.raycast3D != null) + { + var hits = ReflectionMethodsCache.Singleton.raycast3DAll(ray, distanceToClipPlane, (int)m_BlockingMask); + if (hits.Length > 0) + hitDistance = hits[0].distance; + } + } + + if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All) + { + if (ReflectionMethodsCache.Singleton.raycast2D != null) + { + var hits = ReflectionMethodsCache.Singleton.getRayIntersectionAll(ray, distanceToClipPlane, (int)m_BlockingMask); + if (hits.Length > 0) + hitDistance = hits[0].distance; + } + } + } + + m_RaycastResults.Clear(); + Raycast(canvas, currentEventCamera, eventPosition, canvasGraphics, m_RaycastResults); + + int totalCount = m_RaycastResults.Count; + for (var index = 0; index < totalCount; index++) + { + var go = m_RaycastResults[index].gameObject; + bool appendGraphic = true; + + if (ignoreReversedGraphics) + { + if (currentEventCamera == null) + { + // If we dont have a camera we know that we should always be facing forward + var dir = go.transform.rotation * Vector3.forward; + appendGraphic = Vector3.Dot(Vector3.forward, dir) > 0; + } + else + { + // If we have a camera compare the direction against the cameras forward. + var cameraFoward = currentEventCamera.transform.rotation * Vector3.forward; + var dir = go.transform.rotation * Vector3.forward; + appendGraphic = Vector3.Dot(cameraFoward, dir) > 0; + } + } + + if (appendGraphic) + { + float distance = 0; + + if (currentEventCamera == null || canvas.renderMode == RenderMode.ScreenSpaceOverlay) + distance = 0; + else + { + Transform trans = go.transform; + Vector3 transForward = trans.forward; + // http://geomalgorithms.com/a06-_intersect-2.html + distance = (Vector3.Dot(transForward, trans.position - currentEventCamera.transform.position) / Vector3.Dot(transForward, ray.direction)); + + // Check to see if the go is behind the camera. + if (distance < 0) + continue; + } + + if (distance >= hitDistance) + continue; + + var castResult = new RaycastResult + { + gameObject = go, + module = this, + distance = distance, + screenPosition = eventPosition, + index = resultAppendList.Count, + depth = m_RaycastResults[index].depth, + sortingLayer = canvas.sortingLayerID, + sortingOrder = canvas.sortingOrder + }; + resultAppendList.Add(castResult); + } + } + } + + public override Camera eventCamera + { + get + { + if (canvas.renderMode == RenderMode.ScreenSpaceOverlay || (canvas.renderMode == RenderMode.ScreenSpaceCamera && canvas.worldCamera == null)) + return null; + + return canvas.worldCamera != null ? canvas.worldCamera : Camera.main; + } + } + + // + /// <summary> + /// Perform a raycast into the screen and collect all graphics underneath it. + /// </summary> + [NonSerialized] static readonly List<Graphic> s_SortedGraphics = new List<Graphic>(); + private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, IList<Graphic> foundGraphics, List<Graphic> results) + { + // Debug.Log("ttt" + pointerPoision + ":::" + camera); + // Necessary for the event system + int totalCount = foundGraphics.Count; + for (int i = 0; i < totalCount; ++i) + { + Graphic graphic = foundGraphics[i]; + + // -1 means it hasn't been processed by the canvas, which means it isn't actually drawn + if (graphic.depth == -1 || !graphic.raycastTarget || graphic.canvasRenderer.cull) + continue; + + if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera)) + continue; + + if (graphic.Raycast(pointerPosition, eventCamera)) + { + s_SortedGraphics.Add(graphic); + } + } + + // 从高到低,所以会以深度优先。越深的越先响应。 + s_SortedGraphics.Sort((g1, g2) => g2.depth.CompareTo(g1.depth)); + // StringBuilder cast = new StringBuilder(); + totalCount = s_SortedGraphics.Count; + for (int i = 0; i < totalCount; ++i) + results.Add(s_SortedGraphics[i]); + // Debug.Log (cast.ToString()); + + s_SortedGraphics.Clear(); + } + } +} |