您的位置:首页 > 移动开发 > Unity3D

Unity3D 优化总结

2016-07-17 22:24 260 查看
资源守恒定律:为了完成一项功能,必须消耗一定资源。消耗的资源在CPU、GPU、Memory之间平衡。

CPU消耗比较高时:由于短时间内的计算量太大,导致画面流畅性降低,俗称跳帧,发热严重,耗电量高

1.将计算分到多个逻辑帧中进行计算,避免短时间内的性能超过负荷,俗称“分帧”(time-slice)。
2.将可以缓存的数据尽可能的缓存起来,避免重复计算和重复分配内存,常见的示例为“内存池”。
3.使用合理的算法和数据结构,比如:冒泡排序和直接插入排序在整体数组比较有序的情况下效率大大好于快速排序。把快排替换成是优化程序排序效率的一个常见的思路。

4.设置一个合适的Fixed Timestep,若计算的频率太高,自然会影响到CPU的开销。同时,若计算频率达不到游戏设计时的要求,有会影响到功能的实现,所以如何抉择需要各位具体分析,选择一个合适的值。

5.不要使用网格碰撞器(mesh
collider):为啥?因为实在是太复杂了。

6.以物体的Transform组件为例,我们应该只访问一次,之后就将它的引用保留,而非每次使用都去访问。

7.如上所述,最好不要频繁使用GetComponent,尤其是在循环中。

8.善于使用OnBecameVisible()和OnBecameVisible(),来控制物体的update()函数的执行以减少开销。

9.使用内建的数组,比如用Vector3.zero而不是new
Vector(0, 0, 0)。

10.降低DrawCall,

静态DrawCall:场景中的静态对象,使用同一材质,设置为static,可以通过批次降低DrawCall。

动态DrawCall:对材质相同的物体,Unity会自动批次渲染,降低DrawCall,但有以下限制:

批处理动态物体需要在每个顶点上进行一定的开销,所以动态批处理仅支持小于900顶点的网格物体。
如果你的着色器使用顶点位置,法线和UV值三种属性,那么你只能批处理300顶点以下的物体;如果你的着色器需要使用顶点位置,法线,UV0,UV1和切向量,那你只能批处理180顶点以下的物体。
不要使用缩放。分别拥有缩放大小(1,1,1) 和(2,2,2)的两个物体将不会进行批处理。
统一缩放的物体不会与非统一缩放的物体进行批处理。
使用缩放尺度(1,1,1) 和 (1,2,1)的两个物体将不会进行批处理,但是使用缩放尺度(1,2,1) 和(1,3,1)的两个物体将可以进行批处理。
使用不同材质的实例化物体(instance)将会导致批处理失败。
拥有lightmap的物体含有额外(隐藏)的材质属性,比如:lightmap的偏移和缩放系数等。所以,拥有lightmap的物体将不会进行批处理(除非他们指向lightmap的同一部分)。
多通道的shader会妨碍批处理操作。比如,几乎unity中所有的着色器在前向渲染中都支持多个光源,并为它们有效地开辟多个通道。
预设体的实例会自动地使用相同的网格模型和材质
保持材质的数目尽可能少。这使得Unity更容易进行批处理。
使用纹理图集(一张大贴图里包含了很多子贴图)来代替一系列单独的小贴图。它们可以更快地被加载,具有很少的状态转换,而且批处理更友好。
如果使用了纹理图集和共享材质,使用Renderer.sharedMaterial 来代替Renderer.material 。
GPU消耗比较高时:

使用光照纹理(lightmap)而非实时灯光。
使用LOD,好处就是对那些离得远,看不清的物体的细节可以忽略。
遮挡剔除(Occlusion culling)
使用mobile版的shader。因为简单。
避免使用alpha测试,而是选择alpha混合。

Per-Layer Cull Distances 每层消隐距离
  使用Camera.layerCullDistances函数,设置每一层消隐距离。这样可以把远距离的需需要渲染的物体隐掉,以减少渲染批次。

使用合并器或像素着色器,混合每帧的多个纹理,而不是用多通道方法
如果您使用的是内置的着色器,对于移动平台。记住,Mobile / VertexLit 是目前最快的着色器。
如果编写自定义的着色器,用尽可能小的浮点格式
  fixed / lowp -- perfect for color, lighting information and normals, 
  用于颜色,灯光信息和法线
  half / mediump -- for texture UV coordinates, 
  用于纹理UV坐标,
  float / highp -- avoid in pixel shaders, fine to use in vertex shader for vertex position calculations. 
  尽可能地使用最低的精度,这点对于iOS和Android平台特别重要。推荐的经验法则:对于颜色和单位长度的向量,使用fixed;对于其他的,如果范围和精度允许的话,使用half,否则使用float。
  在移动平台上,关键是在片段着色器中使用尽可能多低精度数据计算。在大多数移动设备的GPU中,在低精度 (fixed/lowp) 类型上应用swizzles是比较耗时的;同时,在fixed/lowp 和高精度类型之间进行转换也是需要付出很大代价的。
尽量减少在像素着色器使用复杂的数学运算,如pow, sin, cos 等。
通常地说,所需要渲染的像素(像素着色器执行)个数要比所需要渲染的顶点(顶点着色器执行)个数要多,同时,所需要渲染的顶点个数也要比模型的个数要多。所以,一般来说,尽可能地将计算量从像素着色器移到顶点着色器中,或者完全从着色器中移除并从脚本中来赋值。避免在像素着色器,而是使用顶点着色器,计算顶点的位置

减少FPS,在ProjectSetting->
Quality中的VSync Count 参数会影响你的FPS,EveryVBlank相当于FPS=60,EverySecondVBlank = 30;
  这两种情况都不符合游戏的FPS的话,我们需要手动调整FPS,首先关闭垂直同步这个功能,然后在代码的Awake方法里手动设置FPS(Application.targetFrameRate = 45;)降低FPS的好处: 1)省电,减少手机发热的情况;2)能都稳定游戏FPS,减少出现卡顿的情况。

待机时,调整游戏的FPS为1,节省电量。

Memory消耗比较高时:

1.Texture的Read/Write Enable选项:选择此项将允许从脚本(GetPixels,SetPixels和其他Texture2D函数)访问纹理数据。但是注意,一个纹理数据副本将产生,由此必将为纹理资源消耗双倍的内存量。只有在绝对必要时使用。默认情况下禁用。

2.每个“foreach”循环的每次迭代会生成24字节的垃圾内存。一个简单的循环迭代10次就可以留下240字节的垃圾内存。
  不使用LINQ命令,因为它们一般会分配中间缓器,而这很容易生成垃圾内存。

3.网格里面的Normal Color Tangent数据能不用就不用,在合批的时候,一个模型带有此类数据,会导致其他的模型也自动添加该数据。

4.Mipmap可以降低渲染带宽压力,但会导致内存变为1.33倍,3D场景和角色建议开启;UI渲染在屏幕最上层,开启了mipmap并不会提升渲染效率,不建议开启。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: