首页 > Unity3D频道 > 【NGUI研究院之Unity插件】 > NGUI研究院之UISprite和UITexture浅谈(十二)
2014
06-05

NGUI研究院之UISprite和UITexture浅谈(十二)


NGUI的三大组件,UILabel、UISprite、UITexture,
它们三个同时都继承UIWidget。先回到一个很郁闷的话题上,到底是优化DrawCall还是优化内存。

UISprite :  NGUI引入图集的概念,不考虑ABA叠层的情况下,一个图集内的图片用UISprite,那么它就是一个DrawCall。但是如果你做了一个图集是1024X1024的。此时你的界面上只用了图集中的一张很小的图,那么很抱歉1024X1024这张大图都需要载入你的内存里面,1024就是4M的内存,如果你做了10个1024的图集,你的界面上刚好都只用了每个图集里面的一张小图,那么再次抱歉你的内存直接飙40M。另外生成出来的Atlas我记得默认会打开mipMap的选项,mipMap是摄像机离得远近用不同的图片,用来减少渲染,可是UI绝对不会出现远近之分,mipMap会让你的包占更大的容量,因为是两张图。

如下图所示,Atlas图集生成完以后,选择Advanced,不要勾选Generate Mip Maps ,也不要勾选Read/Write Enabled ,不然1024在内存里就不4M了将变成8M。。

 NGUI研究院之UISprite和UITexture浅谈(十二) - 雨松MOMO程序研究院 - 1

 

那么NGUI的内存怎么施放呢?我建议最好不要手动施放,因为Unity有一套非常完善自动施放内存的方法。如果你的项目不变态,切场景的时候就用异步切换场景。

 我发现很多人喜欢切场景的时候,在调用一下Resources.unloadunnsedAssets,这是多此一举的。

当场景切换完毕后,Unity会自动施放没有被引用的内存。 我记得NGUI3.X某一个版本是存在内存泄漏的问题,后来我们专门升级了新版本,扯远了,回到正题!

UITexture:它完全没有图集的概念,使用起来非常的灵活,只需要把图片挂上去就行了。这样内存里只会占用你这一张图的大小,内存虽然小了但是DrawCall就上去了。因为每一张UITexture就是一次DrawCall。如果你发现你的UITexture图片大小不对了,是因为图片拖进Unity默认图片的格式会设置成Texture,它的NonPower of2 是默认打开的,所以他会缩放你的图片成2的幂次方,所以你可以把图片格式改成GUI。

NGUI研究院之UISprite和UITexture浅谈(十二) - 雨松MOMO程序研究院 - 2

图片格式: NGUI生成的图集的图片格式是PNG,但是无论是什么格式的图片,Unity都会自己搞一套格式,并且打包的时候也不会用你文件夹下图片的格式,而是Unity自己的格式。如果你用UITexture你可以真对每一张图来修改它的格式,比如一些颜色数比较少的图片,你可以直接用16bit,如果你的图片没有用到透明,你可以用pvr或者etc,这样你的图片会更小。可是UISprite就不行,只要其中有一张小图用了透明,你就得用RGBA32,不然UI就会很难看,你可以自己试试。

除了UITexture 和 Atlas的图片没办法以外(因为必须有透明),不是建议是必须,你的贴图无论如何都必须是2的幂次方。因为只有2的幂次方图片 并且没有透明通道才会被压缩,IOS会压缩成pvr格式,Android会压缩成ETC格式,压缩以后图片会小很多的,好几倍的小。

人物贴图、场景贴图、特效贴图、一定要2的幂次方!切记!!如下图所示,同样的贴图大小。

 RGBA 32 大小 1M

NGUI研究院之UISprite和UITexture浅谈(十二) - 雨松MOMO程序研究院 - 3

Android ETC 大小170.7KB

NGUI研究院之UISprite和UITexture浅谈(十二) - 雨松MOMO程序研究院 - 4

IOS PVR 大小 170.8 KB
NGUI研究院之UISprite和UITexture浅谈(十二) - 雨松MOMO程序研究院 - 5

我觉得界面中那些重复性比较高的图片最好打成图集,而一些原画,或者背景图建议直接使用UITexture。还有NGUI的图集其实很占用内存,也很占用空间,为了优化效率尽量让策划拖妥协让UI尽可能的复用。

