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.
118 lines
4.8 KiB
118 lines
4.8 KiB
using System.Collections.Generic;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
namespace UnityEngine.UIElements
|
|
{
|
|
// This code is disabled unless the com.unity.modules.uielements module is present.
|
|
// The UIElements module is always present in the Editor but it can be stripped from a project build if unused.
|
|
#if PACKAGE_UITOOLKIT
|
|
/// <summary>
|
|
/// A derived BaseRaycaster to raycast against UI Toolkit world-space document instances at runtime.
|
|
/// </summary>
|
|
[AddComponentMenu("UI Toolkit/World Document Raycaster (UI Toolkit)")]
|
|
public class WorldDocumentRaycaster : BaseRaycaster
|
|
{
|
|
[SerializeField] private Camera m_EventCamera;
|
|
|
|
/// <summary>
|
|
/// The camera that will generate rays for this raycaster.
|
|
/// </summary>
|
|
public override Camera eventCamera => m_EventCamera;
|
|
|
|
/// <summary>
|
|
/// The camera used by this Raycaster to convert screen coordinates to Rays.
|
|
/// If empty, Camera.main is going to be used.
|
|
/// </summary>
|
|
public new Camera camera
|
|
{
|
|
get => m_EventCamera;
|
|
set => m_EventCamera = value;
|
|
}
|
|
|
|
private static PhysicsDocumentPicker worldPicker = new();
|
|
|
|
/// <summary>
|
|
/// Raycast against the scene.
|
|
/// </summary>
|
|
/// <param name="eventData">Current event data.</param>
|
|
/// <param name="resultAppendList">List of hit Objects.</param>
|
|
public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
|
|
{
|
|
var currentInputModule = EventSystem.current != null ? EventSystem.current.currentInputModule : null;
|
|
if (currentInputModule == null)
|
|
return;
|
|
|
|
if (!GetWorldRay(eventData, out var worldRay, out var maxDistance, out var layerMask))
|
|
return;
|
|
|
|
maxDistance = Mathf.Min(maxDistance, EventSystem.current.uiToolkitInterop.worldPickingMaxDistance);
|
|
layerMask &= EventSystem.current.uiToolkitInterop.worldPickingLayers;
|
|
|
|
var pointerId = currentInputModule.ConvertUIToolkitPointerId(eventData);
|
|
|
|
var capturingCamera = PointerDeviceState.GetCameraWithSoftPointerCapture(pointerId);
|
|
if (capturingCamera != null)
|
|
{
|
|
var cam = m_EventCamera != null ? m_EventCamera : Camera.main;
|
|
if (capturingCamera != cam)
|
|
return;
|
|
}
|
|
|
|
if (!worldPicker.TryPickWithCapture(pointerId, worldRay, maxDistance, layerMask, out _,
|
|
out var document, out var elementUnderPointer, out var distance, out var captured))
|
|
return;
|
|
|
|
resultAppendList.Add(new RaycastResult
|
|
{
|
|
// Discard hits against non-UI objects. They should block UI but not hide the PhysicsRaycaster results.
|
|
gameObject = document == null ? gameObject : document.containerPanel.selectableGameObject,
|
|
origin = worldRay.origin,
|
|
worldPosition = worldRay.origin + distance * worldRay.direction,
|
|
document = document,
|
|
element = elementUnderPointer,
|
|
module = this,
|
|
distance = distance,
|
|
sortingOrder = captured ? int.MaxValue : 0,
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a ray from a given pointer event, according to this raycaster's properties.
|
|
/// Also allows the raycaster to constrain the distance and layers that the ray can use.
|
|
/// </summary>
|
|
/// <param name="eventData">Current event data.</param>
|
|
/// <param name="worldRay">The created ray.</param>
|
|
/// <param name="maxDistance">A distance constraint for the created ray.</param>
|
|
/// <param name="layerMask">A layer constraint for the created ray.</param>
|
|
/// <returns>Returns true if a valid ray could be created.</returns>
|
|
protected virtual bool GetWorldRay(PointerEventData eventData, out Ray worldRay, out float maxDistance, out int layerMask)
|
|
{
|
|
var cam = m_EventCamera != null ? m_EventCamera : Camera.main;
|
|
if (cam == null)
|
|
{
|
|
worldRay = default;
|
|
maxDistance = 0;
|
|
layerMask = 0;
|
|
return false;
|
|
}
|
|
|
|
maxDistance = cam.farClipPlane;
|
|
layerMask = cam.cullingMask;
|
|
|
|
Vector3 eventPosition = MultipleDisplayUtilities.GetRelativeMousePositionForRaycast(eventData);
|
|
|
|
// Discard events that are not part of this display so the user does not interact with multiple displays at once.
|
|
if ((int)eventPosition.z != cam.targetDisplay)
|
|
{
|
|
worldRay = default;
|
|
return false;
|
|
}
|
|
|
|
worldRay = cam.ScreenPointToRay(eventPosition);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
}
|