关于Unity中的NGUI优化,你可能遇到这些问题_ngui ui移出屏幕-程序员宅基地

技术标签: unity  厚积薄发| Unity优化  优化  NGUI  

原文链接:https://blog.uwa4d.com/archives/QA_NGUI-1.html

关键字

界面制作
界面切换
网格重建
UICamera.Update
Draw Call
加载
字体


一、界面制作

Q1:我用的是NGUI,本来已经打包图集了,输出时候是不是就不用理会那些原始2D Sprite图 ?粒子贴图需要Packing Tag吗?

在NGUI中使用Atlas后,原纹理是不需要进行打包或进行其他特殊处理的,因为理论上这些资源在运行时已不再需要。粒子系统所使用的纹理并不是Sprite类型的,因此不需要设置Packing Tag。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58dbba664e69b5ed22e68ab4

Q2:NGUI变形,如下图走样了,请问是不是图片压缩导致的?
请输入图片描述

当UI纹理在设备上的显示分辨率低于原始分辨率时,会因为出现aliasing现象,导致UI局部变形。通常对于粗线条、块状的UI图素,变形通常是不明显的,但对于细线条的UI图素,则可能非常明显。
通常该问题可以考虑三种方式来改善:

  1. 在NGUI中将UIRoot的Scaling Style设置为Flexible,这种方式的好处在于UI纹理不会因为设备分辨率的限制而降低,而缺点在于相同的UI纹理在高分辨率设备上显得比较小,而在低分辨率设备上显得比较大,从而提高了UI布局的复杂度;
  2. 将UI纹理的显示分辨率(Sprite的size属性)设定为高于原始分辨率,其缺点在于高分辨率设备上可能会产生模糊,但大多数情况下“模糊”相比于“走样”更不易察觉;
  3. 开启UI纹理的Mipmap,从而在低分辨率设备上自动切换到低Level,以“模糊”替换“走样”,但缺点在于增加了纹理的大小,因此只适用于出现了明显变形的少量UI。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d49f5dc5233b18793e0c4b

Q3:能否在NGUI多分辨率适应方面提供一些解决方案或者思路?

多分辨率适应涉及到以下几个方面:

  1. 布局。通常可以通过 NGUI 中的 Anchor 组件来实现,能够保证 UI 到屏幕上指定锚点的距离;
  2. UI 背景图比例。通常我们建议将背景图的长宽比放大,以适配不同长宽比的屏幕,但要注意两边需要留空,或者保留可被裁掉的元素;
  3. UI 的整体缩放。可以通过 UIRoot 组件的 Scaling Style 来统一配置。

需要提醒的是,不同类型的游戏对布局的需求通常也不同,因此还是需要结合实际开发情况来做调整。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d2930c9ad5c0094f461e66

Q4:我看到UICamera.Update()的GC调用特别高,只要我一移动就会产生2.8K的GC,看起来是NGUITools.FindInParents这个方法导致的,有没有什么可以优化的方法呢?

请输入图片描述
请输入图片描述

在 Editor 下,当调用GetComponent() 且 T组件并不在当前的GameObject 上时,确实会出现GC Alloc,但这在发布后是不会出现的,因此建议在真机上做一个验证。这是因为在Editor下,Unity的MissingComponentException实现所致,在出现以上情况时,Unity 并不是直接返回一个 NULL,而是返回一个代理 Object用来储存一些相关信息,在后续被访问时可以给出更详细的报错信息。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d29ccb4ecd88b86cb570d5

二、网格重建

Q1:我用NGUI开发,因为角色名字导致重建,使得UIPanel.LateUpdate的CPU占用很高。如果将它们分离到多个UIPanel里,是否这个开销会相对小一些?

