Unity3D性能优化

发表于2018-06-14
评论0 2.8k浏览
一个项目从制作中到完成,肯定会遇到各种各样的问题,而其中最能决定项目是否可以上线,就需看在性能上是否得到了足够的优化,而决定性能优化也就这三个:CPU方面 、GPU方面和内存方面。

一、CPU方面的优化

对DrawCalls的优化

1.DrawCalls : 每个物体尽量减少渲染次数,多个物体最好一起渲染。
(1).使用Draw Calls Batahing,也就是描绘调用批处理。Unity3D在运行时可以将一些物体进行合并,从而用一个描绘调用来渲染他们。

(2).通过把纹理打包成图集尽量减少材质的使用。

(3).尽量少的使用反光、阴影之类的效果,因为那会使物体多次渲染。

2.Static Batching静态批处理
(1).静态批处理操作允许引擎对任意大小的几何物体进行批处理操作来降低绘制调用(只要这些物体不移动,并且拥有相同的材质)。因此,静态批处理比动态批处理更加有效,你应该尽量低使用它,因为它需要更少的CPU开销。

(2). 明确指出哪些物体是静止的,并且在游戏中永远不会移动、旋转和缩放,在检测器(Inspector)中勾选“Static”,Unity在运行时会对static物体进行自动优化处理,所以应该尽可能将非运行实体勾上static标签。

3.动态批处理
(1). 批处理动态物体需要在每个顶点上进行一定的开销,所以动态批处理仅支持小于900顶点的网格物体。

(2). 如果你的着色器使用顶点位置,法线和UV值三种属性,那么你只能批处理300顶点以下的物体;
如果你的着色器需要使用顶点位置,法线,UV0,UV1和切向量,那你只能批处理180顶点以下的物体。
请注意:属性数量的限制可能会在将来进行改变。

(3).不要使用缩放尺度(scale)。分别拥有缩放尺度(1,1,1)和(2,2,2)的两个物体将不会进行批处理。

(4).统一缩放尺度的物体不会与非统一缩放尺度的物体进行批处理。

使用缩放尺度(1,1,1)和 (1,2,1)的两个物体将不会进行批处理,但是使用缩放尺度(1,2,1)和(1,3,1)的两个物体将可以进行批处理。

(5).使用不同材质的实例化物体(instance)将会导致批处理失败。

(6). 拥有lightmap的物体含有额外(隐藏)的材质属性,比如:lightmap的偏移和缩放系数等。所以,拥有lightmap的物体将不会进行批处理(除非他们指向lightmap的同一部分)

(7).预设体的实例会自动地使用相同的网格模型和材质。

对物理组件的优化

1.减少FPS
在ProjectSetting-> Quality中的VSync Count 参数会影响你的FPS,EveryVBlank相当于FPS=60,EverySecondVBlank = 30;

这两种情况都不符合游戏的FPS的话,我们需要手动调整FPS,首先关闭垂直同步这个功能,然后在代码的Awake方法里手动设置FPS(Application.targetFrameRate = 45;)

降低FPS的好处:
(1)省电,减少手机发热的情况;
(2)能都稳定游戏FPS,减少出现卡顿的情况。

2.设置一个合适的FixedTimestep
这个参数在ProjectSetting->Time中,目的是减少物理计算的次数,来提高游戏性能

3.尽量不用MeshCollider
如果可以的话,尽量不用MeshCollider,以节省不必要的开销。如果不能避免的话,尽量用减少Mesh的面片数,或用较少面片的代理体来代替

处理内存,尽量少的触发GC

GC处理的是托管堆,引用类型(类实例、字符串、数组)会被分配到托管堆上,需要注意的是:
  • 字符串的链接处理。旧得字符串空间会被GC当做垃圾回收。
  • 尽量不要使用foreach语句,使用for语句。foreach会带来大量垃圾。
  • 不要直接访问gameobject的tag属性。最好用if(goCompareTag(“human”))来代替if(go.tag==”human”)等。
  • 使用池,以实现空间的重复利用。
  • 最好不要用LINQ的命令,他们会分配临时空间,同样也是GC收集的目标。

对代码质量的优化
  • 最好不要频繁的使用GetComponent,尤其在循环中
  • 善于使用OnBecameVisible()和OnBecameVisible()来控制物体的Update()函数的执行以减小开销
  • 使用内建数组,比如Vector3.zero而不是new Vector(0,0,0);
  • 对于方法参数的优化,善于使用ref关键字

