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.
203 lines
7.7 KiB
203 lines
7.7 KiB
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>(); |
|
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 = MultipleDisplayUtilities.RelativeMouseAtScaled(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 |
|
} |
|
}
|
|
|