123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.EventSystems;
- using UnityEngine.UI;
- namespace Nxr.Internal
- {
- public class NxrUIGraphicRaycaster : GraphicRaycaster
- {
- protected Canvas currentCanvas;
- protected Vector2 lastKnownPosition;
- protected const float UI_CONTROL_OFFSET = 0.00001f;
- [NonSerialized]
- // Use a static to prevent list reallocation. We only need one of these globally (single main thread), and only to hold temporary data
- private static List<RaycastResult> s_RaycastResults = new List<RaycastResult>();
- public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
- {
- if (canvas == null)
- {
- return;
- }
- var ray = new Ray(eventData.pointerCurrentRaycast.worldPosition, eventData.pointerCurrentRaycast.worldNormal);
- Raycast(canvas, eventCamera, ray, ref s_RaycastResults);
- SetNearestRaycast(ref eventData, ref resultAppendList, ref s_RaycastResults);
- s_RaycastResults.Clear();
- }
- protected virtual void SetNearestRaycast(ref PointerEventData eventData, ref List<RaycastResult> resultAppendList, ref List<RaycastResult> raycastResults)
- {
- RaycastResult? nearestRaycast = null;
- for (var index = 0; index < raycastResults.Count; index++)
- {
- RaycastResult castResult = raycastResults[index];
- castResult.index = resultAppendList.Count;
- if (!nearestRaycast.HasValue || castResult.distance < nearestRaycast.Value.distance)
- {
- nearestRaycast = castResult;
- }
- resultAppendList.Add(castResult);
- }
- if (nearestRaycast.HasValue)
- {
- eventData.position = nearestRaycast.Value.screenPosition;
- eventData.delta = eventData.position - lastKnownPosition;
- lastKnownPosition = eventData.position;
- eventData.pointerCurrentRaycast = nearestRaycast.Value;
- }
- }
- protected virtual float GetHitDistance(Ray ray)
- {
- var hitDistance = float.MaxValue;
- if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None)
- {
- var maxDistance = Vector3.Distance(ray.origin, canvas.transform.position);
- if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All)
- {
- RaycastHit hit;
- Physics.Raycast(ray, out hit, maxDistance);
- if (hit.collider)
- {
- hitDistance = hit.distance;
- }
- }
- if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All)
- {
- RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxDistance);
- if (hit.collider != null)
- {
- hitDistance = hit.fraction * maxDistance;
- }
- }
- }
- return hitDistance;
- }
- protected virtual void Raycast(Canvas canvas, Camera eventCamera, Ray ray, ref List<RaycastResult> results)
- {
- var hitDistance = GetHitDistance(ray);
- var canvasGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas);
- for (int i = 0; i < canvasGraphics.Count; ++i)
- {
- var graphic = canvasGraphics[i];
- if (graphic.depth == -1 || !graphic.raycastTarget)
- {
- continue;
- }
- var graphicTransform = graphic.transform;
- Vector3 graphicForward = graphicTransform.forward;
- float distance = Vector3.Dot(graphicForward, graphicTransform.position - ray.origin) / Vector3.Dot(graphicForward, ray.direction);
- if (distance < 0)
- {
- continue;
- }
- //Prevents "flickering hover" on items near canvas center.
- if ((distance - UI_CONTROL_OFFSET) > hitDistance)
- {
- continue;
- }
- Vector3 position = ray.GetPoint(distance);
- Vector2 pointerPosition = eventCamera.WorldToScreenPoint(position);
- if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera))
- {
- continue;
- }
- if (graphic.Raycast(pointerPosition, eventCamera))
- {
- var result = new RaycastResult()
- {
- gameObject = graphic.gameObject,
- module = this,
- distance = distance,
- screenPosition = pointerPosition,
- worldPosition = position,
- depth = graphic.depth,
- sortingLayer = canvas.sortingLayerID,
- sortingOrder = canvas.sortingOrder,
- };
- results.Add(result);
- }
- }
- results.Sort((g1, g2) => g2.depth.CompareTo(g1.depth));
- }
- protected virtual Canvas canvas
- {
- get
- {
- if (currentCanvas != null)
- {
- return currentCanvas;
- }
- currentCanvas = gameObject.GetComponent<Canvas>();
- return currentCanvas;
- }
- }
- }
- }
|