原文:http://gad.qq.com/college/articledetail/7191053

注[1]:该比较是基于15年-16年期间使用NGUI(3.8.0版本)与UGUI(4.6.9版本)所得

注[2]:仅对工作中经常接触到的功能做总结,如有疏漏,欢迎指正讨论

渊源

先来段小八卦,听说UGUI的主创人员是从NGUI招过去的,所以,UGUI中有很多概念,对于用过NGUI的童鞋来说,看起来都似曾相识。

先来个概念对比:

  NGUI UGUI
锚点 Anchor RectTransform Anchor
图片 Sprite Image
文字 Label Text
根节点 UIRoot Canvas
UI面板 Panel Canvas
UI容器 uiWidget Panel
事件交互 Collider EventSystem
单张贴图 Texture RawImage
UI相机 camera + UICamera camera + EventSystem

再看下UI主要的通用几个组件:

  NGUI UGUI
Button
Toggle
Scroll Bar
Progress Bar
Input Field
Popup List ×
Localization ×
Play Sound ×
Scroll View

总体来说,对于基本的UI元素, NGUI与UGUI都有;在组件的丰富度上,UGUI略逊于NGUI。例如,UGUI没有Localization、Play Sound组件;NGUI的Label是支持静态图文混排跟文字URL超链接的,而UGUI不支持。所以使用UGUI的时候需要自行开发以上缺失的组件及功能。

差异化

RectTransform

UGUI采用RectTransform的概念,将NGUI中的Transform+Widget+Anchor的功能,封装了起来。

  UGUI NGUI
Pivot RectTransform Widget
Width、Height RectTransform Widget
x、y、z RectTransform Transform
Anchor RectTransform Anchor
 

相对于NGUI的Anchor可以直接对某个GO进行锚点而言,UGUI新的锚点设计显然只能针对父节点来进行,是做不到跨层级锚点的,丧失了灵活性;但是也解决了NGUI多重锚点之间,由于时序问题,控件“锚飞了”的情况。

比较难理解的,应该是Anchor按比例锚点做相对布局的情况,普通的使用方法,可以参考Unity的官方文档[1],这里不展开。

要使用脚本来修改UI控件,情况就会变得比较复杂,需要理解绝对布局(anchor四个角都在一起)跟相对布局(anchor四个角分开,会按父控件的百分比来定义该控件)的情况。同时,也要理解Transform与anchoredPosition的关系。

曾经碰到过一个问题,UI偶现消失。后来发现是因为开始创建的时候没有对Localposition做重置,UGUI会通过anchoredPosition来重置Transform的x跟y,但没有重置z值,所以z值是乱的,所以当Z值大于UICamera的Clip范围的时候,就会被裁剪掉,消失了。

层级管理概念

UGUI采用Hierarchy排序的方式,替代了NGUI中的Depth排序。

更精准的说,NGUI的排序是通过Depth、Z值、RenderQueue共同影响的,整体规则过于复杂;而UGUI采用的排序比较简单,在Canvas内部元素采用Hierarchy方式排序,在Canvas同级之间通过Sort Order或者是Hierarchy来进行排序;UI的组织方式,就是层级的可见顺序,跟平常的认知具有一致性。

3DMesh嵌套问题

通常UI开发中都会存在UI与Unity3DMesh嵌套的需求,特别常见的是角色与粒子特效。通常有两种方案来处理嵌套。第一种方案是将3DMesh渲染到一张RenderTexture中,再用这张RenderTexture来与其他的UI做排序。这种方案在UGUI与NGUI中都可用,比较适合角色这种渲染目标唯一并使用控件唯一的需求。

另一种方案是将3DMesh的渲染与UI一起排序,UGUI跟NGUI都没有提供将Unity3DMesh内嵌为一个UI元素进行排序的功能。

在NGUI中,官方论坛推荐使用一个脚本来动态修改Mesh的RenderQueue,达到跟UI排序的目的。具体逻辑是每帧获取目标UI的RenderQueue,同步更改Mesh的RenderQueue。因为NGUI默认的排序方式,是每个drawcall对应一个3000以上的RenderQueue。

在UGUI中,采用的是Sorting Order的方式来做排序,需要修改的是粒子Renderer的Sorting Order来跟UI进行排序。所以使用Sorting Order来管理canvas之间的层级关系时,需要留出足够的Order厚度来支持Canvas内部元素嵌套使用粒子特效。

