namespaceUnityEngine.UI { [AddComponentMenu("Event/Graphic Raycaster")] [RequireComponent(typeof(Canvas))] ///<summary> /// A derived BaseRaycaster to raycast against Graphic elements. ///</summary> publicclassGraphicRaycaster : BaseRaycaster { ///<summary> /// Perform the raycast against the list of graphics associated with the Canvas. ///</summary> ///<param name="eventData">Current event data</param> ///<param name="resultAppendList">List of hit objects to append new results to.</param> publicoverridevoidRaycast(PointerEventData eventData, List<RaycastResult> resultAppendList) { //... var canvasGraphics = GraphicRegistry.GetRaycastableGraphicsForCanvas(canvas);//获取当前Canvas下所有Graphic子组件 //... var currentEventCamera = eventCamera; // 确认事件相机,默认是主相机 //获取当前的显示器 if (canvas.renderMode == RenderMode.ScreenSpaceOverlay || currentEventCamera == null) displayIndex = canvas.targetDisplay; else displayIndex = currentEventCamera.targetDisplay; //... //下面是根据显示器获取分辨率的逻辑,将主显示映射到pos这个变量里(),pos是介于0~1的。如果是在副显示器操作就直接返回 Vector2 pos; if (currentEventCamera == null) { //... } //... //根据Graphic Raycast中设置的BlockingObjects和renderMode获取hitDistance,即射线击中的距离 if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None) { #if PACKAGE_PHYSICS //... hitDistance = hits[0].distance; #endif #if PACKAGE_PHYSICS2D hitDistance = hits[0].distance; #endif } //... Raycast(canvas, currentEventCamera, eventPosition, canvasGraphics, m_RaycastResults);//这是一个静态重载,Raycast筛选的主要逻辑 //根据上面的筛选,得到m_RaycastResults int totalCount = m_RaycastResults.Count; for (var index = 0; index < totalCount; index++) { var go = m_RaycastResults[index].gameObject; bool appendGraphic = true;
if (ignoreReversedGraphics)//筛选是否一个反面的元素,交给appendGraphic { //... } if (appendGraphic)//如果是一个正面的元素,筛选是否在相机的背面 { //... if (distance >= hitDistance)//这里通过一个公式计算出了当前元素和摄像机的距离distance,它要小于hitDistance(点击击中的最远距离)才行 continue; var castResult = new RaycastResult { //... } resultAppendList.Add(castResult);//最终的结果都要加入结果的list中 } } } //... ///<summary> /// Perform a raycast into the screen and collect all graphics underneath it. ///</summary> [NonSerialized] staticreadonly List<Graphic> s_SortedGraphics = new List<Graphic>(); //这个方法主要对Graphic的状态进行筛选 privatestaticvoidRaycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, IList<Graphic> foundGraphics, List<Graphic> results) { // Necessary for the event system int totalCount = foundGraphics.Count; for (int i = 0; i < totalCount; ++i) { Graphic graphic = foundGraphics[i];
// graphic的深度是-1就表示当前UI元素根本不会绘制在屏幕上 //如果UI元素没有打开raycastTarget,也被过滤掉 if (!graphic.raycastTarget || graphic.canvasRenderer.cull || graphic.depth == -1) continue; //判断当前点击事件是否在目标物体的Rect里面 if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera, graphic.raycastPadding)) continue; //当前点击事件的z坐标是否超出了相机的最远面 if (eventCamera != null && eventCamera.WorldToScreenPoint(graphic.rectTransform.position).z > eventCamera.farClipPlane) continue; //使用Grapic.Raycast判断,主要是判断当前组件是否继承ICanvasRaycastFilter接口,具体可见源码 if (graphic.Raycast(pointerPosition, eventCamera)) { s_SortedGraphics.Add(graphic); } }
s_SortedGraphics.Sort((g1, g2) => g2.depth.CompareTo(g1.depth));//进行深度排序 totalCount = s_SortedGraphics.Count; for (int i = 0; i < totalCount; ++i) results.Add(s_SortedGraphics[i]);