2022-01-12 10:39:15 +03:00
using System.Collections.Generic ;
2022-01-12 10:06:03 +03:00
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 > ( ) ;
return m_EventCamera ? ? Camera . main ;
}
}
/// <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 = Display . RelativeMouseAt ( eventData . position ) ;
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
}
}