将较多的动态UI元素分组放在不同的UIPanel中确实是UWA比较推荐的方式,一方面可以降低重建的概率,某些分组中可能没有UI元素发生变化,从而不会进行重建;另一方面可以降低重建的开销。通过分组,可以将每个UIPanel所产生的Mesh控制在较小的范围内,从而控制其重建的开销(通常重建的开销会因Mesh的增大而明显升高,且不是线性的关系)。虽然这种做法会产生额外的DrawCall,但DrawCall的开销与网格重建相比通常都非常小。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d259d97dc35e7f0efb4738

Q2:我的UWA报告中看到几乎每次切换场景都会有UIPanel.LateUpdate()这个函数的堆内存开销,请问说明了什么问题,我是否还能优化?
请输入图片描述

UIPanel.LateUpdate持续分配较大量的堆内存,说明UI界面在制作上存在以下问题:

  1. Panel中Widgets数量过多,且存在频繁的变动,导致UIPanel需要进行大量的网格重建;
  2. 动静态UI元素没有分离;
  3. 建议研发团队对UI界面的制作进行进一步检测,尽可能将静态UI元素和动态UI元素分开,存放于不同的Panel下。同时,对于不同频率的动态元素也建议存放于不同的Panel中。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d259167dc35e7f0efb4734

Q3:UWA建议“尽可能将静态UI元素和频繁变化的动态UI元素分开,存放于不同的Panel下。同时,对于不同频率的动态元素也建议存放于不同的Panel中。”那么请问,如果把特效放在Panel里面,需要把特效拆到动态的里面吗?

通常特效是指粒子系统,而粒子系统的渲染和UI是独立的,仅能通过Render Order来改变两者的渲染顺序,而粒子系统的变化并不会引起UI部分的重建,因此特效的放置并没有特殊的要求。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d29af75a5050b366a6b6ab

三、界面切换

Q1:我在Profiler中看到GameObject.Deactivate耗时较大,请问该如何优化?

实际上GameObject.Activate/Deactivate本身通常不会产生很高的开销,主要都是由其上或其子节点上的组件的OnEnable/OnDisable操作引起,比如UI相关的组件在OnEnable和OnDisable中都会有较多的操作,所以较复杂的UI界面的GameObject.Activate/Deactivate会有很高的开销。因此,针对这一问题,如果是由自定义的脚本造成,那么就需要考虑优化OnEnable/OnDisable的逻辑;如果是UI,那么可以对频繁切换激活状态的UI采用平移出屏幕、修改Culling Layer等方式来替换。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58dba87a96a4860c52acada7

Q2:游戏中出现UI界面重叠,该怎么处理较好?比如当前有一个全屏显示的UI界面,点其中一个按钮会再起一个全屏界面,并把第一个UI界面盖住。我现在的做法是把被覆盖的界面 SetActive(False),但发现后续 SetActive(True) 的时候会有 GC.Alloc 产生。这种情况下,希望既降低 Batches 又降低 GC Alloc 的话,有什么推荐的方案吗?

可以尝试通过添加一个 Layer 如 OutUI, 且在 Camera 的 Culling Mask 中将其取消勾选(即不渲染该 Layer)。从而在 UI 界面切换时,直接通过修改 UIPanel 的 Layer 来实现“隐藏”。但需要注意事件的屏蔽,禁用动态的 UI 元素等等。
这种做法的优点在于切换时基本没有开销,也不会产生多余的 Draw Call,但缺点在于“隐藏时”依然还会有一定的持续开销(通常不太大),而其对应的 Mesh 也会始终存在于内存中(通常也不太大)。
以上的方式可供参考,而性能影响依旧是需要视具体情况而定。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58dd18e84e69b5ed22e68ad7

Q3:通过移动位置来隐藏UI界面,会使得被隐藏的UIPanel继续执行更新(LateUpdate有持续开销),那么如果打开的界面比较多,CPU的持续开销是否就会超过一次SetActive所带来的开销?

这确实是需要注意的,通过移动的方式“隐藏”的UI界面只适用于几个切换频率最高的界面,另外,如果“隐藏”的界面持续开销较高,可以考虑只把一部分Disable,这个可能就需要具体看界面的复杂度了。一般来说在没有UI元素变化的情况下,持续的 Update 开销是不太明显的。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58dd18a54e69b5ed22e68ad5

