|
问题出现的原因:
GraphicRaycaster.get_eventCamera();
Graphic.get_canvasRenderer();优化方式:
GraphicRaycaster.get_eventCamera()
这个函数使用来获取当前UI的摄像机的,但是实际上相机都是与各个Canvas绑定的,按理来说一旦初始化之后,只要游戏内没有更改过相机,那么就应该一直是原来的相机。
继承重写Canvas中的eventCamera
public class YHGraphicRaycaster : GraphicRaycaster
{
public Camera TargetCamera;
public override Camera eventCamera
{
get
{
if (TargetCamera == null)
{
TargetCamera = base.eventCamera;
}
return TargetCamera;
}
}
}在不修改游戏内UI相机的情况下,可以这样优化,替换原来的Canvas脚本(可以从源码中修改,可能会出现意外的bug),这个操作是Unity为了兼容性做的动态获取摄像机,在项目中如果可以确定,可以不必动态获取
Graphic.get_canvasRenderer()
这个函数Unity本身是有对应的缓存操作的。在优化的方向上只能通过对调用次数的减少,来增加效率 从源码分析上看到,,其实UGUI在获取到很多点击控件的时候会对其进行排序。
如果项目中只需要响应最顶层的UI响应,可以值返回最顶层的UI 如果涉及到UI穿透,对应最顶层下的UI也是不必要排序的,因为这里只是每个Canvas下面的UI元素排序,再收集完各个Canvas的点击元素之后,UGUI会再进行一次排序,最后选择最上层的UI元素
[NonSerialized] static readonly List<Graphic> s_SortedGraphics = new List<Graphic>();
private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, IList<Graphic> foundGraphics, List<Graphic> results)
{
int totalCount = foundGraphics.Count;
Graphic upGraphic = null;
int upIndex = -1;
for (int i = 0; i < totalCount; ++i)
{
Graphic graphic = foundGraphics;
int depth = graphic.depth;
if (depth == -1 || !graphic.raycastTarget || graphic.canvasRenderer.cull)
continue;
if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera))
continue;
if (eventCamera != null && eventCamera.WorldToScreenPoint(graphic.rectTransform.position).z > eventCamera.farClipPlane)
continue;
if (graphic.Raycast(pointerPosition, eventCamera))
{
s_SortedGraphics.Add(graphic);
if (depth > upIndex)
{
upIndex = depth;
upGraphic = graphic;
}
}
}
if (upGraphic != null)
results.Add(upGraphic);
}因为,这个方法是没有重载的,所以需要在脚本中添加另外一个Raycast方法的重写。(不用修改,直接复制就可以了) 经过这样的优化,可以减少depth,和CanvasRenderer的调用,从而减少耗时
在项目中,会有一些Get_Canvas的耗时,如果可以接受,可以不用优化 因为再缓存中对Canvas会进行判空的操作,如果没有对应的Canvas上的修改,可以不用判空直接在Awake中赋值,减少判空的耗时 相对应的CanvasRender也可以修改判空的逻辑修改。 对应的可以重载Image中的Awake,直接获取组件上的CanvasRender组件 并且对应的depth也可以使用CanvasRender.absoluteDepth属性直接获取,不做缓存
如果需要优化这一部分,可以在YHGraphicRaycaster脚本中添加对应的获取方法:
/// <summary>
/// 获取层级;
/// </summary>
/// <param name=&#34;gra&#34;></param>
/// <returns></returns>
public static int GetGraphicDepth(Graphic graphic)
{
if (graphic is YHImage)
{
return (graphic as YHImage).depth;
}
return graphic.depth;
}
/// <summary>
/// 获取CanvasRenderer;
/// </summary>
/// <param name=&#34;gra&#34;></param>
/// <returns></returns>
public static CanvasRenderer GetGraphicCanvasRenderer(Graphic graphic)
{
if (graphic is YHImage)
{
return (graphic as YHImage).canvasRenderer;
}
return graphic.canvasRenderer;
}然后将对应脚本中根据Graphic中获取depth和canvasRenderer的地方都替换为这两种方法
经过这些优化,可以修改对应的Raycast方法,来减少depth的调用次数; 这里添加一个Raycast2方法,因为对应Graphic中RaycastTarget如果没有勾选,就不用判断depth相关的操作所以:
/// <summary>
/// Perform a raycast into the screen and collect all graphics underneath it.
/// </summary>
private static void Raycast2(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, IList<Graphic> foundGraphics, List<Graphic> results)
{
int totalCount = foundGraphics.Count;
Graphic upGraphic = null;
int upIndex = -1;
for (int i = 0; i < totalCount; ++i)
{
Graphic graphic = foundGraphics;
//不响应点击事件的就不要执行了;
if (!graphic.raycastTarget) continue;
//层级;
int depth = GetGraphicDepth(graphic);
if (depth == -1 || GetGraphicCanvasRenderer(graphic).cull)
continue;
if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera))
continue;
if (eventCamera != null && eventCamera.WorldToScreenPoint(graphic.rectTransform.position).z > eventCamera.farClipPlane)
continue;
if (graphic.Raycast(pointerPosition, eventCamera))
{
if (depth > upIndex)
{
upIndex = depth;
upGraphic = graphic;
}
}
}
if (upGraphic != null)
results.Add(upGraphic);
} |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|