这是原文
手机游戏的性能异常重要,特别是对于快节奏的动作游戏。你可能知道,我们现在在做一款安卓/IOS平台的弹球游戏,他的特点是在一个3D世界中迅速的物理引擎结合完整的角色动画,任何弹球游戏需要60fps的性能,为了实现它我们需要一点一滴地压榨设备CPU。
所以,我们面对的挑战是,如何在至少60fps的情况下保证游戏运行流畅。只要降低到60fps以下将会减少一半的帧率!60fps-30fps之间切换意味着一个严重的hick-up。而且如果频繁发生将会带来不好的游戏体验。
极限情况,我们想要支持最老的iPhone 3GS,而且要运行在30fps以上。
Above: Momo and Fry are beating up two owl bandits – 四个角色同时出现在屏幕中。
所以性能是非常重要的,当你用Unity开发安卓/Iphone游戏时怎么提高性能?这里有四个我们过去用过的Unity工具,用来优化iPhone/安卓版本的Momonga的帧率。
1.使用Proformance Profiler
第一件事情要做的是看,看你想要提高性能游戏的Unity Profiler,它是一个Unity Pro的特性,让你分析性能瓶颈。分析器是一个无价的工具,通过它,你可以确定所有的帧率问题出自哪里。你在你的目标设备上运行游戏,然后在PC上运行分析器,当你启动游戏时,分析器就会显示出性能数据。
方便的地方是你可以在windows机器上运行Profiler分析一台iPhone或者iPad。
在你的设备上使用Profiler,在开发者模式简单建立一个游戏。通过Unity文档:
为了能够连接一个设备,设备必须在BuildSettings对话框中找到Development Build并勾选,在这里可能还需要勾选Editor和Player Autoconnect。
当你玩游戏时分析器显示CPU使用情况的曲线图,简单的保持你的设备和你的开发机器连接,然后玩游戏,分析器会实时的显示所有的瓶颈和hick-ups。分析器会在一些地方分类显示活动:渲染、脚本、物理、垃圾回收、垂直同步和其他。
对于手机游戏来说,问题通常和渲染有关,例如Momonga,渲染耗费了40%的CPU,这是一个需要我们注意的地方:我们尝试减少顶点和poly数量。
当加载场景时在脚本中会偶有峰值-但在加载场景时有一个低帧率这不是不寻常的。你依然可以看到一些峰值,大部分是物理引擎相关的,这将是我们进一步提高性能下一步关注的。
2.静态批处理(Static batching)
静态批处理是Unity的一个特性,节省了很多CPU循环。它的工作像这样。
每次一个对象被渲染都会有一个“Draw Call”-主要是一条告诉CPU或者GPU的命令,这个对象需要渲染。Unity发出数条drawcalls,然后把它们放在其他drawcalls顶部,使场景完整。但是,每个Draw Call都有CPU开销,而你想要尽可能的最小化Draw Call,将一个draw call比作一个需要油漆的空白画布,你是想要油漆1个呢还是50个呢?我是这样想的。
批处理,它确保没有不必要的draw call被使用,Batching有两种口味:静态(Static)和动态(Dynamic)。
静态给你最好的性能,所以我们总是使用静态批处理。学习细节看这里。
有效的使用静态批处理你要尽可能少的使用不同的材质。为了实现这个你需要整合你的材质到一张大的纹理里,我们选择使用顶点颜色和所有物体有同一模式的纹理,顶点着色允许你给每个顶点一个颜色,删除需要实时光照,颜色将会通过我们艺术家直接画在模型上。这就意味着我们所有的道具和环境中的物体使用同样的材质,静态批处理棒棒的。
Above:静态批处理运行时,注意这些物体在一个单独的Draw Call中渲染。
使用顶点颜色仅仅看上去有一点减少,所以我们有一对乘以顶点颜色的纹理给物体多一点“纹理”。
Above:顶点颜色和一个模式纹理
最后一步是添加一个光线映射在场景中,因为我们几乎没有给物体本身使用任何纹理内存,我们可以有一个相当详细的没有内存问题的光线映射。
静态批处理需要你在Ojbect Properties面板选中“Static”,它只能用在场景中没有移动、旋转或者缩放的物体上。
3.动态批处理(Dynamic Batching)
当静态批处理不是最佳选择时,动态批处理可以挽救局面,事实上,它总是用在哪些不是静态的物体上,使用它你只要使用尽量小的物体和尽量 少的顶点。
批处理动态物体每个顶点有一些开销,所以批处理仅支持网格包含且少于900顶点的网格物体。
我们的着色器使用顶点位置、UV和颜色,所以我们的每个物体可以有高达300个顶点。
一些来自Unity Manual有用的提示:
- 批处理动态物体每个顶点会有一些开销,所以批处理仅被允许使用在网格数量包含且小于900顶点属性。
- 如果你的着色器是是用的是顶点位置, 法线和单一的UV,你可以批处理300个顶点,如果你的着色器是用的是顶点位置, 法线, UV0, UV1 和切向量,你只能处理180个顶点。
- 不要使用缩放尺寸,分别拥有缩放尺寸(1,1,1)和(2,2,2)的物体不会进行批处理。
- 统一缩放尺度的物体不会与非统一缩放尺度的物体进行批处理。
- 使用缩放尺度(1,1,1,)和(1,2,1)的两个物体不会进行批处理,但是使用缩放尺度(1,2,1)和(1,3,1)的两个物体将可以进行批处理。
- 使用不同材质的实例化物体将会导致批处理失败。
- 拥有lightmap的物体含有额外(隐藏)的材质属性,比如:lightmap的偏移和缩放系数等。所以拥有lightmap的物体将不会进行批处理(除非他们指向lightmap的同一部分)。
- 多通道的shader会妨碍批处理操作。比如,几乎unity中所有的着色器在前向渲染中都支持多个光源,并为他们有效的开辟多个通道。
- 预设体的事例会自动使用相同的网格模型和材质。
还有一些重要的小提示:如果一个物体有一个动画但是有一部分从来不动,你可以标记那一部分为静态的,而且他将不会影响动画。
Dynamic Batching is very useful for star pickups and other small objects that are animated but are otherwise the same in the scene.
动态批处理对于star pickups和一些运动的但在同一场景的小物体是非常有用的。
4.音频最佳化(Audio Optimizations)
我们遭遇了一些严重的性能问题,之后我们挖掘问题所在,发现罪魁祸首就是音频。
Unity组件文档中有这样一段话关于音频剪辑:
一般原则,压缩音频(或者模块)适用于长文件像背景音乐或者对话框中,而Native用于短的声音音效更好。
这是一个好的建议,但是有一个问题,我们发现播放有不正确的压缩设置的音频会扰乱你的内存使用或造成CPU峰值。
仔细阅读Unity Manual帮助我们定位了问题所在:
“Note that only one hardware audio stream can be decompressed at a time.”
“请注意一次只有一个硬件音频流可以解压。”
我们看见CPU峰值是因为iPhone使用硬件解码器一次只能解压一个音频文件。
这个可以通过使用“Decompress On Load”设置来解决,性能提升了,但是它造成了内存飞涨,所以真正需要时才使用它。
当用不同类型的音频,我们为了获得最佳性能的一些经验法则:
- 短剪辑 - 本地
- 长的(或循环的)剪辑 -压缩在内存中
- 音乐 - disc流(Stream from disc)
- 造成CPU峰值的文件 - 在加载时解压
如果你遵循这些规则,音频应该不会给你带来太多的麻烦,除非你一次启动了所有的声音文件。
结论
对于手机游戏最重要的事是保持你的三角形、顶点和drawcall尽可能的少,如果你遇到性能问题,Unity提供了很多工具让你的游戏重回掌控,它将肯定不会辜负你阅读文档。
这就是我们现在所有的提示。
你提升性能的小技巧是什么?在评论里让我们知道。