Q4:如图,我们在UI打开或者移动到某处的时候经常会观测到CPU上的冲激,经过进一步观察发现是因为Instantiate产生了大量的GC。想请问下Instantiate是否应该产生GC呢?我们能否通过资源制作上的调整来避免这样的GC呢?如下图,因为一次性产生若干MB的GC在直观感受上还是很可观的。
请输入图片描述

准确的说这些 GC Alloc 并不是由Instantiate 直接引起的,而是因为被实例化出来的组件会进行 OnEnable 操作,而在 OnEnable 操作中产生了 GC,比如以上图中的函数为例:

上图中的 UILabel.OnEnable 是在实例化一个 UI 界面时,UI 中的文本(即 UILabel 组件)进行了 OnEnable 操作,其中主要是初始化文本网格的信息(每个文字所在的网格顶点,UV,顶点色等等属性),而这些信息都是储存在数组中(即堆内存中),所以文本越多,堆内存开销越大。但这是不可避免的,只能尽量减少出现次数。

因此,我们不建议通过 Instantiate/Destroy 来处理切换频繁的 UI 界面,而是通过 SetActive(true/false),甚至是直接移动 UI 的方式,以避免反复地造成堆内存开销。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d3d663dae058bb3c56af47

四、字体

Q1:对NGUI字体错乱有什么好的解决方案吗?

有这么几种可能:

  1. 一次展开文字太多了。这种情况在部分高通机型和Unity早期版本上都经常出现,现在也偶尔有,究其原理是FontTexture的扩容操作做得不够快或者收到了硬件驱动的限制。
    一般来说有两种方法可以解决:(1)减少面板中的字体内容;(2)一开始就用超大量的字体去扩容,将动态字体的FontTexture扩大到足够大;
  2. 文字渲染与开发团队编写的多线程渲染发生了冲突。这种情况也常有发生,特别是通过GL.IssuePluginEvent方式来开启多线程渲染的项目,就会容易出现问题。
    就我们的优化经验来看,第一种情况发生的可能性比较大。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d2558d7dc35e7f0efb4728

Q2:我在用Profiler真机查看iPhone App时,发现第一次打开某些UI时,Font.CacheFontForText占用时间超过2s,这块主要是由什么影响的?若iPhone5在这个接口消耗2s多,是不是问题很大?这个消耗和已经生成的RenderTexture的大小有关吗?

Font.CacheFontForText主要是指生成动态字体Font Texture的开销, 一次性打开UI界面中的文字越多,其开销越大。如果该项占用时间超过2s,那么确实是挺大的,这个消耗也与已经生成的Font Texture有关系。简单来说,它主要是看目前Font Texture中是否有地方可以容下接下来的文字,如果容不下才会进行一步扩大Font Texture,从而造成了性能开销。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58dbad6b09b061fe195d60b4

五、加载相关

Q1:加载UI预制的时候,如果把特效放到预制里,会导致加载非常耗时。怎么优化这个加载时间呢?

UI和特效(粒子系统)的加载开销在多数项目中都占据较高的CPU耗时。UI界面的实例化和加载耗时主要由以下几个方面构成:

1. 纹理资源加载耗时
UI界面加载的主要耗时开销,因为在其资源加载过程中,时常伴有大量较大分辨率的Atlas纹理加载,我们在之前的Unity加载模块深度分析之纹理篇有详细讲解。对此,我们建议研发团队在美术质量允许的情况下,尽可能对UI纹理进行简化,从而加快UI界面的加载效率。
请输入图片描述

2. UI网格重建耗时
UI界面在实例化或Active时,往往会造成Canvas(UGUI)或Panel(NGUI)中UIDrawCall的变化,进而触发网格重建操作。当Canvas或Panel中网格量较大时,其重建开销也会随之较大。

