-
图片格式
---------------
--------------------------------------------------
-------1
DrawCall
---------------
--------------------------------------------------
--------2
?
图片格式:
NGUI
生成的图集的图片格式是
PNG
格式,但是无论是什么
格式的图片
Unity
都会自己生成
一套格式,并
且打包的时候不会用文件夹下面的格式,而是
Un
ity
自己格式。
如果你用的
UITexture
你可
以对每一张图来修改格式,比如颜色数比较少的图片可以使用
16bit
,如果没有
透明,可以使用
pvr
或者
etc
这样图片会小很多。
如果是
UISprite
只要有透明的
就必须使用
RGBA32
要不然
p>
UI
会很难看。
除去
UITextuer
和
Atlas
的图片之外(因为有透明),其余的
贴图必须是
2
的幂次方。因为只有
2<
/p>
的幂次方
图片,并且没有透明通道的才会被压缩。
Ios
会被压缩成
pvr
格式
,
Andriod
会压缩成
etc
p>
格式。压缩之后会
小很多。
人物贴图
场景题图
特效贴图
一定要是
< br>2
的幂次方。
贴图透明通道分离,压缩格式设为
ETC/PVRTC
p>
最初我们使用了
DXT5
作为贴图压缩格式
,希望能减小贴图的内存占用,但很快发现移动平台的显卡是不
支持硬件解压
DXT5
的。因此对于一张
1024x1024<
/p>
大小的
RGBA32
贴图,虽然
DXT5
可将它从
4MB
压缩
到
1MB
,
但系统将它送进显卡之前,
会先用
CPU
< br>在内存里将它解压成
4MB
的
R
GBA32
格式
(软件解压)
,
然后再将这
4MB
送进显存。于是在这段时间
里,这张贴图就占用了
5MB
内存和
4
MB
显存;而移动平台
往往没有独立显存,需要从内存里抠一块
作为显存,于是原以为只占
1MB
内存的贴图实际却占了
9MB
!
所有不支持硬件压缩格式都有相同的问题。
解决方案:
现在
Andriod
硬件最广泛支持的时
Etc
,IOS
上支持的时
PVRTC
。但
这两种格式都是不带透明(
Alpha
)
通道的,因此我们需要将每张原始贴图的透明通道分离出来,写进另一张贴图的红色通道里,这两张特图
都采用
Etc/Pvrtc
压缩。
渲染的时候
将两张贴图都送进显存。
同时
我们修改了
NGUI
的
shader
在渲染时第
二张贴图的红色通道写入到第一张
贴图的透明通道里恢复原来的颜色:
1.
2.
3.
4.
5.
6.
}
fixed4 frag
(v2f i) : COLOR
{
fixed4 col;
= tex2D(_MainTex,
rd).rgb;
col.a =
tex2D(_AlphaTex, rd).r;
return col *
这样,
一张
4MB
的
1024x1024
大小的
RGBA32
原始贴图,
会被分离并压缩成两张
0.5MB
的
ETC/PVRTC
贴图(我们用的是
p>
ETC/PVRTC 4 bits
)。它们渲染时的内存占用则是
2x0.5+2x0.5=2MB
。
?
DrawCall
当两个
renderQueue
相邻的
DrawCal
l
使用了相同的贴图、材质和
shader
实例时,这两个
DrawCall
就可以
< br>合并。但需要注意的是
DrawCall
合并不见得会提
高性能,有时反而会降低性能
<
/p>
如果是
UIGeometry
为了渲染绘
制准备数据,那么
UIDrawCall
其实是定义了渲染绘制
需要的基本组件。这
里拿煮菜做个比喻帮助理
解:
UIGeometry
好比为煮菜准备食材,
p>
UIDrawCall
好比是煮菜的工具(锅,炉
< br>子等),
UIPanel
就是大厨了决定着什么时候该煮
菜,
UIWidget
(
UILabel
,
UIS
prite
和
UITexture
)是
这道
菜怎么样的最终呈现。
UIWi
dget
分别用
UpdateGeometry
和
WriteToBuffers
对
< br>UIGeometry
的
ApplyTransform
和
WriteToBuffers<
/p>
进
行封装调用,
ApplyTransf
orm
是根据
UIPanel
的坐标调
整
Vertices
的坐
标,
WriteToBuffers
将
UIGeometry
的
Vertices
,
UVs
和
Colo
rs
添加进
UIPanel
的
Vertices
,
UVs
和
Colors
的
BetterList
中。
这里还有一个细节就是:
UIGeometry
中的
Vertices<
/p>
,
UVs
和
Co
lors
的
BetterList
的<
/p>
buffer
什么时候得到,
因为这些都
是
UIWidget
或其子类的信息,
所以在
UIWidget
的子类
UILabel
,
UISprite
和
UITexture
中
OnFill
函数生成
UIGeometry
的
BetterList
的
buffer
。
UIWidget
这个脚本中的两个函数:
WriteToBuffers
,
OnFill
p>
,
UpdateGeometry
。
WriteToBuffers
和
OnFill
这两个函数都是将
Vertice
s
,
UVs
和
Colors
等
add
进参数的
List
中去,查看
WriteToBuffers
的调用出发现其参数是
UIP
anel
的
Vertices
,
UVs
和
Colors
,
而
OnFill
的参数是
UIGeometry
的
Vertices
,
UVs
和
p>
Colors
。
WriteToBuffers<
/p>
只是对
UIGeometry
的封装调用
,也就是说将
UIGeometry
的
Vertices
,
UVs
和
Colors
等
信息
a
dd
进
UIPanel
的对应
List
中。
UIG
eometry
的脚本,一直有一个疑问:
UIGeometr
y
的
Vertices
,
UVs
和
Colors
的<
/p>
List
没有看到
add
方法的
执行,
只有在
WriteToBuffers
被
add
p>
。直到看到了
OnFill
才恍然大悟,虽
然
UIWidget
的
OnFill<
/p>
是虚函数,
没有具体实现,看了下
p>
UISprite
重写的
OnFill
p>
函数,就是把
Vertices
,
UVs
和
Colors
添加到
UIGeometry
的
Ve
rtices
,
UVs
和
Colors
中。所有
UI
组件的
Vertices
,
UVs
p>
和
Colors
都汇集到
< br>UIPanel
的
Vertices
,
UVs
和
Colors
去了,然后
UIPanel
< br>指定给
UIDrawCall
渲染就行了
UIWidget
的一些实现细节,
MakePixelPerfect():
对
game
Object
的
localPosition
< br>和
locaScale
进行微调和纠正。
SetDirty():
调用
UIPanel
的
SetDirty()
对组件的变更进行重建
(
rebuilt)
。
Uiwidge UIGeometry& UIDrawCall
的关系:
UIWidget
中有两个变量
UiDrawCall mDrawcall
和
UIGeometry mGeo
的
verts uvs cols
的
BetterList,
然后
UiWi
dget
的
UpdateGeometry
< br>函数对
UIGeometry
的
ApplyTransform()
和
WriteToBuf
fer()
调用进行更新
.
每
一个
UIwidget
都有一个
UIGeometry
但是不都有一个
UIDra
wCall,
而是通过
Batch
合并
达到减少
DrawCall
的数量,
U
iDrawCall
是有
UiPanel
生成的。
DrawCall
的数量优化
根据上述描述可以得出一个结论:
使用相同
material
的连续的
U
iwidget(UILable UiSprite)
公用一个
UIDrawcall
。通过这个结论我们可以得到一个解决
DrawCall
过多的问题,
UIPanel
生成
DrawCall
时是
F
ill()
方法。
Fill
方法对<
/p>
进行检测把使用相同
Material<
/p>
的连续的
Uiwidget
合并生成一个
DrawCall ,
的排序是根据
UiWidget
的
Depth
进行的
。所以解决方案有两种:
1.
修改<
/p>
UiWidget(UiLable UIwidget )
的<
/p>
Depth,
限定
的排序
2.
重写
< br>Uiwidget
的
CompareFunc()
p>
方法。
(重写
UIWidget
的
CompareFunc
也是可以的,
按照
Material
的
name
优先排序,只有当
material
一样是才考虑
depth
进行排序:)
3.
无重叠时自动重排。
绘制顺序按照
Hierarchy
采用第二种方式减少
DrawCall:
Material leftMat = al;
Material rightMat = al;
if (leftMat == rightMat)
{
if ( < ) return -1;
else if ( > ) return 1;
else return 0;
}
if(leftMat !=null &
rightMat != null)
return e(,);
if
(leftMat != null) return -1;
if (rightMat != null) return 1;
return (tanceID() <
tanceID()) ? -1 : 1;
夹层问题:
因为
Material
使用的
Shader
使用了透明,这样就不能做深度测试,也就是
Mesh
的“
深度”是不影响的,
这样最终的显示就跟
Shader
的
renderQueue
< br>有关了,即
renderQueue
越大,显示的越靠前
面(重叠的图层,
renderQueue
越大,
越靠前)
。
当然现在只有增加一
个
DrawCall
(如多使用
一个
UIPanel
或用另外一个
Ma
terial)
来做到
Material
的夹层效果。
特效层级:
粒子系统的渲染顺序列默认为
3000
而
NGUI
的渲染顺序默认是从
30
00
开始,当有嵌套的
Panel
或者
Deoth
更高的
panel
时,
NGUI
的渲染顺序会高于
3000
解决方案:
1.
修改
Ngui
中的
panel
脚本中的默认
RenderQueue
调整到
3000
以下,这样就不会挡住
粒子特效。当
窗口显示在特效上面时把窗口的
RenderQu
eue
调整到
3000
以上,就解决了
。
2.
使用另外一个摄像机显示特效,
但是
Ui
窗口切换时不太好控制
p>
3.
修改例子特效的
shader
中的
RenderQueue
的值(需要考虑特
效中的层级关系)
一级界面
二级界面
..
浮动窗口
1.
不同图集
p>
项目中做到复杂一些的界面,经常会用到多个图集,以技能界面为例,项目中常用的图片放到
共用图
集中,
这是一个图集,技能界
面本身独有的元素,比如跟技能职业相关的背景,算作第二个图集,还有一
些技能图标,
图标单独归类到一个图集中,再一个就是字体的图集。基本一
个界面如此分法,最多需要
4
个图集。
NGUI
的图集之间的
处理,默认是
靠调整控件的
Z
值来区分的,但是这里他可以调整同一个图集<
/p>
每个一个控件的
Z
值,其实不是很好。经
常会出现图层相互遮挡的情况,尤其对于控件比较多的界面,一
段时间回过来再修改界面
的时候,整个要崩溃。
解决方案:
在
UIPanel
中,
为每一个
Material
添加一个
layer
的变量,
当同一图层靠
depth
来决定前后关
系,不同图层靠
layer
来决定前后关系,在绘制
UIDrawCall
的时候,根据
layer
对跟节点做一定偏移。
这样就能从
Z
值中解放出来。
如果大家也有碰到图层的问题,
可以参考这样的做法,以此种方
法来处理图
层关系,简单,做过项目的圈套
UI
,还未有不能解决的情况。
?
UI
自适应
Scaling Style
的作用是制定
< br>UiRoot
的缩放类型,如果是
PixelPerfe
ct ,Minimum Height
和
Maximum
Height
才起作用,
scaling style
选择的是
Pixelperfect
要对
Minimum
Height
和
Maximum Height
进行设置。
(
如果是
Pixe
lPerfect
缩放类型,当屏
幕的分辨率大于
Maximum
Height
,
则以
Maximum
Height
为基础缩放,
反之,
如
果屏幕分辨率小于
Minimum
Height
则以
Minimum Height
为
基础进行缩放。例如,如果屏幕高度为
1000
,而设置的
p>
Maximum Height
值为
800
,则
UI
界面整体放大为原来的
1000/800=1.25
倍。
)
FixedSize :
跟
Manual
Height
有关
FixedSizeOnMobiles
:
跟
Manual
Height
有关
只是针对
IOS
和
Andro
id
上的判断,也就是说只有
IOS
和
Android
平台下
FixedSi
zeOnMobiles
才起作用
.
FixedSize
或
FixedSizeOnMobiles
,
则缩放只以
Manual Heig
ht
为参考,
屏幕分辨率的高度值不同于此设
< br>置值时,则根据其比例(即
Screen Height / Manual H
eight
)对整棵
UI
树的进行“等
比”缩放(宽度的缩放
比也是此比例值)。
< br>注释:如果设置
FixedSize,
(以
UiRoot
默认值进行高度缩放)是不会改变的,不管实际屏
幕分辨率的像素是多少,
Anchor Stretch
的背景图片高度始终是
下的
UIW
idget
的
height
参数一直都
是实际的值
UIRoot
是基于高度进行缩放的如何做以宽度适配。
< br>UIRoot
是基于高度放缩的,即放缩的比例是以高度为参考的,所以
UIRoot
有一个
manualHeight
的参
数。那么对于横版游戏显然不行,要是
能实现基于宽度放缩。所以可以通过设置一个“
manu
alWidth
”的
参数来做。比如我们项目中使用的是
1024
作为
U
I
的宽屏尺寸,通过换算设置
manualHeight
的值:
int height = (2,
);
manualHeight = * 1024 /
//
基于宽度的屏幕分辨率自适应
注释:
UIRoot
其实就做了一件事情:根据
和
Height
的比例来调整
UIRoot
的
loaclScal
,从而保证
UIWidget
(
UISprite
,
UILabel
)可以按照其本身的
大小进行设置,而不用经过复杂
的换算过程。
?
资源分离打包与加载
资源分离打包与
加载是最有效的减小安装包体积与运行时内存占用的手段。一般打包粒度越细,这两个指
标就越小。但打包粒度也并不是越细就越好。如果运行时要同时加载大量小
bundle
,那么加载速度将会非
常慢——时间都浪费在协程之间的调度和
多批次的小
I/O
上了。此需要有策略地控制打包粒度。一般只
分
离字体和贴图这种体积较大的公用资源。
?
关闭贴图的读写选项
Unity
中导入的每张贴图都有一个启用可读可写(
Read/Write Enable
)的开关,对应的参数是
able
。
选中贴图后可在
Impo
rt Setting
选项卡中看到这个开关。
只有打开这个开
关才可
以对贴图使用
el
,读取或改写
贴图资源的像素,但这就需要系统在内存中保留一份贴图的
拷贝,
以供
Cpu
访问,
但是一般游戏运行
过程中不会有这样的需求,
因此我们对所有贴图都关闭这个开关,
只在中做贴图导入后处理(比如对原始提贴图分离透明通道)时需要打开这个选项。这样,上文提到的
1024x1024
大小的贴图,其运行时的
2
MB
内存占用又可以少一半,减小到
1MB
。
Texture
图片空间和内
存占用分析
纹理大小影响:
可以将其他(非二的幂
-
“
NPOT
”)纹理大小用于
Unity
非二的幂纹理大小通常占用的内存稍多一点,
由
GPU
进行读取的速度可能较慢
,
因此考虑到性能,
最好尽可能使用二的幂大小。
如果平台或
GPU
不支持
NPOT
纹理大小,
则
Unity
会缩放纹理并将其填补为下一个二的幂大小,
p>
这甚至会使用更多内存并使加载
更慢
Iphone
:
空项目
空间占用量
42.3M
ipa
包
10M
10
张
1200*520
无压缩
Texture
单张图占用量
2.8M
空间占用两
70.2M
ipa
包
22.9M
10
张
< br>1200*520
压缩成
1024*1024
PVRTC4
单图占用量
0.5M
空间占用量
47.3M
ipa
包
13.2M
10
张
1024*1024
无压缩
Texture
单图占用量
4M
空间占用量
82.M
ipa
包
14.6M
10
张
1024*1024
压
缩为
PVRTVC4
格式
单张图占用量
0.5M
空间占用量
47.3M
ipa
包
11.6M
综上所述:
1.2
的
N
次方大小的图片会得到引擎更大的
支持,包括压缩比率,内存消耗
打包压缩大小,而且支持
p>
的力度非常大。
2.
减小
图片的占用大小和内存方式有:图片大小变化(
Maxsize
)
,
色彩位数变化(
16
位色
32
位色),
压缩
PVRC
格式
p>
3.U3D
对于图片的格式是自己生成的,而并不是你给它什么它用
什么格式。一张
1024*1024
图在无压
< br>缩的格式下,
他会被
U3D
无压
缩文件像是存放,
也就是说
U3D
里的
Texture Perview
里显示的占用大小
**M
不只是内存占用的大小,还是空间占用大小。
Unity
图片压缩格式介绍:
U3D
的内部机制为自动生成图片类型来替代我们的图片在图片的压缩方式需要进行谨慎的选择。
几种
比较主要的压缩格式:
RGBA32 BIT/AutomaticTurecolor
(256*256 256k)
格式为无压缩最保真格式,最消耗内存和空间的格式。
RGBA16 BIT/
格式为无压缩
16
位格式,比
32
位节省一半的
空间和内存,与
Automatic16
相同。
RGBA
Compressed PVRTC
4bits
格式为
PVRTC
图片格式,
它相当
于把图片更改了压缩方式新生成了一个图片来替换原来的图片格式
贴图格式:
3D
游戏中贴图的的分类:
UI
贴图
ui
是按照
1280*853
比例出的图
3D
场景贴图
主要是因为多重采样的缘故。
3D
游戏一般来说都是受摄像机
远近大小改变而采取不同的采
样大小,如果不设置多重采样的话,在远处有非常多的白色
噪点。
2D
游戏
所有都不需要勾选多重采样,具有
3D
性质的贴图,我们都需要勾选上
G
ENERATE MIP MAPS
,这样会
使贴图大小增加<
/p>
25%
这样。
正方贴图与非正方贴图也要区分
:
非正方贴图只有
16
位的压缩(相当于
真彩色减半),所以最好游戏中都是正方的贴图。
正方贴图:
IOS
:
普通不透明:
RGB PVRTC 4 BITS
普通透明:
RGBA PVRTC 4 BITS
(256*256 32kb)
Androis:
普通不透明:
RGB ETC 4
BITS
(256*256 32kb)
普通透明:因为没有通用的兼容模
式,所以一般情况是用
RGBA 16 BITS
或是针对不
同的
GPU
选择
DXT5/ATC8 BITS/ETC2 8BITS
。
p>
如果技术支持,
可以采用
RGB ETC 4 BITS
加一张
Alpha
8
的贴图来实现
透明效果。
非正方形:
一般采用
16
位压缩,
16
位色会带来颜色损失,如果本来美术就按
16
位色画的话,就不会带来损失。日
本的很
多
2D
游戏都是采用那个
16
位来画的。少渐变
和艳色。
不透明贴图:
RGB 16
BIT
(
256*256
128KB
)
透明贴图:
RGBA 16 BIT
(
256*256
128KB
)
高清不压缩贴图:
RGBA 32 BIT
(256*256 256kb)
对于不重要的贴图,模糊度低的贴图,建议不仅要采取像素压缩,还要直接压缩其大小。如光照贴图压到
512
或
256
。如背
景原本
1024
的图直接压到
256<
/p>
。玩家不注意到就可以了。
注意:
U3D
所有图片的压缩格式都会以另
一种方式存储,不会以你给的方式存储,只有你指定了某种格式,他才会转换成
你要的格
式。而且在
Andriod
里的并不一定有效,因为
Andriod
的机型多,
GPU
的渲染方式也不一样,
RGBA16
适应
于所有机型
?
GameObject
数量
场景中
GameObject
的数量也是衡量性能的重要指标,频繁的创建
和销毁
GameObjec
是非常耗
时,场景
中存在的
GameObject
会占用内存,如果
GameObject
上挂有物体的话,每
个
GameOject
的脚本都需要实力
化。
?
整理图集
整理图集的主要目的是节省运行时内存(虽然有时也能起到合
并
DrawCall
的作用)。从这个角度讲,显
示一个界面时送进显存的图集尺寸之和是越小越好。一般有如下方法可以帮助我们做到这点:
1)
在界面设计上,尽量让美术控件设计成九宫格拉伸,即
UiSprite<
/p>
的类型是
Sliced.
这样美术素材可
以
切出一张很小的图片在
unity
中
做拉伸。
当然一个九宫格也就意味着其定点数量会从
4
个增加到
16
个
(如果
九宫格的中心格子采用
Tiled
做平铺类型的话,
定点数会更多)
,
构建
D
rawCall
的开销会更大。
但一般只要
DrawCall
安排合理就不会出问题
2)
同样在界面设计上
尽量设计成对称的
形式,这样在切图的时候美术切图的时候就可以只切一部分,
我们在
Untiy
中将完整的图案拼出来,比如一个圆形图案我们可以只切四分之一,不过
与上述第一点
类似这样会增加定点个数,
同时也会增加场景中<
/p>
GameObject
的个数,
因为
p>
GameObject
的数量增多时
会占用
跟多的内存,所以只对尺寸较大的图案采用这种方法。
-
-
-
-
-
-
-
-
-
上一篇:layout _igraph
下一篇:父母永远不要在孩子面前做的八件事