123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- using System.Collections.Generic;
- using UnityEngine.UI;
-
- namespace UnityEngine.EventSystems
- {
- /// <summary>
- /// Simple event system using physics raycasts.
- /// </summary>
- [AddComponentMenu("Event/Physics Raycaster")]
- [RequireComponent(typeof(Camera))]
- /// <summary>
- /// Raycaster for casting against 3D Physics components.
- /// </summary>
- public class PhysicsRaycaster : BaseRaycaster
- {
- /// <summary>
- /// Const to use for clarity when no event mask is set
- /// </summary>
- protected const int kNoEventMaskSet = -1;
-
- protected Camera m_EventCamera;
-
- /// <summary>
- /// Layer mask used to filter events. Always combined with the camera's culling mask if a camera is used.
- /// </summary>
- [SerializeField]
- protected LayerMask m_EventMask = kNoEventMaskSet;
-
- /// <summary>
- /// The max number of intersections allowed. 0 = allocating version anything else is non alloc.
- /// </summary>
- [SerializeField]
- protected int m_MaxRayIntersections = 0;
- protected int m_LastMaxRayIntersections = 0;
-
- #if PACKAGE_PHYSICS
- RaycastHit[] m_Hits;
- #endif
-
- protected PhysicsRaycaster()
- {}
-
- public override Camera eventCamera
- {
- get
- {
- if (m_EventCamera == null)
- m_EventCamera = GetComponent<Camera>();
-
- if (m_EventCamera == null)
- return Camera.main;
-
- return m_EventCamera ;
- }
- }
-
-
- /// <summary>
- /// Depth used to determine the order of event processing.
- /// </summary>
- public virtual int depth
- {
- get { return (eventCamera != null) ? (int)eventCamera.depth : 0xFFFFFF; }
- }
-
- /// <summary>
- /// Event mask used to determine which objects will receive events.
- /// </summary>
- public int finalEventMask
- {
- get { return (eventCamera != null) ? eventCamera.cullingMask & m_EventMask : kNoEventMaskSet; }
- }
-
- /// <summary>
- /// Layer mask used to filter events. Always combined with the camera's culling mask if a camera is used.
- /// </summary>
- public LayerMask eventMask
- {
- get { return m_EventMask; }
- set { m_EventMask = value; }
- }
-
- /// <summary>
- /// Max number of ray intersection allowed to be found.
- /// </summary>
- /// <remarks>
- /// A value of zero will represent using the allocating version of the raycast function where as any other value will use the non allocating version.
- /// </remarks>
- public int maxRayIntersections
- {
- get { return m_MaxRayIntersections; }
- set { m_MaxRayIntersections = value; }
- }
-
- /// <summary>
- /// Returns a ray going from camera through the event position and the distance between the near and far clipping planes along that ray.
- /// </summary>
- /// <param name="eventData">The pointer event for which we will cast a ray.</param>
- /// <param name="ray">The ray to use.</param>
- /// <param name="eventDisplayIndex">The display index used.</param>
- /// <param name="distanceToClipPlane">The distance between the near and far clipping planes along the ray.</param>
- /// <returns>True if the operation was successful. false if it was not possible to compute, such as the eventPosition being outside of the view.</returns>
- protected bool ComputeRayAndDistance(PointerEventData eventData, ref Ray ray, ref int eventDisplayIndex, ref float distanceToClipPlane)
- {
- if (eventCamera == null)
- return false;
-
- var eventPosition = MultipleDisplayUtilities.RelativeMouseAtScaled(eventData.position, eventData.displayIndex);
- if (eventPosition != Vector3.zero)
- {
- // We support multiple display and display identification based on event position.
- 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 != eventCamera.targetDisplay)
- return false;
- }
- 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;
- }
-
- // Cull ray casts that are outside of the view rect. (case 636595)
- if (!eventCamera.pixelRect.Contains(eventPosition))
- return false;
-
- ray = eventCamera.ScreenPointToRay(eventPosition);
- // compensate far plane distance - see MouseEvents.cs
- float projectionDirection = ray.direction.z;
- distanceToClipPlane = Mathf.Approximately(0.0f, projectionDirection)
- ? Mathf.Infinity
- : Mathf.Abs((eventCamera.farClipPlane - eventCamera.nearClipPlane) / projectionDirection);
- return true;
- }
-
- public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
- {
- #if PACKAGE_PHYSICS
- Ray ray = new Ray();
- int displayIndex = 0;
- float distanceToClipPlane = 0;
- if (!ComputeRayAndDistance(eventData, ref ray, ref displayIndex, ref distanceToClipPlane))
- return;
-
- int hitCount = 0;
-
- if (m_MaxRayIntersections == 0)
- {
- if (ReflectionMethodsCache.Singleton.raycast3DAll == null)
- return;
-
- m_Hits = ReflectionMethodsCache.Singleton.raycast3DAll(ray, distanceToClipPlane, finalEventMask);
- hitCount = m_Hits.Length;
- }
- else
- {
- if (ReflectionMethodsCache.Singleton.getRaycastNonAlloc == null)
- return;
- if (m_LastMaxRayIntersections != m_MaxRayIntersections)
- {
- m_Hits = new RaycastHit[m_MaxRayIntersections];
- m_LastMaxRayIntersections = m_MaxRayIntersections;
- }
-
- hitCount = ReflectionMethodsCache.Singleton.getRaycastNonAlloc(ray, m_Hits, distanceToClipPlane, finalEventMask);
- }
-
- if (hitCount != 0)
- {
- if (hitCount > 1)
- System.Array.Sort(m_Hits, 0, hitCount, RaycastHitComparer.instance);
-
- for (int b = 0, bmax = hitCount; b < bmax; ++b)
- {
- var result = new RaycastResult
- {
- gameObject = m_Hits[b].collider.gameObject,
- module = this,
- distance = m_Hits[b].distance,
- worldPosition = m_Hits[b].point,
- worldNormal = m_Hits[b].normal,
- screenPosition = eventData.position,
- displayIndex = displayIndex,
- index = resultAppendList.Count,
- sortingLayer = 0,
- sortingOrder = 0
- };
- resultAppendList.Add(result);
- }
- }
- #endif
- }
-
- #if PACKAGE_PHYSICS
- private class RaycastHitComparer : IComparer<RaycastHit>
- {
- public static RaycastHitComparer instance = new RaycastHitComparer();
- public int Compare(RaycastHit x, RaycastHit y)
- {
- return x.distance.CompareTo(y.distance);
- }
- }
- #endif
- }
- }
|