3. UI相关构造函数和初始化操作开销
这部分是指UI底层类在实例化时的ctor开销,以及OnEnable和OnDisable的自身开销。

上述2和3主要为引擎或插件的自身逻辑开销,因此,我们应该尽可能避免或降低这两个操作的发生频率。我们的建议如下:

  1. 在内存允许的情况下,对于UI界面进行缓存。尽可能减少UI界面相关资源的重复加载以及相关类的重复初始化;
  2. 根据UI界面的使用频率,使用更为合适的切换方式。比如移进移出或使用Culling Layer来实现UI界面的切换效果等,从而降低UI界面的加载耗时,提升切换的流畅度。
  3. 对于特效(特别是粒子特效)来说,我们暂时并没有发现将UI界面和特效耦合在一起,其加载耗时会大于二者分别加载的耗时总和。因此,我们仅从优化粒子系统加载效率的角度来回答这个问题。粒子系统的加载开销,就目前来看,主要和其本身组件的反序列化耗时和加载数量相关。对于反序列化耗时而言,这是Unity引擎负责粒子系统的自身加载开销,开发者可以控制的空间并不大。对于加载数量,则是开发者需要密切关注的,因为在我们目前看到的项目中,不少都存在大量的粒子系统加载,有些项目的数量甚至超过1000个,如下图所示。因此,建议研发团队密切关注自身项目中粒子系统的数量使用情况。一般来说,建议我们建议粒子系统使用数量的峰值控制在400以下。
    请输入图片描述

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58d25a537dc35e7f0efb4740

Q2:我有一个UI预设,它使用了一个图集, 我在打包的时候把图集和UI一起打成了AssetBundle。我在加载生成了GameObject后立刻卸载了AssetBundle对象, 但是当我后面再销毁GameObject的时候发现图集依然存在,这是什么情况呢?

这是很可能出现的。unload(false)卸载AssetBundle并不会销毁其加载的资源 ,是必须调用 Resources.UnloadUnusedAssets才行。关于AssetBundle加载的详细解释可以参考我们之前的文章:你应该知道的AssetBundle管理机制。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/58da55111ccdfe463a4f87c7
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/UWA4D/article/details/78376093

智能推荐

unity3d 实现简单水墨画效果_unity3d shader 水墨动画-程序员宅基地

文章浏览阅读6.6k次,点赞2次,收藏8次。水墨效果,素材简陋:文章参考http://gad.qq.com/article/detail/18724,原理可以看这位大佬的文章,我就贴上自己工程源码:https://download.csdn.net/my_unity3d shader 水墨动画

(Java毕业设计)招聘信息管理系统(基于java+springboot)附源码_java人力资源管理系统招聘管理-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏17次。在Internet高速发展的今天,我们生活的各个领域都涉及到计算机的应用,其中包括招聘信息管理系统的网络应用,在外国招聘信息管理系统已经是很普遍的方式,不过国内的线上管理系统可能还处于起步阶段。招聘信息管理系统具有招聘信息管理功能的选择。_java人力资源管理系统招聘管理

冯诺依曼、哈佛、RISC、CISC_冯诺依曼曼指令和数据区分-程序员宅基地

