public abstract class BaseRaycaster : UIBehaviour public class GraphicRaycaster : BaseRaycaster public class PhysicsRaycaster : BaseRaycaster public class Physics2DRaycaster : PhysicsRaycaster
本系列主要是阅读分析UGUI代码,所以只讨论GraphicRaycaster相关的内容。
BaseRaycaster
所有的Raycaster的基类,提供了一个抽象方法Raycast(...)交由子类实现:
1
public abstract void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList);
[NonSerialized] private List<Graphic> m_RaycastResults = new List<Graphic>(); public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList) { if (canvas == null) return;
var eventPosition = Display.RelativeMouseAt(eventData.position);
int displayIndex = canvas.targetDisplay;
// Discard events that are not part of this display so the user does not interact with multiple displays at once. if (eventPosition.z != displayIndex) return;
// 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. if (eventPosition.z == 0) eventPosition = eventData.position;
// Convert to view space Vector2 pos; if (eventCamera == null) { // Multiple display support only when not the main display. For display 0 the reported // resolution is always the desktops resolution since its part of the display API, // so we use the standard none multiple display method. (case 741751) float w = Screen.width; float h = Screen.height; if (displayIndex > 0 && displayIndex < Display.displays.Length) { w = Display.displays[displayIndex].systemWidth; h = Display.displays[displayIndex].systemHeight; } pos = new Vector2(eventPosition.x / w, eventPosition.y / h); } else pos = eventCamera.ScreenToViewportPoint(eventPosition);
// If it's outside the camera's viewport, do nothing if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f) return;
float hitDistance = float.MaxValue;
Ray ray = new Ray();
if (eventCamera != null) ray = eventCamera.ScreenPointToRay(eventPosition);
for (var index = 0; index < m_RaycastResults.Count; index++) { var go = m_RaycastResults[index].gameObject; bool appendGraphic = true;
if (ignoreReversedGraphics) { if (eventCamera == null) { // If we dont have a camera we know that we should always be facing forward var dir = go.transform.rotation * Vector3.forward; appendGraphic = Vector3.Dot(Vector3.forward, dir) > 0; } else { // If we have a camera compare the direction against the cameras forward. var cameraFoward = eventCamera.transform.rotation * Vector3.forward; var dir = go.transform.rotation * Vector3.forward; appendGraphic = Vector3.Dot(cameraFoward, dir) > 0; } }
while (t != null) { t.GetComponents(components); for (var i = 0; i < components.Count; i++) { var canvas = components[i] as Canvas; if (canvas != null && canvas.overrideSorting) continueTraversal = false;
var filter = components[i] as ICanvasRaycastFilter;
if (filter == null) continue;
var raycastValid = true;
var group = components[i] as CanvasGroup; if (group != null) { if (ignoreParentGroups == false && group.ignoreParentGroups) { ignoreParentGroups = true; raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } else if (!ignoreParentGroups) raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } else { raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); }
if (!raycastValid) { ListPool<Component>.Release(components); return false; } } t = continueTraversal ? t.parent : null; } ListPool<Component>.Release(components); return true; }
private GameObject m_GameObject; // Game object hit by the raycast
public GameObject gameObject { get { return m_GameObject; } set { m_GameObject = value; } }
public BaseRaycaster module; // Event system that hit this object public float distance; // The distance from the origin this hit was. public float index; // The index this element is in the raycastList (used for sorting) public int depth; public int sortingLayer; public int sortingOrder; // World-space position where a ray cast into the screen hits something public Vector3 worldPosition; // World-space normal where a ray cast into the screen hits something public Vector3 worldNormal;
public Vector2 screenPosition;
public bool isValid { get { return module != null && gameObject != null; } }
public void RaycastAll(PointerEventData eventData, List<RaycastResult> raycastResults) { raycastResults.Clear(); var modules = RaycasterManager.GetRaycasters(); for (int i = 0; i < modules.Count; ++i) { var module = modules[i]; if (module == null || !module.IsActive()) continue;
private static int RaycastComparer(RaycastResult lhs, RaycastResult rhs) { if (lhs.module != rhs.module) { if (lhs.module.eventCamera != null && rhs.module.eventCamera != null && lhs.module.eventCamera.depth != rhs.module.eventCamera.depth) { // need to reverse the standard compareTo if (lhs.module.eventCamera.depth < rhs.module.eventCamera.depth) return 1; if (lhs.module.eventCamera.depth == rhs.module.eventCamera.depth) return 0;
return -1; }
if (lhs.module.sortOrderPriority != rhs.module.sortOrderPriority) return rhs.module.sortOrderPriority.CompareTo(lhs.module.sortOrderPriority);
if (lhs.module.renderOrderPriority != rhs.module.renderOrderPriority) return rhs.module.renderOrderPriority.CompareTo(lhs.module.renderOrderPriority); }
if (lhs.sortingLayer != rhs.sortingLayer) { // Uses the layer value to properly compare the relative order of the layers. var rid = SortingLayer.GetLayerValueFromID(rhs.sortingLayer); var lid = SortingLayer.GetLayerValueFromID(lhs.sortingLayer); return rid.CompareTo(lid); }
if (lhs.sortingOrder != rhs.sortingOrder) return rhs.sortingOrder.CompareTo(lhs.sortingOrder);
if (lhs.depth != rhs.depth) return rhs.depth.CompareTo(lhs.depth);
if (lhs.distance != rhs.distance) return lhs.distance.CompareTo(rhs.distance);
public override int sortOrderPriority { get { // We need to return the sorting order here as distance will all be 0 for overlay. if (canvas.renderMode == RenderMode.ScreenSpaceOverlay) return canvas.sortingOrder;
return base.sortOrderPriority; } }
public override int renderOrderPriority { get { // We need to return the sorting order here as distance will all be 0 for overlay. if (canvas.renderMode == RenderMode.ScreenSpaceOverlay) return canvas.renderOrder;