实战Unity3d - iOS图形性能优化之batching篇

发表于2015-04-29
评论1 4.3k浏览

摘要:本文通过实际项目的经验和具体的例子,说明如何通过减少渲染批次,减少CPU的负担,从而提高游戏的性能。并对游戏图形优化中各工种的配合进行探讨。

 

课题说明:

在手机平台上,3D游戏的性能是个大问题。有限的硬件机能,加上玩家越来越高的要求,使得开发人员必须对游戏的性能进行多方面的优化,并对不同平台特殊处理,才能达到令人满意的结果。下面就通过我们项目中的实际经验,说明如何通过减少渲染批次,减少CPU的负担,从而提高游戏的性能。

我们的项目是使用Unity3D这一引擎开发的,主要面向iphone 3gs 以上的ios手机平台,这里先选择两个常见平台作对比:

机型

分辨率

GPU

CPU

iPhone 3GS

480*320

PowerVR SGX535

Cortex-A8(600MHz)

iPhone 4

960*640

PowerVR SGX535

Cortex-A8(A4 1GHz)

 

可以看出3GS在分辨率较低的情况下,GPU和iPhone 4一样,因此GPU方面的压力较轻,但是CPU要差一个档次。因此这两个平台很可能会出现不同的瓶颈,CPU的瓶颈更有可能出现在3GS上。

 

以下是两个有问题的场景:

一个是游戏的主界面,这个场景有固定的场景布置和特效,没有需要复杂计算的游戏逻辑,但是帧数却很低,需要找出原因。

其二是游戏的副本场景,这个场景有大量物体块构成,他们的位置是随机的,同时有不少特效,动画等,帧数同样很低。

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image001.gif

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image002.gif

为了对他们优化,我们首先需要找到瓶颈。

找到瓶颈:

由于系列文章中已有较好的论述,本文重点不放在如何找瓶颈上,但会简要说一下方法。

使用instruments在真机上进行测试,通过观察OpenGLES图表,发现renderer utilization始终维持在较低的水平上,这说明GPU负荷不大,分辨率低的3GS表现的特别明显。这说明CPU是瓶颈。

通过游戏内置的profiler可以发现,主要CPU开销都在render上,动画,声音,脚本等占用都很低。同时,打开游戏自带的统计可以发现两个场景的drawcall都很高:

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image003.gif

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image004.gif

由此,基本可以确定drawcall(batch)太多是CPU占用太高的主要原因。

减少Draw call的重要性:

下图是摘自nvidia的文章“Batch, Batch, Batch:”,用于说明每帧能够有多少batch是依赖于CPU的。图中可见,每个drawcall提交多少个三角形,对CPU压力变化不大,但是每帧有多少个drawcall则影响很明显。

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image005.gif

由此图,我们可以从理论上得到以下结论:

每帧允许的batch数,由以下几个条件决定:

平台的CPU性能

希望达到的帧数

扣除其他模块对CPU的消耗,一帧内能够有多少CPU时间用于提交batch

如果每帧的batch数超过了允许值,必然会导致帧数下降。那么,该怎么优化呢?

 

优化方法:

为了减少batch数,我们要想办法让不同的游戏物体能够尽量合在一起被渲染出来。方法有许多,下面分别描述。

合并贴图,材质

这个是最基本的需求,如果不同的物体所用材质不同,自然要分开来渲染,那就不能合并了。下图中物体1和2都是树林,但形态不同,这里可以要求美术对他们使用同样的材质和贴图,这样就有了以下优化的可能性了。进行这一步骤需要让美术理解不同物体应该尽量复用同样的贴图和材质,能合并的尽可能合并。

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image006.gif

利用Unity3D引擎的Dynamic batching

Unity3D引擎里,使用同一材质,小于300个顶点的mesh可以自动进行dynamic batching, 即合并渲染,这样就减少了drawcall。为了能够利用这一特性,需要美术帮助控制模型的顶点数,对于简单小物件,远景上精度低的模型等等,是可以减面到要求范围以内的。

 

利用Unity3D引擎的Static batching和 动态Static batching

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image007.gif

但是,总有一些较大的物体无法控制在300面以内,而它们最好也能batching。请看上图,其中使用同样材质的物体很多,但大小,面数都不一样。如果这个场景是固定的(即这些树不会移动),我们可以利用Unity3D引擎的Static batching功能。只要在编辑器里选中不会移动的物体,并标记为static即可,引擎会在编译期合并这些mesh,使他们一次画出。

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image008.gif

在我们这个场景中,由于场景地形是动态生成的,这种方法行不通。但是好在动态生成的树也同样是不要求移动的,因此我们可以在运行期进行动态Static batching。在生成场景的时候,可以将需要Static batching的物体放在一起,这里叫StaticRoot,等所有物体都生成好了,

调用Unity3D的工具函数:

StaticBatchingUtility.Combine(StaticBatchingRoot);

这样就能在运行期实现动态Static batching。

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image009.gif

要注意的是这会花一点时间,即使游戏的load时间变长一点。

改变表现方法

许多时候,更好的优化方法是略微改变表现方法。这需要和美术人员讨论后进行,但是这一方法非常有效。请看以下例子:

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image010.gif

这一喷泉原本是用粒子效果制作的,共耗费了18个drawcall,通过改成一整个模型并进行uv动画的方法,现在只用1个drawcall。

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image011.gif

这些轨道灯原本每个是一个粒子特效,共10个drawcall,通过要求美术人员合并为一个mesh,减少到了只用1个drawcall。

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image012.gif

这些天上飞的海鸥,原本分别是由各自的动画控制的,每只是一个drawcall,通过修改为一个动画控制所有海鸥,现在只用1个drawcall。

以上这些例子都需要与美术和项目经理多沟通,先确定是否能在表现力不变差的情况下,使用另一种更高效的方法。然后确定这些优化是需要美术付出人工的,在工作计划中合理的安排进去。

改变场景设计

 

http://avocado.oa.com/fconv/files/201205/f9b66836dad9323669c3ba9c524d700f.files/image013.gif

这种树冠由于是透明的,所以不能batching。原本场景里有很多,耗费了大量drawcall,经过讨论后,决定远处不明显的树,都可以去掉,或使用其他替代方法,只留下沙滩上最明显树。这种设计改变对效果影响不大,但非常有效的减少了batch,提升了性能。

经验总结

性能优化有一误区,就是认为这只是程序员的工作。许多项目在安排工作时,根本不为性能优化产生的额外工作量留出美术人员的时间。实际上各职能在在性能优化中都有作用,有效的沟通和事前计划能使这一工作事半功倍。

程序员:找出性能瓶颈

修改能程序员自己解决的性能问题

牵涉到其他工种的,与相关人员讨论,提出合理的修改方案

推动其他工种理解性能优化的各种方面

 

美术 制作前尽量了解所需满足的规范,如材质如何合并,mesh顶点限制等。

性能优化开始后,合理安排好时间,配合参与性能优化。

 

技术美术:

优化shader

成为程序员和其他工种沟通的桥梁 

策划:    积极沟通,必要时修正设计,放弃小功能,换取大的性能提升


【注】本文作者:feikailin(林霏开)

 

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