文章浏览阅读1.3w次,点赞5次,收藏20次。几个基础材料(源:http://jwc.seu.edu.cn/zq/signal/new/importent/zhang5_6/feng.htmhttp://jwc.seu.edu.cn/zq/signal/new/importent/zhang5_6/harvard.htmhttp://dingjun.net/dingjun/html/14/84FB43402106C575.html_冯诺依曼曼指令和数据区分

Netty——深入解析心跳检测机制_netty 服务端心跳检测-程序员宅基地

文章浏览阅读428次。客户端定时每X秒(推荐小于60秒)向服务端发送特定数据(任意数据都可),服务端设定为X秒没有收到客户端心跳则认为客户端掉线,并关闭连接触发onClose回调。当需要服务端定时给客户端发送心跳数据时, $gateway->pingData设置为服务端要发送的心跳请求数据,心跳数据是任意的,只要客户端能识别即可。当设置为服务端主动发送心跳时,如果客户端最近有发来数据,那么证明客户端存活,服务端会省略一个心跳,下个心跳大约1.5*$gateway->pingInterval秒后发送。心跳检测时间间隔 单位:秒。_netty 服务端心跳检测

linux内核SPI总线驱动分析(一)_linux spi驱动总线分析-程序员宅基地

文章浏览阅读535次。下面有两个大的模块:一个是SPI总线驱动的分析 (研究了具体实现的过程)另一个是SPI总线驱动的编写(不用研究具体的实现过程)SPI总线驱动分析 1 SPI概述 SPI是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口,是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应_linux spi驱动总线分析

Nginx,nginx-rtmp-module-master搭建直播平台-程序员宅基地

文章浏览阅读511次。Nginx,nginx-rtmp-module-master搭建直播平台_nginx-rtmp-module-master

随便推点

出行大数据,滴滴发布400城数据可视化分析_滴滴出行数据-程序员宅基地

文章浏览阅读2.1w次,点赞2次,收藏35次。转 一:出行大数据,滴滴发布400城数据可视化分析 2018年01月04日 00:00:00https://blog.csdn.net/zw0Pi8G5C1x/article/details..._滴滴出行数据

智能算法综述_为什么智能算法不会出现两次快速下降-程序员宅基地

文章浏览阅读1.1k次。 智能算法综述1 什么是智能算法 智能计算也有人称之为“软计算”,是人们受自然(生物界)规律的启迪,根据其原理,模仿求解问题的算法。从自然界得到启迪,模仿其结构进行发明创造,这就是仿生学。这是我们向自然界学习的一个方面。另一方面,我们还可以利用仿生原理进行设计(包括设计算法),这就是智能计算的思想。这方面的内容很多,如人工神经网络技术、遗传算法、模拟退火算法、模拟退火技术和群集智能技术_为什么智能算法不会出现两次快速下降

Open3d学习计划——高级篇 12(交互式可视化)–最终章-程序员宅基地

文章浏览阅读4.4k次,点赞4次,收藏27次。Open3d学习计划——高级篇 12(交互式可视化)本篇教程介绍了Open3d的可视化窗口的交互功能。# examples/Python/Advanced/interactive_visualization.pyimport numpy as npimport copyimport open3d as o3ddef demo_crop_geometry(): print("Demo for manual geometry cropping") print( _open3d学习计划

springboot2.x The character [_] is never valid in a domain name_springboot the character [_] is never valid in a d-程序员宅基地

文章浏览阅读1k次。访问springcloud工程, springboot版本为2.1.15 ,使用域名访问接口报400但是直接用ip不报错。发现是集成的tomcat版本不支持域名下划线。大约是8.5.31以后的版本不支持带下划线的域名,但是也没办法降低版本了,会有很多冲突。先搁置。..._springboot the character [_] is never valid in a domain name.

QEMU 运行 RISC-V 64 位 Linux_qemu启动riscv环境-程序员宅基地

文章浏览阅读420次。QEMU 运行 RISC-V 64 位 Linux_qemu启动riscv环境

一年对于程序员来说有多长?_程序员 一年多少秒-程序员宅基地

文章浏览阅读4.3k次。聊这个话题,我表示又蛋疼了!你想看么?还没写过这么有争议的话题,有点小小的不安!一年有多长?让我来掐指算一算:1年=365天(今年是366天)=多少小时呢?前方高能,等我去写个程序算一下!还用写程序吗?早有人写好了!有多少分有多少秒,又有多少毫秒呢?我们只需要选择一下单位就好了,结果是:1年(yr)=31536000000毫秒(ms)为什么聊这个话题?蛋当然不可能说疼就疼了!水是有源的,树是有根的_程序员 一年多少秒