二、GPU的优化

GPU与CPU不同,所以侧重点也不一样。GPU的瓶颈主要有以下4个方面:
  • 填充率,可以简单地理解为图形处理单元每秒渲染的像素数量
  • 像素的复杂度,比如动态的阴影、光照、复杂的shader等
  • 几何体的复杂度(顶点数量)
  • GPU的显存宽带

可以从以下两个方面优化:
(1)减少顶点的数量,简化计算复杂度
        保持材质的数目尽可能少
        使用纹理图集来代替一系列单独的小贴图
        如果使用了纹理图集和共享材质,使用Renderer.shaderMaterial来代替renderer.material
        使用光照纹理而非实时灯光
        使用LOD,好处就是对那些离得远,看不清的物体的细节可以忽略
        使用遮挡剔除(Occlusion Culling)
        使用mobile版的shader,因为简单

(2)优化显存宽带
        OpenGL ES2.0使用ETC1格式压缩等,在打包设置那里都有
        使用MipMap

三、内存的优化

角色Material数量: 2-3个
骨骼数量: 小于30个
面片数量: 300-1500

一般角色应该没有IK结点: 这是因为角色的动作大多数都是事先设定好的,并不需要经过IK操作来进行实时计算(Rogdoll除外),所以在模型导入时,不要将IK结点一起导入

静态实体: 不要附加Animation Component,在静态实体上附加Animation部件虽然对结果没有影响,但却会增加一定的CPU开销来调用这一组件,所以尽量去掉该组件

网格顶点数: 小于500
角色Material数量: 2-3个
UV值范围尽量不要超过(0, 1)区间: 尽量保证UV值不越界,这对于将来的纹理拼合优化很有帮助

地形

1.地形的分辨率大小,长宽均尽量小于257。这是因为地形太大,会造成大量顶点数据,给你的内存带宽造成一定的影响,在目前的ios设备中,内存带宽是非常有限的,需要尽量节省。同时,如果用Unity自带的地形,一定也要使用Occlusion Culling,因为Unity的刷地形工具虽然方便,但却是framekiller,刷过之后,你会发现drawcall增加的非常多

2.混合纹理数量不要超过4。地形的混合操作是很耗时的,应该尽量避免。能合并的纹理尽量合并

纹理

1.纹理格式建议png或tga。不用转成ios硬件支持的PVRTC格式,因为Unity在发布时会帮你自动转的。

2.纹理尺寸长宽小于1024。同时应该尽可能地小,够用就好,以保证纹理对内存带宽的影响达到最小。

3.支持Mipmap建议生成Mipmap。虽然这种做法会增加一些应用程序的大小,但在游戏运行时,系统会根据需求应用Mipmap来渲染,从而减少内存带宽

4.检查Alpha值,如果纹理的alpha通道均为1,则用RGB的24位纹理来代替RGBA的32位纹理。(据说Unity内部会进行自动检测)

光源

1.光源“Important”个数建议1个,一般为方向光。“Important”个数应该越小越少。个数越多,drawcall越多。

2.Pixel Light数目1-2个。

音频

1.游戏中播放时间较长的音乐(如背景音乐),使用。ogg或。mp3的压缩格式。

2.较短音乐(如枪声),使用。wav和。aif的未压缩音频格式。

相机

1.裁剪平面,将远平面设置成合适的距离。远平面过大会将一些不必要的物体加入渲染,降低效率。

2.根据不同的物体设置不同的远裁剪平面

Unity提供了可以根据不同的layer来设置不同的view distance,所以我们可以实现将物体进行分层,大物体层设置的可视距离大些,而小物体层可以设置地小些,另外,一些开销比较大的实体(如粒子系统)可以设置得更小些等等。

粒子特效

1.屏幕上的最大粒子数,建议小于200个粒子。

2.每个粒子发射器发射的最大粒子数,建议不超过50个。

3.粒子大小如果可以的话,粒子的size应该尽可能地小。因为Unity的粒子系统的shader无论是alpha test还是alpha blending都是一笔不小的开销。同时,对于非常小的粒子,建议粒子纹理去掉alpha通道。

4.尽量不要开启粒子的碰撞功能。非常耗时

来自:https://blog.csdn.net/edinburgh_yx/article/details/69569798

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引