NGUI图集与Drawcall

Unity中常用的界面是NGUI和UGUI,他们都用来创建界面,而NGUI学习成本更低。

在Unity渲染界面的时候,总体上会根据层级自下向上地渲染。其中,UIPanel的优先级最高,我们可以认为Unity首先会按照UIPanel的层级把prefab排序,而子物体们则会在UIPanel的层级上再根据层级排序。另外,即使一个UIPanel挂在另一个UIPanel的下面,也属于不同的层级。

然后由于有这样的渲染顺序,所以我们需要合理安排各个组件的层级,让使用相同美术素材的组件在接近的层级上,不同美术素材的组件尽量远一些。

举个栗子,假设我们有四个组件A、B、C、D层级分别是1、2、3、4,然后他们用的美术素材分别是E、F、E、F,那么在渲染的时候就会自底向上把A、B两个美术素材各渲染2遍,Drallcall也就是渲染次数等于4。为什么Unity这么蠢,不能自动地寻找相同美术素材的组件然后一起渲染呢?没办法,这只能靠我们自己来优化。所以我们应该把这四个组件的顺序调整成A、C、B、D,这样AC和BD就会分别一起渲染。

NGUI图集

在Unity中我们会经常用到很多美术元素,可能有几百上千个,而同一个元素会在不同地方被多次调用,这样的话Dracall会很容易变得很高,如果我们能够让同一个界面上的美术元素都合成一张图,总体只渲染一次,那不就很完美吗?所以NGUI和UGUI都使用图集来管理图片素材。他们的思路都是把经常复用的元素放到一张图集上面。

UISprite

NGUI引入图集的概念,不考虑ABA叠层的情况下,一个图集内的图片用UISprite,那么它就是一个DrawCall。但是如果你做了一个图集是1024X1024的。此时你的界面上只用了图集中的一张很小的图,那么很抱歉1024X1024这张大图都需要载入你的内存里面,1024就是4M的内存,如果你做了10个1024的图集,你的界面上刚好都只用了每个图集里面的一张小图,那么再次抱歉你的内存直接飙40M。

UITexture

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

图片格式

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

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