有时候会发现 Unity UI 非常耗时,在 Profiler 中可以轻易的看到 UI 中 的 GraphicRaycaster.Raycast 单帧调用可以成百上千,甚至好几千,帧速率前不忍赌,一关掉 UI 立马满血复活。
     这种情况大多出现在一是 Canvas 比较多而且子节点添加 GraphicRaycaster  组件也比较多的情况;二是每个 Canvas 下面有很多个 UI 面板,而每次其实显示的只有那么几个,不用的隐藏 SetActive(false),使用的激活显示 SetActive(true)。
     第一种情况就只能自己根据需求进行简化,不要滥用了 Canvas,优化和精简自己的设计;第二种情况看起来貌似没什么问题,实际上正是帧速率大大下降的元凶。
     说第二种没问题主要是符合 Unity 的使用基本原则,而且大家容易想到的使用方式,那为什么有问题,那要先看看一点相关 UI 的工作模式。每个 Graphic 组件(包括所有继承自 Graphic 的组件)都必须要通过 GraphicRegistry.RegisterGraphicForCanvas 注册到 GraphicRegistry 中,Graphic 中能够引起注册的事件有:OnTransformParentChanged(),OnEnable(),OnCanvasHierarchyChanged();OnEnable() 这个不必说就是组件激活时的回调,其它两个 OnTransformParentChanged(), OnCanvasHierarchyChanged() 理论上应该只在控件可用 Enable 和 Active 的时候才会被调用,或者说才应该产生 GraphicRegistry.RegisterGraphicForCanvas 的注册过程,而现在的代码是只有 OnTransformParentChanged() 在 GraphicRegistry.RegisterGraphicForCanvas 之前检测了 IsActive(),而 OnCanvasHierarchyChanged() 却未做任何检测,即使挂接了 Graphic 的对象在 Unity 的 Inspector 中处于非激活状态,启动游戏后 OnCanvasHierarchyChanged() 依然会被调用,导致该 Graphic 被注册进 GraphicRegistry,并且最终参与了 GraphicRaycaster.Raycast,造成了 CPU 周期的浪费。
     总而言之,这应该是 Unity UI 系统的一个 bug,本来从 BitBucket 上 Fork 了想修改下提交,但是发现无法 clone,很是奇怪,暂时搁置了,既然暂时无法修改源码,官方也没有修改,那么暂时的解决方案就是在启动后,手动清理每个 Canvas 下在 GraphicRegistry 中注册的 Graphic,将所有 IsActive() 为 false 的组件通过 GraphicRegistry.UnregisterGraphicForCanvas 从 GraphicRegistry 中移除即可,达到曲线救国的目的。
 

关于 Unity UI 中 GraphicRaycaster.Raycast 数量巨大的问题的更多相关文章

  1. unity ui中使用onmouseover

    unity ui中鼠标移进或者移出的触发方式与2d.3d的不同,2d.3d物体使用的是onmouseover,ui使用的是OnPointerEnter.需要实现以下两个接口. public class ...

  2. Unity UI性能优化技巧

    本文将介绍一些提升Unity UI性能的技巧.更多优化技巧,可以观看Unity工程师Ian Dundore在Unite Europe 2017的演讲<使用Unity性能提升技巧>. 1.划 ...

  3. Unity优化方向——优化Unity游戏中的图形渲染(译)

    CPU bound:CPU性能边界,是指CPU计算时一直处于占用率很高的情况. GPU bound:GPU性能边界,同样的是指GPU计算时一直处于占用率很高的情况. 原文:https://unity3 ...

  4. i3D的一篇Unity教程中的笔记

    原地址:http://blog.sina.com.cn/s/blog_72b936d80100wwej.html 以下是i3D的一篇Unity教程中的笔记. i3D的这篇教程是[i3D.Next-Ge ...

  5. [译]如何在Unity编辑器中添加你自己的工具

    在这篇教程中你会学习如何扩展你的Unity3D编辑器,以便在你的项目中更好的使用它.你将会学习如何绘制你自己的gizmo,用代码来实现创建和删除物体,创建编辑器窗口,使用组件,并且允许用户撤销他们所作 ...

  6. 关于Unity项目中创建项目遇到的一些问题

    1.Unity调用Android的方法默认不是在UI线程执行,所以在Android上写一些页面的重绘的方法,让Unity去调用时,注意要在Android中添加对应的runOnUiThread才可以: ...

  7. Unity UI 基础【译】

    https://unity3d.com/cn/learn/tutorials/topics/best-practices/fundamentals-unity-ui?playlist=30089 理解 ...

  8. Unity 3D中不得不说的yield协程与消息传递

    1. 协程 在Unity 3D中,我们刚开始写脚本的时候肯定会遇到类似下面这样的需求:每隔3秒发射一个烟花.怪物死亡后20秒再复活之类的.刚开始的时候喜欢把这些东西都塞到Update里面去,就像下面这 ...

  9. Unity UI相关总结

    UIGrid 加载面板时,如果面板中含有大容量的 UIGrid,可能会很卡.我们可以只加载 UIGrid 的前 n 个单元格对象,在显示面板之后,利用协程加载剩余的所有单元格,每帧加载 m 个. 同样 ...

随机推荐

  1. memcached全面剖析--2

    理解memcached的内存存储 下面是<memcached全面剖析>的第二部分. 发表日:2008/7/9 作者:前坂徹(Toru Maesaka) 原文链接:http://gihyo. ...

  2. 解决使用 Composer 的时候提示输入 Token

    Could not fetch https://api.github.com/repos/RobinHerbots/jquery.inputmask/contents/bower.json?ref=0 ...

  3. (转载)ADOQuery参数传递

    ADOQuery参数传递 dbgrid1.DataSource := datasource1; datasource1.DataSet := adoquery1; Value := 1221; SQL ...

  4. 【Hades】ades是一个开源库,基于JPA和Spring构建,通过减少开发工作量显著的改进了数据访问层的实现

    几乎每个应用系统都需要通过访问数据来完成工作.要想使用领域设计方法,你就需要为实体类定义和构建资源库来实现领域对象的持久化.目前开发人员经常使用JPA来实现持久化库.JPA让持久化变得非常容易,但是仍 ...

  5. C# zip/unzip with DotNet framework 4.5

    add reference System.IO.Compression.FileSystem public class ZipHelper { public static string UnZip(s ...

  6. iOS 8 定位失败问题

    首先plist定义两个string:  NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription 然后调用 [self. ...

  7. xxx couldn't be loaded because it has not been added to the build settings.

    这个由于没有将进入场景放入Build Settings里面造成的.

  8. Linux系统备份与还原

    在使用Ubuntu之前,相信很多人都有过使用Windows系统的经历.如果你备份过Windows系统,那么你一定记忆犹新:首先需要找到一个备份工 具(通常都是私有软件),然后重启电脑进入备份工具提供的 ...

  9. apt-get用法

    转自apt-get语法- - 对于debian来说,安装软件大多都是通过apt-get来实现的. 1.apt-get update 更新软件包信息库.在Debian中,软件包是通过一个数据库来管理的, ...

  10. WINDOWS 2008 SERVER域用户自动登陆

    The user I wanted to auto-logon as didn’t have a password, this reg hack worked instead: HKEY_LOCAL_ ...