Mask裁剪

NGUI中的Mask裁剪,是通过透明度裁剪实现的;UGUI中的Mask裁剪,是通过Stancil裁剪实现的。透明度裁剪,需要在shader中做额外的透明度因子计算,并且被裁剪掉的像素(透明度为0的像素)还是会参与到后续的Blending等渲染流程;Stancil裁剪,需要额外一个pass来渲染mask区域,但没通过Stencil的像素会被丢弃,不参与后续渲染流程。权衡下来,UGUI的做法会更省一点。特别是被裁剪区域特别大,或者区域内重叠框体特别多的情况。

3DMesh裁剪

在UI的mask组件内部层级嵌套使用3DMesh时,粒子也需要被裁剪。NGUI与UGUI都需要对嵌套的3DMesh做裁剪处理。

图集管理模式

UGUI不再使用自定义Atlas资源,image中使用的是Sprite,图集可以用Unity提供的Sprite Picker来合成。

NGUI抛弃了Unity的Sprite组件,自定义了一套图集资源及管理模式(Atlas),提供合图工具、Sprite选取窗口、并提供了对单个资源做静态深加工(加阴影、轮廓)的功能。

UGUI整合了Unity的Sprite,使用Sprite Picker来做合图集,功能上简化了许多,但可以直接从Unity的Project窗口中直接把Sprite或者Multiple sprite中的某个Sprite直接拖到Image中,操作上简化了些。

对于小型游戏UI来说,UGUI的简化版功能会更便捷些。但是对于MMORPG这种有复杂UI层级的游戏来说,使用UGUI的自动合图集,由于可控度太低,大概率会造成内存浪费,或者Drawcall Issue。所以,复杂UI层级的游戏,使用NGUI的图集管理模式,可控度会更高些。在UGUI中,可以通过使用第三方工具(如TexturePicker)合图后转成Multiple Sprite来达到跟NGUI相似的可控度。

采用Multiple Sprite有个缺点,不能直接动态加载这个MultipleSprite中包含的某个Sprite,需要使用LoadAll接口将该图集所有的Sprite都加载以后,再遍历对比出所需的Sprite。而Unity的LoadAll函数,是会对Resource中所有文件进行遍历的。当Resource中的文件数量非常庞大的时候,遍历耗时会造成性能卡顿。

这个问题,可以通过将自定义Altas中的Sprite导出成Prefab,并提供一个Sprite Prefab的加载缓存管理器即可。除此之外,精简Resource中的文件数量也是一种很好的方案。“Best Practices for the Resources System —— Don't use it”。[2]

渲染性能

Batch算法

NGUI的Panel内部排序:在Widget新增时,是通过Insert到List中进行排序的,整个算法的时间复杂度是O(n),元素越多,效率越差。在Rebuild时,直接遍历WidgetList,按材质、贴图、shader来拆drawcall,进行batch。

UGUI的canvas内部排序:由于没有明确的指定次序,UGUI需要按照顺序,对每个UI控件遍历出相交情况,再查看是否可以合批,算法比NGUI更复杂些(判断相交的算法有优化,时间复杂度小于O(n2))。

Native Code 优势

然而,NGUI实质上是创建自定义Mesh,使用Mesh Renderer来做渲染的。对UI的合批操作逻辑在C#层。UGUI定义了Canvas组件,使用Canvas Renderer来做渲染,在C++层做合批逻辑,所以UGUI处理动态层的性能会比NGUI更佳。

对于有频繁动画需求的UI,使用UGUI会比使用NGUI有性能优势。

EventSystem & Raycasters

UGUI中采用Event&Raycasters的设计,来替代NGUI中的Collider&sendMessage。

在NGUI中,默认控件是不参与交互的,除非加上Collider;而在UGUI中,默认控件是参与交互的,除非使用canvas Group组件来禁止交互(在5.x版本中,可以通过去掉勾选raycast Target来禁止)。所以在使用UGUI的过程中,突然发现某个点击无效了,可以优先考虑是否是最近有人添加新的Text把消息遮挡了。

NGUI的交互事件是通过SendMessage来发送消息的,SendMessage的性能比较差,Delegate与SendMessage的性能测算,前者会快10倍左右[3]。UGUI的交互事件改为通过事件回调机制来发送消息,对于交互输入这种比较频繁调用的消息来说,性能上提升不少,比较直接反馈是scroll view的滑动流畅度。

Layout布局

UGUI的布局,采用Layout组件群(Layout Element、GridLayoutGroup、Content Size Fitter等),来替代NGUI中的Table跟Grid。

对于UGUI来说,Layout是比较费的组件,因为每次被标记Dirty时,它需要重算所有的子元素的大小跟位置。一般来说,只用在跟内容的相对大小相对位置有关联的复杂布局中。例如说scrollview中动态添加新Item或者是文本背景纹理需要根据文本的长宽动态变化的时候[4]。

平时可以在编辑模式下,用Layout组件来辅助界面快速布局。另外比较小规模的相对布局(如2*2table),可以使用RectTransform的Anchor替代。因为RectTransform的计算是在C++层发生的,比同等的Layout更效率

UI动画

NGUI整合了ITween,并将ITween的使用封装成脚本,可以非常方便制作出各种旋转、平移、缩放的效果,易用性很强。

UGUI官方文档建议是采用Unity的Animation System来制作UI动画[5],但是使用Animation动画有个比较明显的缺陷,在UI频繁显隐的时候(Active/Inactive),Animator会重新Rebind一次Controller,导致无意义的性能损耗,所以UGUI的动画实现,可以有另一个option,通过整合DoTween来实现。Dotween不存在Animation的反复初始化问题,并且它使用了一些缓存策略,相对于ITween来说,每帧耗时更短,效率更高,产生GC更少。[6]

总结

从易用性角度来看,NGUI比UGUI好用一点点

NGUI的工具支持度更高:

Drawcall Tool,可以查看UI的Drawcall分布以及哪些元素影响了Drawcall分布,可以很方便的调整顺序优化Drawcall;

Prefab Toolbar,可以将Prefab模板直接保存成可视态,通过拖曳到Hierarchy创建新组合;

Editor Right - Click Menu, 在编辑场景中,右键弹出的操作菜单,可以在多重叠控件中,拾取某一个,或者对某个控件进行层级操作。在开发多层级复杂UI的时候,这个功能是可以提升效率的。

ITween, NGUI整合了ITween并提供了封装后的使用脚本,可以很方便快捷的完成UI的动画需求,如旋转、缩放、变色、移动等。

UGUI的概念封装更好,可视化更高:

将层级管理改为Hierarchy排序以后,比较符合人类认知;

对于可交互空间的navigation顺序,可以直接给出可视图;

深度利用Unity的内核,如Inspector,Sprite等;

从可扩展性来看,UGUI略逊NGUI一点点

UGUI与NGUI都可以通过简单组件组合,来满足大多数的需求;也可以通过继承扩展现有组件来满足特殊需求;

NGUI更极端一点,可以通过直接修改源码来满足需求。UGUI虽然也开放了源码,但只是C#部分,C++部分是无法做改动的。

从性能来看,UGUI比NGUI有底层优势

UGUI的排序及合批逻辑都在C++层处理,效率更高;

采用EventSystem的分发模式,效率更高;

结论

除以上总结外,UGUI还有几个优势:全免费、官方身份、跟Unity可深度融合(多线程)等。

选用UGUI应该是趋势,因为性能是关键, 易用性可以通过开发辅助工具或者扩展组件来弥补。随着使用者越来越多,UGUI会越来越强大。

Reference

[1]  Unity Manual - UI - Base Layout

[2]  Best Practices -- The Resources folder

[3]  Unity3D的Delegate和SendMessage的性能差测试

[4]  UGUI中实现底图自适应size的方法

[5]  Unity Manual - UI - Animation Integration

[6]  Unity CPU占用-DoTween与iTween效率对比

