public static GetGraphicsForCanvas ( Canvas canvas ) : IList |
||
canvas | Canvas | Input canvas. |
리턴 | IList |
private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, List <GameObject> results) { // Necessary for the event system var foundGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas); s_SortedGraphics.Clear(); for (int i = 0; i < foundGraphics.Count; ++i) { Graphic graphic = foundGraphics[i]; // -1 means it hasn't been processed by the canvas, which means it isn't actually drawn if (graphic.depth == -1) { continue; } if (!RectTransformUtility.PointInRectangle(pointerPosition, graphic.rectTransform, eventCamera)) { continue; } if (graphic.Raycast(pointerPosition, eventCamera)) { s_SortedGraphics.Add(graphic); } } s_SortedGraphics.Sort((g1, g2) => g2.depth.CompareTo(g1.depth)); for (int i = 0; i < s_SortedGraphics.Count; ++i) { results.Add(s_SortedGraphics[i].gameObject); } }
private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, List <Graphic> results) { IList <Graphic> graphicsForCanvas = GraphicRegistry.GetGraphicsForCanvas(canvas); for (int i = 0; i < graphicsForCanvas.Count; i++) { Graphic graphic = graphicsForCanvas[i]; if (!graphic.canvasRenderer.cull) { if (graphic.depth != -1 && graphic.raycastTarget) { if (RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera)) { if (graphic.Raycast(pointerPosition, eventCamera)) { GraphicRaycaster.s_SortedGraphics.Add(graphic); } } } } } GraphicRaycaster.s_SortedGraphics.Sort((Graphic g1, Graphic g2) => g2.depth.CompareTo(g1.depth)); for (int j = 0; j < GraphicRaycaster.s_SortedGraphics.Count; j++) { results.Add(GraphicRaycaster.s_SortedGraphics[j]); } GraphicRaycaster.s_SortedGraphics.Clear(); }
private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, List <Graphic> results) { IList <Graphic> graphicsForCanvas = GraphicRegistry.GetGraphicsForCanvas(canvas); for (int i = 0; i < graphicsForCanvas.Count; i++) { Graphic item = graphicsForCanvas[i]; if ((!item.canvasRenderer.cull && (item.depth != -1)) && ((item.raycastTarget && RectTransformUtility.RectangleContainsScreenPoint(item.rectTransform, pointerPosition, eventCamera)) && item.Raycast(pointerPosition, eventCamera))) { s_SortedGraphics.Add(item); } } if (< > f__am$cache0 == null) {
private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, List <Graphic> results) { IList <Graphic> graphicsForCanvas = GraphicRegistry.GetGraphicsForCanvas(canvas); for (int index = 0; index < graphicsForCanvas.Count; ++index) { Graphic graphic = graphicsForCanvas[index]; if (graphic.depth != -1 && graphic.raycastTarget && (RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera) && graphic.Raycast(pointerPosition, eventCamera))) { GraphicRaycaster.s_SortedGraphics.Add(graphic); } } GraphicRaycaster.s_SortedGraphics.Sort((Comparison <Graphic>)((g1, g2) => g2.depth.CompareTo(g1.depth))); for (int index = 0; index < GraphicRaycaster.s_SortedGraphics.Count; ++index) { results.Add(GraphicRaycaster.s_SortedGraphics[index]); } GraphicRaycaster.s_SortedGraphics.Clear(); }
private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, List <Graphic> results) { // Debug.Log("ttt" + pointerPoision + ":::" + camera); // Necessary for the event system var foundGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas); for (int i = 0; i < foundGraphics.Count; ++i) { Graphic graphic = foundGraphics[i]; if (graphic.canvasRenderer.cull) { continue; } // -1 means it hasn't been processed by the canvas, which means it isn't actually drawn if (graphic.depth == -1 || !graphic.raycastTarget) { continue; } if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera)) { continue; } if (graphic.Raycast(pointerPosition, eventCamera)) { s_SortedGraphics.Add(graphic); } } s_SortedGraphics.Sort((g1, g2) => g2.depth.CompareTo(g1.depth)); // StringBuilder cast = new StringBuilder(); for (int i = 0; i < s_SortedGraphics.Count; ++i) { results.Add(s_SortedGraphics[i]); } // Debug.Log (cast.ToString()); s_SortedGraphics.Clear(); }
public override void Raycast(PointerEventData eventData, List <RaycastResult> resultAppendList) { if (canvas == null) { return; } var canvasGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas); if (canvasGraphics == null || canvasGraphics.Count == 0) { return; } //是否支持 MultiDisplay int displayIndex; var currentEventCamera = eventCamera; // Propery can call Camera.main, so cache the reference if (canvas.renderMode == RenderMode.ScreenSpaceOverlay || currentEventCamera == null) { displayIndex = canvas.targetDisplay; } else { displayIndex = currentEventCamera.targetDisplay; } var eventPosition = Display.RelativeMouseAt(eventData.position); if (eventPosition != Vector3.zero) { // We support multiple display and display identification based on event position. int 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 != displayIndex) { return; } } 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; // We dont really know in which display the event occured. We will process the event assuming it occured in our display. } // Convert to view space Vector2 pos; if (currentEventCamera == 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 = currentEventCamera.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 (currentEventCamera != null) { ray = currentEventCamera.ScreenPointToRay(eventPosition); } //通过两个属性来阻断射线检测部分; if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None) { float distanceToClipPlane = 100.0f; if (currentEventCamera != null) { float projectionDirection = ray.direction.z; distanceToClipPlane = Mathf.Approximately(0.0f, projectionDirection) ? Mathf.Infinity : Mathf.Abs((currentEventCamera.farClipPlane - currentEventCamera.nearClipPlane) / projectionDirection); } if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All) { if (ReflectionMethodsCache.Singleton.raycast3D != null) { var hits = ReflectionMethodsCache.Singleton.raycast3DAll(ray, distanceToClipPlane, (int)m_BlockingMask); if (hits.Length > 0) { hitDistance = hits[0].distance; } } } if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All) { if (ReflectionMethodsCache.Singleton.raycast2D != null) { var hits = ReflectionMethodsCache.Singleton.getRayIntersectionAll(ray, distanceToClipPlane, (int)m_BlockingMask); if (hits.Length > 0) { hitDistance = hits[0].distance; } } } } m_RaycastResults.Clear(); Raycast(canvas, currentEventCamera, eventPosition, canvasGraphics, m_RaycastResults); int totalCount = m_RaycastResults.Count; for (var index = 0; index < totalCount; index++) { var go = m_RaycastResults[index].gameObject; bool appendGraphic = true; //将背向 Camera 的对象过滤掉 if (ignoreReversedGraphics) { //判断当前 Graphic 方向与正方向 Vector3.forward 是否相交 if (currentEventCamera == 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 = currentEventCamera.transform.rotation * Vector3.forward; var dir = go.transform.rotation * Vector3.forward; appendGraphic = Vector3.Dot(cameraFoward, dir) > 0; } } //检测 Distance if (appendGraphic) { float distance = 0; if (currentEventCamera == null || canvas.renderMode == RenderMode.ScreenSpaceOverlay) { distance = 0; } else { Transform trans = go.transform; Vector3 transForward = trans.forward; // http://geomalgorithms.com/a06-_intersect-2.html distance = (Vector3.Dot(transForward, trans.position - ray.origin) / Vector3.Dot(transForward, ray.direction)); // Check to see if the go is behind the camera. if (distance < 0) { continue; } } if (distance >= hitDistance) { continue; } var castResult = new RaycastResult { gameObject = go, module = this, distance = distance, screenPosition = eventPosition, index = resultAppendList.Count, depth = m_RaycastResults[index].depth, sortingLayer = canvas.sortingLayerID, sortingOrder = canvas.sortingOrder }; resultAppendList.Add(castResult); } } }
public override void Raycast(PointerEventData eventData, List <RaycastResult> resultAppendList) { if (!(this.canvas == null)) { IList <Graphic> graphicsForCanvas = GraphicRegistry.GetGraphicsForCanvas(this.canvas); if (graphicsForCanvas != null && graphicsForCanvas.Count != 0) { Camera eventCamera = this.eventCamera; int targetDisplay; if (this.canvas.renderMode == RenderMode.ScreenSpaceOverlay || eventCamera == null) { targetDisplay = this.canvas.targetDisplay; } else { targetDisplay = eventCamera.targetDisplay; } Vector3 vector = Display.RelativeMouseAt(eventData.position); if (vector != Vector3.zero) { int num = (int)vector.z; if (num != targetDisplay) { return; } } else { vector = eventData.position; } Vector2 vector2; if (eventCamera == null) { float num2 = (float)Screen.width; float num3 = (float)Screen.height; if (targetDisplay > 0 && targetDisplay < Display.displays.Length) { num2 = (float)Display.displays[targetDisplay].systemWidth; num3 = (float)Display.displays[targetDisplay].systemHeight; } vector2 = new Vector2(vector.x / num2, vector.y / num3); } else { vector2 = eventCamera.ScreenToViewportPoint(vector); } if (vector2.x >= 0f && vector2.x <= 1f && vector2.y >= 0f && vector2.y <= 1f) { float num4 = 3.40282347E+38f; Ray r = default(Ray); if (eventCamera != null) { r = eventCamera.ScreenPointToRay(vector); } if (this.canvas.renderMode != RenderMode.ScreenSpaceOverlay && this.blockingObjects != GraphicRaycaster.BlockingObjects.None) { float f = 100f; if (eventCamera != null) { float z = r.direction.z; f = ((!Mathf.Approximately(0f, z)) ? Mathf.Abs((eventCamera.farClipPlane - eventCamera.nearClipPlane) / z) : float.PositiveInfinity); } if (this.blockingObjects == GraphicRaycaster.BlockingObjects.ThreeD || this.blockingObjects == GraphicRaycaster.BlockingObjects.All) { if (ReflectionMethodsCache.Singleton.raycast3D != null) { RaycastHit[] array = ReflectionMethodsCache.Singleton.raycast3DAll(r, f, this.m_BlockingMask); if (array.Length > 0) { num4 = array[0].distance; } } } if (this.blockingObjects == GraphicRaycaster.BlockingObjects.TwoD || this.blockingObjects == GraphicRaycaster.BlockingObjects.All) { if (ReflectionMethodsCache.Singleton.raycast2D != null) { RaycastHit2D[] array2 = ReflectionMethodsCache.Singleton.getRayIntersectionAll(r, f, this.m_BlockingMask); if (array2.Length > 0) { num4 = array2[0].distance; } } } } this.m_RaycastResults.Clear(); GraphicRaycaster.Raycast(this.canvas, eventCamera, vector, graphicsForCanvas, this.m_RaycastResults); int count = this.m_RaycastResults.Count; int i = 0; while (i < count) { GameObject gameObject = this.m_RaycastResults[i].gameObject; bool flag = true; if (this.ignoreReversedGraphics) { if (eventCamera == null) { Vector3 rhs = gameObject.transform.rotation * Vector3.forward; flag = (Vector3.Dot(Vector3.forward, rhs) > 0f); } else { Vector3 lhs = eventCamera.transform.rotation * Vector3.forward; Vector3 rhs2 = gameObject.transform.rotation * Vector3.forward; flag = (Vector3.Dot(lhs, rhs2) > 0f); } } if (flag) { float num5; if (eventCamera == null || this.canvas.renderMode == RenderMode.ScreenSpaceOverlay) { num5 = 0f; } else { Transform transform = gameObject.transform; Vector3 forward = transform.forward; num5 = Vector3.Dot(forward, transform.position - eventCamera.transform.position) / Vector3.Dot(forward, r.direction); if (num5 < 0f) { goto IL_4EE; } } if (num5 < num4) { RaycastResult item = new RaycastResult { gameObject = gameObject, module = this, distance = num5, screenPosition = vector, index = (float)resultAppendList.Count, depth = this.m_RaycastResults[i].depth, sortingLayer = this.canvas.sortingLayerID, sortingOrder = this.canvas.sortingOrder }; resultAppendList.Add(item); } } IL_4EE: i++; continue; goto IL_4EE; } } } } }
/// <summary> /// Perform the raycast against the list of graphics associated with the Canvas. /// GraphicRaycaster内围绕复写的基类的Raycast方法来展开(注意在GraphicRaycaster内部有另一个名为Raycast的私有静态方法,不要搞混)。 /// /// 整个函数代码很多,但是做的事情很简单,对于给定的PointerEventData,射线投射得出一些投射结果RaycastResult, /// 追加到传入的参数List<RaycastResult>之后。 /// </summary> /// <param name="eventData">Current event data</param> /// <param name="resultAppendList">List of hit objects to append new results to.</param> public override void Raycast(PointerEventData eventData, List <RaycastResult> resultAppendList) { if (canvas == null) { return; } // 获取当前 Canvas 下所有的 Graphic(canvasGraphics,这些 Graphics 在进行射线检测的时候会用到)。 var canvasGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas); if (canvasGraphics == null || canvasGraphics.Count == 0) { return; } int displayIndex; var currentEventCamera = eventCamera; // Property can call Camera.main, so cache the reference if (canvas.renderMode == RenderMode.ScreenSpaceOverlay || currentEventCamera == null) { //Canvas.targetDisplay => For Overlay mode, display index on which the UI canvas will appear. displayIndex = canvas.targetDisplay; } else { displayIndex = currentEventCamera.targetDisplay; } // Display.RelativeMouseAt => Query relative mouse coordinates. // RelativeMouseAt can be used to query relative mouse input coordinates and the screen in which Mouse Input is recorded. // This is only valid on the Windows Desktop platforms with Multiple Displays. // x, y returns the coordinates in relative space and z returns the screen in which Mouse Input is handled. // Display.RelativeMouseAt(...)方法用于获取鼠标的相对位置,在PC平台下可能会有多个Display窗口,返回的z表示的是Display的id。 // 如果不支持多个Display则返回值的z为0,此时获取到的就是eventData.position; var eventPosition = Display.RelativeMouseAt(eventData.position); if (eventPosition != Vector3.zero) { // We support multiple display and display identification based on event position. int eventDisplayIndex = (int)eventPosition.z; // Discard events that are not part of this display so the user does not interact with multiple displays at once. // 当平台支持 MultiDisplay 时,如果用户操作的不是当前的 Display,那么所有的其他 Display 上产生的事件都会被舍弃。 if (eventDisplayIndex != displayIndex) { return; } } 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; // We dont really know in which display the event occured. We will process the event assuming it occured in our display. } // Convert to view space // 获取正确的pos:将上一步的屏幕坐标eventPosition转换成ViewPort坐标pos,这里同样也处理了多Display的情况。 // 获取eventCamera不为null则直接调用相机的坐标转换方法ScreenToViewportPoint Vector2 pos; if (currentEventCamera == 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 = currentEventCamera.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; } // Distance from camera to target point. // 获取正确的hitDistance:这里分别处理blockingObjects 为不同的枚举值时的情况(默认值为None)。 // hitDistance表示相机到投射目标点的距离。后边会根据这个距离值筛选掉一部分Graphic; // m_BlockingMask是LayerMask用于按层筛选投射目标; // 这里的ReflectionMethodsCache.Singleton.raycast3D这样的方法实际上调用的就是Physics.Raycast(...)方法 float hitDistance = float.MaxValue; Ray ray = new Ray(); if (currentEventCamera != null) { // Camera.ScreenPointToRay => Returns a ray going from camera through a screen point. // Resulting ray is in world space, starting on the near plane of the camera // and going through position's (x,y) pixel coordinates on the screen (position.z is ignored). // Screen space is defined in pixels. The bottom-left of the screen is (0,0); the right-top is (pixelWidth -1,pixelHeight -1). ray = currentEventCamera.ScreenPointToRay(eventPosition); } // Canvas renderMode 不为 RenderMode.ScreenSpaceOverlay 并且设置了 blockingObjects, // 此时就会 Blocked Objects 和 Blocked Mask 就会生效。 if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None) { float distanceToClipPlane = 100.0f; if (currentEventCamera != null) { float projectionDirection = ray.direction.z; distanceToClipPlane = Mathf.Approximately(0.0f, projectionDirection) ? Mathf.Infinity : Mathf.Abs((currentEventCamera.farClipPlane - currentEventCamera.nearClipPlane) / projectionDirection); } if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All) { if (ReflectionMethodsCache.Singleton.raycast3D != null) { // ReflectionMethodsCache.Singleton.raycast3D这样的方法实际上调用的就是Physics.Raycast(...) // raycast3DAll 时指定了射线检测层 m_BlockingMask,这个参数就是自定义设定的 Blocking Mask, // 属于 block mask 的对象在这里就会就行射线检测,并得到最小的一个 hitDistance; // 后面对所有的 Graphics 进行射线检测时,如果检测结果 distance 大于 hitDistance,那么那个结果会被舍弃。 // 如此一来,Blocking Mask 就起到了阻挡的作用,属于这个 layer 的所有对象的一旦被射线检测成功并得到 hitDistance, // PhysicsRaycaster 最后的射线检测结果都只会包含这个 hitDistance 距离以内的对象。 var hits = ReflectionMethodsCache.Singleton.raycast3DAll(ray, distanceToClipPlane, (int)m_BlockingMask); if (hits.Length > 0) { hitDistance = hits[0].distance; } } } if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All) { if (ReflectionMethodsCache.Singleton.raycast2D != null) { var hits = ReflectionMethodsCache.Singleton.getRayIntersectionAll(ray, distanceToClipPlane, (int)m_BlockingMask); if (hits.Length > 0) { hitDistance = hits[0].distance; } } } } m_RaycastResults.Clear(); Raycast(canvas, currentEventCamera, eventPosition, canvasGraphics, m_RaycastResults); // 判断对应的GameObject是否有效appendGraphic,即是否继续处理追加该Graphic到射线投射结果的列表 int totalCount = m_RaycastResults.Count; for (var index = 0; index < totalCount; index++) { var go = m_RaycastResults[index].gameObject; bool appendGraphic = true; // 如果ignoreReversedGraphics ,则只是追加朝向为正的Graphic if (ignoreReversedGraphics) { if (currentEventCamera == 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 = currentEventCamera.transform.rotation * Vector3.forward; var dir = go.transform.rotation * Vector3.forward; appendGraphic = Vector3.Dot(cameraFoward, dir) > 0; } } if (appendGraphic) { float distance = 0; Transform trans = go.transform; Vector3 transForward = trans.forward; if (currentEventCamera == null || canvas.renderMode == RenderMode.ScreenSpaceOverlay) { distance = 0; } else { // http://geomalgorithms.com/a06-_intersect-2.html // 计算 Graphic 和 Camera 之间的向量在 Graphic 正方向上的投影以及计算射线方向在 Graphic 正方向上的投影, // 两者相除就得到最终的 distance。 distance = (Vector3.Dot(transForward, trans.position - ray.origin) / Vector3.Dot(transForward, ray.direction)); // Check to see if the go is behind the camera. if (distance < 0) { continue; } } if (distance >= hitDistance) { continue; } var castResult = new RaycastResult { gameObject = go, module = this, distance = distance, screenPosition = eventPosition, index = resultAppendList.Count, depth = m_RaycastResults[index].depth, sortingLayer = canvas.sortingLayerID, sortingOrder = canvas.sortingOrder, worldPosition = ray.origin + ray.direction * distance, worldNormal = -transForward }; resultAppendList.Add(castResult); } } }
/// <summary> /// Perform a raycast into the screen and collect all graphics underneath it. /// </summary> private void Raycast(List <Canvas> canvases, Camera eventCamera, Vector2 pointerPosition, List <Graphic> results) { var workspaceTest = new Predicate <Graphic>( // Unity's original test, with modifications from voidALPHA to perform less intensive tests first g => !g.raycastTarget || !RectTransformUtility.RectangleContainsScreenPoint(g.rectTransform, pointerPosition, eventCamera) || g.depth == -1 || !g.Raycast(pointerPosition, eventCamera) ); var choreoTest = new Predicate <Graphic>( // Unity's original test, with modifications from voidALPHA to perform less intensive tests first g => !g.raycastTarget || !RectTransformUtility.RectangleContainsScreenPoint(g.rectTransform, pointerPosition, null) || g.depth == -1 || !g.Raycast(pointerPosition, null) ); foreach (var canvas in canvases) { AllWorkspaceGraphics.AddRange(GraphicRegistry.GetGraphicsForCanvas(canvas)); // Stick all graphics for canvas into list } if (ChoreoCanvas) { AllChoreoGraphics.AddRange(GraphicRegistry.GetGraphicsForCanvas(ChoreoCanvas)); } if (AllWorkspaceGraphics.Count + AllChoreoGraphics.Count != LastKnownGraphicCount) // Graphics count changed { HierarchyCacheDictionary.Clear(); // Clear out cached dictionary and root graphic lists RootWorkspaceGraphics.Clear(); RootChoreoGraphics.Clear(); if (SatelliteUpdateLord.Instance.NodesProcessing) // We're still processing nodes; perform slower non-cached tests while nodes come up. // This provides raycast functionality while generating and is still faster than caching information every frame. { if (Choreography.Views.TimelineViewBehaviour.StepPicker.gameObject.activeInHierarchy || pointerPosition.y < Choreography.Views.TimelineViewBehaviour.Instance.CurrentHeight) { AllChoreoGraphics.RemoveAll(choreoTest); foreach (var graphic in AllChoreoGraphics) { SortedGraphics.Add(graphic); } } else if (ChainView.Instance.Visible) { AllWorkspaceGraphics.RemoveAll(workspaceTest); foreach (var graphic in AllWorkspaceGraphics) { SortedGraphics.Add(graphic); } } LastKnownGraphicCount = 0; // Zero out known Graphic count to force the Raycaster to attempt caching again on next raycast. } else { transformTester.Refresh(AllWorkspaceGraphics, transform); foreach (var g in AllWorkspaceGraphics) // Not processing nodes, do a lot of work up front to improve later speed of calculations { HierarchyCacheDictionary[g] = new List <Graphic>(); // Initialize the list of Children for this Graphic g.transform.GetComponentsInChildren(HierarchyCacheDictionary[g]); // Ask Unity for the list of Graphics under this Graphic, store it in the cache var p = g.transform.parent; if (transformTester.TestTransform(p)) // If no ancestor is a Graphic { RootWorkspaceGraphics.Add(g); // This Graphic will need to be among the first to be tested } } transformTester.Refresh(AllChoreoGraphics, ChoreoCanvas.transform); foreach (var g in AllChoreoGraphics) // Do the same for the Choreography Canvas { HierarchyCacheDictionary[g] = new List <Graphic>(); g.transform.GetComponentsInChildren(HierarchyCacheDictionary[g]); var p = g.transform.parent; if (transformTester.TestTransform(p)) { RootChoreoGraphics.Add(g); } } LastKnownGraphicCount = AllWorkspaceGraphics.Count + AllChoreoGraphics.Count; } } // If we're working against cached graphic lists (ie nodes aren't currently being populated) prepare for the hierarchy-based test var test = workspaceTest; if (Choreography.Views.TimelineViewBehaviour.StepPicker.gameObject.activeInHierarchy || pointerPosition.y < Choreography.Views.TimelineViewBehaviour.Instance.CurrentHeight) { // Mouse is in the Choreography area, perform Choreography tests. test = choreoTest; foreach (var g in RootChoreoGraphics) { GraphicsToTest.Enqueue(g); } } else if (ChainView.Instance.Visible) { foreach (var g in RootWorkspaceGraphics) { GraphicsToTest.Enqueue(g); } } while (GraphicsToTest.Count > 0) { var g = GraphicsToTest.Dequeue(); if (SortedGraphics.Contains(g)) { continue; } if (!test(g)) { foreach (var gr in HierarchyCacheDictionary[g]) { if (gr == g) { continue; } GraphicsToTest.Enqueue(gr); } SortedGraphics.Add(g); } } var sgraphics = new List <Graphic>(SortedGraphics); sgraphics.Sort((g1, g2) => g2.depth.CompareTo(g1.depth)); for (int i = 0; i < sgraphics.Count; ++i) { results.Add(sgraphics[i]); } // Ready the lists for the next run. AllWorkspaceGraphics.Clear(); AllChoreoGraphics.Clear(); SortedGraphics.Clear(); }