本文主要是介绍3D移动端游戏的优化方向-收集整理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
发现一篇给我写的几乎一样的,估计是听的同一个人的视频吧http://www.cnblogs.com/willbin/p/3389837.html
相关:http://blog.codeconch.com/archives/499
http://blog.sina.com.cn/s/blog_471132920101dqsl.html
http://blog.jobbole.com/84323/
http://blog.csdn.net/yesy10/article/details/7847926
http://blog.csdn.net/sgnyyy/article/details/41621039
http://www.cnblogs.com/hellohuan/p/3716357.html
http://gamerboom.com/archives/76214
一.资源相关优化。
二.引擎相关优化。
三.代码相关优化。
四.shader相关优化。
#############################################资源相关优化#############################################
一.可移动的物体
1.主角、NPC、怪物等
a.控制面片的数量:300-2000面片(三角面),如果只有两三个角色(例如,双人格斗游戏),可以适当提高面数。
b.控制Skinned Mesh Renderer数量:1个。
c.控制材质数量:1-3个,如果主角有换装要求另谈。
d.控制骨骼数量:小于30根,在pc端,可以到60根,甚至到100根。
2.其他动态物体(比如:飘的云彩什么的)
a.控制整体的的数据大小(比如雨滴,能用两个面片,就不要用多个)。
利用Dynamic Batching进行合并。
二.静态物体
1.一般静态物体(比如地表的一些装饰物体,像是箱子,铁桶等)
a.控制网格的顶点数:小于500个。
标记为“static”:Static Batching。
b.Animation组件:不要附加Animation组件,因为每次update或者fixedUpdate时都会有计算。
2.地形
a.控制地形的解析度:长宽均尽量小于257,当然你也可以很大,然后streaming,streaming之后,再动态加载。不建议一次性设置很大,因为性能损耗特别大。
b.混合纹理数量:不要超过4。当超过4 的时候,在pad这种真机上会出现一些混合错误,超过4之后计算量会非常大,mobile是扛不住的。如果已经这么做了,可以做纹理拼接,把小的纹理拼接成大的像是2048x2048这种,但是这样会吃掉内存,来换取帧频的提升。
三.纹理数据
1.纹理格式:
a.建议png或tga。IOS会在压包时自动转换为pvrtc格式,这样IOS设备可以硬件解,省时省电;而Android不会自动转换,因为Android的硬件众多,建议:手动改成ETC格式的,有90%的机器可以硬件解码这个格式。
2.纹理尺寸:
a.长宽小于1024,:同时应该尽可能的小,够用就好,2048的图片有些机器可能不能正确的读出来。
3.支持Mipmap:
a.建议生成Mipmap:虽然这种做法会增加包体的大小,但会提高一些渲染效率。2D游戏没有必要生成Mipmap了。
4.控制UV值的范围:
a.UV值的范围不要超过[0,1]。
四.音频数据
1.播放时间较长的音乐(如背景音乐)
a.建议使用.ogg或.mp3的压缩格式。
2.播放时间较短的音乐(如枪声)
a.使用.wav和.aif的未压缩音频格式。
###############################################################################################################
#############################################引擎相关优化#############################################
一.光源设置
1.控制“Important”光源个数
a.建议1个或者0个,一般为方向光。
b.个数越多,drawcall越多。
2.PixelLight数目
a.1-2个
二.相机设置
1.设置合理的远裁剪平面
a.默认为1000,建议根据各自不同的游戏场景进行修改。
2.设置分层的远裁剪平面
例如:
using UnityEngine;
using System.Collections;public class example : MonoBehaviour {void Start() {float[] distances = new float[32];distances[10] = 15;//设置层10的消隐为15米距离,其他所有层使用远剪裁屏幕距离camera.layerCullDistances = distances;}
}
function Start () {var distances = new float[32];// Set up layer 10 to cull at 15 meters distance.// All other layers use the far clip plane distance.//设置层10的消隐为15米距离,其他所有层使用远剪裁屏幕距离
a.根据物体的体积大小、渲染成本来进行分层。
三.粒子特效
1.荧屏上的最大粒子数目
a.建议小于200个粒子
2.每个粒子发射器的最大粒子数
a.建议不要超过50个。
3.粒子的大小
a.如果可以的话,粒子的size应该尽可能的小。
b.对于非常小的粒子,建议粒子的纹理去掉alpha通道。
4.尽量不要开启粒子的碰撞功能。
四.物理系统
1.碰撞体控制
a.如果可以的话,尽可能地使用SphereCollider、BoxCollider。
b.尽量避免使用MeshCollider等。
如果你想在Mobile上达到30fps的话,那么在每一帧上只有33ms的cpu时间。
五.动画系统
1.没有骨骼动画的模型要去除Animation组件
2.如果Animation不进行缩放,去除ScaleCurves(用脚本把它去掉,当然手动也可以,如果不嫌工作量的繁多)
a.减少33%的Blending时间
3.只有一个AnimationClip,使用老版本的Animation系统
4.如果使用Mecanim动画系统的话,要使用BodyMask来减少不必要的计算量
5.如果使用IK,建议使用GenericMode而不是HumanoidMode:不管角色有多少骨骼,在Mecanim系统里,HumanoidMode的Avatar系统会有一个特定数量的骨骼数目,假设有30根,而做的角色有60根的话,avatar就会自动缓存,计算IK的时候在30根中计算,然候在60根骨骼上自动映射,这样就多出一些计算,因为GenericMode是直接按照60根计算的。
6.主要Mecanim系统在Android上运行效率
a.数值运算非常高
b.在支持NEON的Android机上跑的才非常好
六.渲染设置
1.尽可能地避免AlphaTest和AlphaBlend
a.非常耗时,性价比很低
b.如果实在无法避免,请将进行Alpha Test或Alpha Blend的pixel数将至最低。
2.DrawCallBatching
a.Unity在进行时可以将一些物体进行合并,从而用一个DrawCall来渲染它们,我们将这一操作称之为“DrawCallBatching”
b.一般来说,Unity Batch的物体越多,你就会得到越好的渲染性能。
3.Static Batching
a.针对静态的物体进行Batch
b.对几何数据的大小没有限制
1).原理
a.静态VertexBuffer+动态IndexBuffer
b.在Build过程中,同种材质的物体被合并在一个大的VertexBuffer中
c.在Run-time时,通过视域体裁剪来动态改变IndexBuffer
2).注意
a.使用StaticBatching需要额外的内存来存储batch后的几何数据
4.DynamicBatching
a.相同材质的动态物体,Unity会自动对其进行batch
1).原理
a.动态VertexBuffer+动态IndexBuffer
2).注意
a.目前仅支持小于900顶点的网格物体
b.如果shader里使用Position,normal和UV三种属性的话,那么你只能batch 300顶点一下的物体,如果使用Position,normal,UV0,UV1和Tangent,那你 只能batch 180顶点一下的物体
c.进行缩放物体无法与非缩放的物体进行batch
5.纹理拼合(Texture Packing):程序进行开发拼合工具
a.通过检测材质,将材质按照shader的种类来分类
b.将同种shader的不同纹理进行拼合,拼成一张或若干张大的纹理,同时生成新的拼合材质
c.根据拼合结果,修改相关Object的UV值
d.更新相关Object的材质
6.遮挡剔除(Occlusion Culling)
a.区分Occluder(遮挡者)和Occludee(被遮挡者):半透明委托一般不设定额外Occluder
b.选择合适的遮挡技术
1).PVS Only:动态物体仅通过视域体进行裁剪,适合动态物体很少的情况
2).PVS and dynamic objects:动态物体通过portal culling进行裁剪
3).Automatic Portal Generation:动态物体通过portal culling进行裁剪,同时场景支持动态portal
###############################################################################################################
#############################################代码相关优化#############################################
一.使用静态类型(JS)
二.使用#pragma strict
1.禁用JavaScript的动态类型
未完。。。。。。。
转载一些:如下
Unity3D优化
⼀、渲染优化
设置所需的帧率
Unity iOS 允许您更改您的应用程序执行渲染循环的频率,而它的默认设置为每秒 30帧。
您可以降低此帧率来节省电池的电量,但当然这种节约在每帧中也会给您来⼀定的更新代
价。相反,您也可以增加渲染帧率,从而使画面渲染优先于触摸输入和加速度计处理等其
他活动。您需要对帧速率进行反复试验,从而确定它是如何来影响您的游戏体验。
如果您的应用程序涉及到大量计算和复杂的渲染,并且只能达到15帧/秒,那么即便您将
所需帧率设置为高于15帧,那也于事无补。您只有将应用程序进行足够的优化,才能允
许获得更高的帧率。
为了设置需要帧率,打开Unity生成的XCode工程,并打开AppController.mm文件。下面
⼀行
#define kFPS 30
决定了当前的帧率,所以你可以通过更改该值来得到所需的帧率。比如,如果你改变这个
#define为:
#define kFPS 60
那么应用程序将试图将渲染帧率变为60FPS,而不是30FPS。
渲染循环
在使用 iOS 3.1 或更高版本时, Unity将安排渲染循环使用 CADisplayLink类。版本 3.1之
前的版本需要使用几种fallback方法来处理循环。但是, 3.1及更高版本的 iOS可以通过
以下方法来激活fallback方法。
二、性能脚本优化
1. 减少固定增量时间
将固定增量时间值设定在0.04-0.067区间(即,每秒15-25帧)。您可以通过Edit-
>Project Settings->Time来改变这个值。这样做降低了FixedUpdate函数被调用的频率以
及物理引擎执行碰撞检测与刚体更新的频率。如果您使用了较低的固定增量时间,并且在
主角身上使用了刚体部件,那么您可以启用插值办法来平滑刚体组件。
2. 减少GetComponent的调用
使用 GetComponent或内置组件访问器会产生明显的开销。您可以通过⼀次获取组件的
引用来避免开销,并将该引用分配给⼀个变量(有时称为"缓存"的引用)。例如,如果您
使用如下的代码:
function Update ()
{
transform.Translate(0, 1, 0);
}
通过下面的更改您将获得更好的性能:
var myTransform : Transform;
function Awake ()
{
myTransform = transform;
}
function Update ()
{
myTransform.Translate(0, 1, 0);
}
3. 避免分配内存
您应该避免分配新对象,除非你真的需要,因为他们不再在使用时,会增加垃圾回收系统
的开销。您可以经常重复使用数组和其他对象,而不是分配新的数组或对象。这样做好处
则是尽量减少垃圾的回收工作。同时,在某些可能的情况下,您也可以使用结构
( struct)来代替类( class)。这是因为,结构变量主要存放在栈区而非堆区。因为栈的
分配较快,并且不调用垃圾回收操作,所以当结构变量比较小时可以提升程序的运行性
能。但是当结构体较大时,虽然它仍可避免分配/回收的开销,而它由于"传值"操作也会导
致单独的开销,实际上它可能比等效对象类的效率还要低。
4. 最小化GUI
使用GUILayout 函数可以很方便地将GUI元素进行自动布局。然而,这种自动化自然也附
带着⼀定的处理开销。您可以通过手动的GUI功能布局来避免这种开销。此外,您也可以
设置⼀个脚本的useGUILayout变量为 false来完全禁用GUI布局:
function Awake () {
useGUILayout = false;
}
4. 使用iOS脚本调用优化功能
UnityEngine 命名空间中的函数的大多数是在 C/c + +中实现的。从Mono的脚本调用 C/C
++函数也存在着⼀定的性能开销。您可以使用iOS脚本调用优化功能(菜单: Edit-
>Project Settings->Player)让每帧节省1-4毫秒。此设置的选项有:
Slow and Safe – Mono内部默认的处理异常的调用
Fast and Exceptions Unsupported –⼀个快速执行的Mono内部调用。不过,它并不
支持异常,因此应谨慎使用。它对于不需要显式地处理异常(也不需要对异常进行处理)
的应用程序来说,是⼀个理想的候选项。
5. 优化垃圾回收
如上文所述,您应该尽量避免分配操作。但是,考虑到它们是不能完全杜绝的,所以我们
提供两种方法来让您尽量减少它们在游戏运行时的使用:
如果堆比较小,则进行快速而频繁的垃圾回收
这⼀策略比较适合运行时间较长的游戏,其中帧率是否平滑过渡是主要的考虑因素。像这
样的游戏通常会频繁地分配小块内存,但这些小块内存只是暂时地被使用。如果在iOS系
统上使用该策略,那么⼀个典型的堆大小是大约 200 KB,这样在iPhone 3G设备上,垃
圾回收操作将耗时大约 5毫秒。如果堆大小增加到1 MB时,该回收操作将耗时大约
7ms。因此,在普通帧的间隔期进行垃圾回收有时候是⼀个不错的选择。通常,这种做法
会让回收操作执行的更加频繁(有些回收操作并不是严格必须进行的),但它们可以快速
处理并且对游戏的影响很小:
if (Time.frameCount % 30 == 0)
{
System.GC.Collect();
}
但是,您应该小心地使用这种技术,并且通过检查Profiler来确保这种操作确实可以降低
您游戏的垃圾回收时间。
如果堆比较大,则进行缓慢且不频繁的垃圾回收
这⼀策略适合于那些内存分配 (和回收)相对不频繁,并且可以在游戏停顿期间进行处理
的游戏。如果堆足够大,但还没有大到被系统关掉的话,这种方法是比较适用的。但是,
Mono运行时会尽可能地避免堆的自动扩大。因此,您需要通过在启动过程中预分配⼀些
空间来手动扩展堆( ie,你实例化⼀个纯粹影响内存管理器分配的"无用"对象):
function Start() {
var tmp = new System.Object[1024];
// make allocations in smaller blocks to avoid them to be treated in a special way,
which is designed for large blocks
for (var i : int = 0; i < 1024; i++)
tmp[i] = new byte[1024];
// release reference
tmp = null;
}
游戏中的暂停是用来对堆内存进行回收,而⼀个足够大的堆应该不会在游戏的暂停与暂停
之间被完全占满。所以,当这种游戏暂停发生时,您可以显式请求⼀次垃圾回收:
System.GC.Collect();
另外,您应该谨慎地使用这⼀策略并时刻关注Profiler的统计结果,而不是假定它已经达
到了您想要的效果。
三、优化Draw Call 批处理
在屏幕上渲染物体,引擎需要发出⼀个绘制调用来访问图形API( iOS系统中为OpenGL
ES)。每个绘制调用需要进行大量的工作来访问图形API,从而导致了CPU方面显著的
性能开销。
Unity