【转】UGUI VS NGUI的更多相关文章

  1. uGUI VS NGUI

    前言 这篇日志的比较是根据自己掌握知识所写的,请各路大神多多指教. 引擎版本: Unity 4.6 beta 两者区别 1.uGUI的Canvas 有世界坐标和屏幕坐标 2.uGUI的Button属性 ...

  2. 转:UGUI与NGUI的区别与优缺点

    1. NGUI与UGUI的区别 1) uGUI的Canvas 有世界坐标和屏幕坐标   2) uGUI的Image可以使用material     3) UGUI通过Mask来裁剪,而NGUI通过Pa ...

  3. UGUI实现NGUI的UIEventListener功能

    在unity中处理UI事件时,习惯了使用NGUI的UIEventListener,虽然UGUI也有AddListener,但是一个组件只能对应一个函数,不能在一个函数中同时处理多个事件,显得有些麻烦 ...

  4. UGUI和NGUI的优化分享

    学习资料 来自UWA的分享,针对于Unity 4.x 及5.3 以下版本,Unity5.5及更高版本可能适用. 文章:UWA技术直播视频集锦 UGUI &NGUI http://blog.uw ...

  5. Unity3D 使用Socket处理数据并将数据 在UGUI、NGUI上显示出来

    Unity3d 不支持C#的线程直接调用Unity3D 主线程才能实现的功能.例如:给UGUI text 赋值.改变Color值等.怎样解决这个问题呢?使用一个Loom脚本. 按照惯例贴上代码. 首先 ...

  6. Unity NGUI和UGUI与模型、特效的层级关系

    目录 1.介绍两大UI插件NGUI和UGUI 2.unity渲染顺序控制方式 3.NGUI的控制 4.UGUI的控制 5.模型深度的控制 6.粒子特效深度控制 7.NGUI与模型和粒子特效穿插层级管理 ...

  7. 如何快速优化手游性能问题?从UGUI优化说起

    WeTest 导读   本文作者从自身多年的Unity项目UI开发及优化的经验出发,从UGUI,CPU,GPU以及unity特有资源等几个维度,介绍了unity手游性能优化的一些方法.   在之前的文 ...

  8. 用uGUI开发自定义Toggle Slider控件

    一.前言 写完<Unity4.6新UI系统初探>后,我模仿手机上的UI分别用uGui和NGUI做了一个仅用作演示的ToggleSlider,我认为这个小小的控件已能体现自定义控件的开发过程 ...

  9. ugui的优化

    参考文章 https://www.jianshu.com/p/061e67308e5f https://www.jianshu.com/p/8a9ccf34860e http://blog.jobbo ...

随机推荐

  1. 未能加载文件或程序集“System.Web.Http, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)解决办法

    1.查看引用处是否确实引用, 2.查看<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1& ...

  2. 2018.6.18 MyEclipse导入jquery-1.8.0.min.js等文件报错的解决方案

    MyEclipse导入jQuery-1.8.0.min.js等文件的时候有时候会报了一堆missing semicolon的错误.怎么解决这个报错呢?方法如下: 1.选中报错的jquery文件例如&q ...

  3. 基础I/O

    基础IO: c库文件IO操作接口:(详细查看c语言中的文件操作函数总结:https://www.cnblogs.com/cuckoo-/p/10560640.html) fopen 打开文件 fclo ...

  4. 在docker镜像中加入环境变量

    原文链接 前言 reference:https://vsupalov.com/docker-build-time-env-values/ 很多时候,我们需要在docker镜像中加入环境变量,本人了解的 ...

  5. Oracle 配置文件目录

    Oracle 配置文件目录 ① 在oracle安装目录下,找D:\oracle\product\10.2.0\client_1\NETWORK\ADMIN中的tnsnames.ora文件,找到之后,配 ...

  6. Bzoj 1081 [Ahoi2009] chess 中国象棋

    bzoj 1081 [Ahoi2009] chess 中国象棋 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1801 状态比较难设,的确 ...

  7. Mysql关闭和修改密码

    数据库的关闭方法: 1.优雅的关闭数据库的方法:mysqladmin -uroot -p123456 shutdown 2.脚本关闭:/etc/init.d/mysqld stop 3.使用kill信 ...

  8. 04构建之法读书笔记——IT行业的创新

    IT行业的创新: 1.创新的迷思: 灵光一闪现,伟大的创新就紧随其后:大家都喜欢创新:好的想法会赢:创新者都是一马当先:要成为领域的专家,才能创新:技术的创新是关键:成功的团队更能创新 2.创新的时机 ...

  9. music21 关联 MuseScore 和 Lilypond

    在python安装 music21后,需要关联 musescore 或 lilypond 才能可以用图形化的形式看到 乐谱. 因此 在安装 music21后,需要配置环境变量,yvivid 在 mus ...

  10. (转)CocoaPods

    本文转自http://nshipster.cn/cocoapods/ 文明是建立在道路,桥梁,运河,下水道,管线,电线和光纤这些基础设施之上的.只要设计和施工得当,它们可以帮助社会成倍的发展. 唯一的 ...