找回密码
 立即注册
查看: 203|回复: 0

Unity UGUI update优化

[复制链接]
发表于 2022-9-28 12:45 | 显示全部楼层 |阅读模式
问题出现的原因:
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="gra"></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="gra"></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);

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-7-4 09:14 , Processed in 0.089556 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表