所以做项目初期就要好好的管理自己的图集,这也是个很郁闷的话题,因为需求一直都在变所以你很难规划你的图集,你不知道美术会设计出来什么样的图,你也不知道策划会设计出来什么样的界面,所以你很难去确定你的公共图集 还有 界面特有图集该如何来规划。因为一不小心你的图集就会超过1024,你也不知道那些资源复用性最高。。这也是我觉得NGUI最郁闷的一点。。如果那一天做UI不用自己去规划图集而是运行时系统最优选择,那该多好呀!!!

雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!

--

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。

  1. 一个窗口是个比较复杂的prefab ,里面用到了几个atlas ,我想预加载这几个atlas 。发现预加载后,窗口的实例化时间并没有减少?有什么办法吗?雨松遇到过这个问题吗?
    还有个奇怪的 prefab 从resource.load以后,实例化以前,uitextre已经在内存了 ,uiatlas没有在,所以想把uiatlas预加载 减少实例化时间 ,发现然并卵

    • 创建NGUI界面,最主要的耗时并不是加载,而是重绘。界面出现在场景中的第一次Update(Disable后的第一次Update也是),它会遍历所有新的Panel里的所有Widget,计算位置,判断是否改被渲染,然后在DrawCall池中取出DrawCall,加入顶点数据让Unity渲染。这也是NGUI的ScrollView效率如此低下的原因,因为ScrollView在滚动的过程中UIPanel会不断重绘。(尽量减少ScrollView内的Widget数量貌似可以提高一些ScrollView效率)

    • 不知道新版的NGUI有没有增加针对Widget的ScrollView,一些不需要裁剪的ScrollView,显然不需要Panel,这样能明显减少DrallCall,至于能不能降低重绘次数,我最近打算自己加一个针对Widget的ScrollView,试过才知道能不能。

    • 应该是我记错了,刚才试了下:因为UIDrawCall是跟着UIPanel一起移动的,所以移动Panel不会进行重绘;而移动Panel里的带顶点数据的Widget会改变UIDrawCall的顶点,所以一旦发生移动则会重绘。

      • 貌似每次改变运动方向时(静止、向左或向下、向右或向上这三个方向),如果有带顶点数据的widget在裁剪框之外(裁剪模式下),就会产生重绘……

  2. 请问在U3D NGUI的界面下做动画或是粒子特效,需要注意点什么?有时候动画好像播不了,第一次接触此插件,有点难懂,有劳答疑!

  3. MONO你觉得Draw call在什么范围内可以接受,比如就内存而言,大概是个什么概念范围内的内存可以容纳几个Draw call,比如说1M的内存,宁愿用几个Draw call来替代。以前我们游戏一直是Draw call尽量少为上,后来接触了一个项目,Draw call一般都是五六十,表示不算淡定了,主要是用了不少uitexture。

    • 没有反应,应该是shader有问题吧,我也是做了这样的效果,正常实现了,想问一下是不是用了ngui的Atlas之后就不能再在Atlas里的单张图片上使用shader了?

      • 你是怎么做到的,能留个QQ么,我加入的shader流光,但是游戏运行后,流光是不移动的,在编辑器里也不移动,只有在编辑器中修改参数后流光的位置才会改变一下,不是实时的改变

  4. 你好,MOMO老师!为什么NGUI – UIPanel的Clipping功能无法裁剪子UITexture,我在网上查有网友说把uitexture的shader换成NGUI裁剪自带的shader(Unilt-Transparent Colored(Packed)(SoftClip))我换了之后果然可以裁剪了,但是图片却变白了,什么都没有了,这是为什么呢?是texture不兼容这个shader吗?

  5. 目前看,DrawCall弄到个五六十也没什么问题,倒是内存一直很珍贵,所以宁愿多拆分几个图集。另外想问一下,PVR、ETC等压缩是无损的吗,做手机游戏时应该如何选择图片的压缩方式,还有TextureType、FilterMode等怎么设置才是最佳,怎么解决一些GUI放大后模糊的问题?谢谢了

  6. 你好,Atlas的图片不能选GUI-Compressd吗 这样也可以压缩成DXT5 为什么说一定要选RGB32(TrueColor)呢

  7. 我竟然把你的UNITY文章从头到底全读了一遍。。最后提个小问题吧。我看你写的说最好不用UNITY自带的物理引擎,我表示赞同。不用的话能否在UNITY打包时去掉物理引擎呢?我听人说不用的话打包时UNITY自动会去掉物理引擎,可是我实际尝试了下。发现没有这么回事。希望MOMO有办法解答我的疑问。

    • 你可以不用,但是你取不掉。。。 unity 没提供关闭 物理引擎的方法。 不过你可以 把 碰撞器 mesh碰撞器 刚体 啊什么的 都删除了 在打包。。。