[Unity] 【转载】Unite 2019 |《球球大作战》优化之路

查看:4656 |回复:3 | 2019-11-26 17:30:48

您需要 登录 才可以下载或查看,没有账号?注册

x

自从2015年《球球大作战》发布以来,现已拥有五亿多的玩家。如此庞大的玩家群体,对游戏的画面,性能要求是非常高的。在Unite Shanghai 2019大会中,《球球大作战》客户端主程王国祎和资深技术徐宇峰带来了关于《球球大作战》优化之路。

本文将分享《球球大作战》客户端主程王国祎演讲部分,他将分享《球球大作战》升级到Unity 2017版本遇见升级问题和资源问题,以及如何去处理解决。


2e0a19a8-72cf-44f9-b9b4-7add9189ac2f_640_1.jpeg



演讲内容

大家好,感谢大家来听我们的分享。我是《球球大作战》客户端主程王国祎,主要负责《球球大作战》的客户端开发。之前都是以听众角度参加Unite大会的,这次作为一个演讲嘉宾过来参加,感觉体验还是不太一样,很有新鲜感。

简单介绍一下《球球大作战》,这是一款多人休闲竞技游戏,主要强调多人合作玩法,玩法简单上手,但想要达到高的级别或段位,还是比较困难的。

《球球大作战》发布于2015年,当时很多游戏的玩家现在都上了初中或高中。就像《超级马里奥》或《魂斗罗》可以成为我们这一代人的回忆一样,我也希望《球球大作战》能成为他们的长久陪伴,这也是我创作游戏的初衷。

升级Unity 2017

《球球大作战》早期使用Unity 4.7开发,所以整个表现效果都是Unity 4.7版本,后来我们也尝试升级了Unity 5的版本,但发现问题还是比较多,所以我们去年做了Unity 2017版的升级,我们会在下面分享升级过程遇到的一些问题,后面还有优化的过程和新的方式。

先讲第一部分,是我们升级Unity 2017遇到的一些问题。最开始我们也尝试升级Unity 2018版本,我们试了Unity 2018.1和Unity 2018.2,在转换过程中的问题还是可以接受的,但上线测试时发现了兼容性问题,最后我们还是选择使用比较稳定的版本,也就是Unity 2017.4.3。

小提示:Unity每个周期会有3个TECH技术前瞻版本和1个LTS长期稳定支持版本,Unity一直建议对已发布的游戏采用LTS版本,也就是Unity 2017.4或者Unity 2018.4,从而避免遇见上文提到的兼容性问题。请阅读:Unity全新的版本发布计划。

为什么选择Unity 2017呢?主要是因为它和Unity 4.7有一些不同的地方。



1、ASTC图片压缩格式

我们一开始尝试在Android和iOS同时使用该格式,后来经过大量测试发现Android不支持这个格式机型占比很高,最后在Android系统上还是使用原有的ETC和ETC2格式,只在iOS上使用ASTC格式。

iOS在iPhone 5S及以下机型硬件会走原解压的过程,整个图片的加载速度会比之前稍微慢一些,但我们觉得速度测试下来还是比较理想的,所以还是坚持在iOS系统使用ASTC格式。

2、Bundle LZ4的压缩

在Unity 4.7版本时,我们基本是不做压缩和解压缩的,中间会用LZMA做传输过程的压缩,这样在压缩和解压方面不会占用时间。

到了Unity 2017.4后,因为它本身就支持LZ4的压缩,不管从解压速度和内存大小来说,它都是很少的,所以我们最后决定用LZ4。

3、Bundle文件的异步加载和读取

在使用Unity 4.7时,我们在加载非压缩文件时是走同步的方式,因为本身Unity也没有做异步加载Bundle的接口,但是Unity 5.x以上版本就支持这个接口了,所以我们这边Bundle是使用了异步加载的方式。

4、运行时设置分辨率

我们有一些优化测试下来发现,该游戏本身手机的分辨率可以达到很好的提高帧率并降低消耗的效果。

Unity 2017.4和Unity 4.7在设置分辨率有一个很大的不同是,之前在Unity 4.7降低分辨率时,在Android系统会出现闪一次黑屏现象,这在Unity 2017.4上是没有的,所以我们可以用这个特性来动态调整屏幕的分辨率。

在特定场景中,例如:高渲染的场景中,可以动态调低分辨率,使用户可以在没有感知的情况下提高帧率。

5、Camera RT缩放分辨率可提高帧率

在Unity 4.7上我们尝试过在Camera缩放分辨率,但是没有效果。在Unity 2017之后,我们尝试这个方式发现效果比较明显,发现平均帧率可以提高15帧左右。但是带来的问题是,可能显示上有稍许的差别,没有原始的不改分辨率的情况好。

6、Android支持IL2CPP

Android支持IL2CPP主要是为了Google之后发版本的。

7、支持GPU Instance

我们在年初的时候制作一个3D的玩法,如果是Unity 4.7的话,这个玩法在我们的机子上就爆表了,因为同场景渲染的动作非常多。

在升级到Unity 2017时,使用GPU Instance帮了很大的忙。尤其在动作处理这块,可以动态合批,然后它合成的效果非常好。

8、动画系统可以对指定区域缩放

最后一点也是美术吐槽非常多的,那就是Unity 4.7动画调整的时候,不能对指定区域进行缩放,它只能一帧一帧地调,这是升级后缓解最大的一点。

Q1:游戏帧率降低

下面简单说下升级2017后遇到的一些问题,这些问题是我们没想到会发生的。因为我们想:升级引擎只是对一些资源,效果会有一些提升,甚至效率会提升。但升级完之后,测试发现在同等手机,同等内容的情况下,帧率反而会减低。



我们对问题查了很久,做了很多版本的比对,甚至对不同版本,不同客户端进行差异的比对。测试下来的效果是:Unity 2017在同等情况下比Unity 4.7要低10帧左右。这主要发生在中端偏低端的机型,正常的中端以上机型没有这个问题,甚至表现效果会更好。

我们测试问题的时候,还做了独立的只有核心玩法的版本,这个版本抛离了游戏以外的系统,只有核心玩法。这样是想更好地测试过程,并尽快地排除问题,

因为这些问题比较难发现,所以这个版本一直是我们测试的核心版本,而且这个版本也做了动画录制的功能,把每一局的表现的协议和脚本都录制下来,每一局都是自动播放,这样循环地查看问题,查看每个帧率的表现,最后找到这些问题。



有几个选项上的切换,一个是Android上的Blit Type

Blit Type选项在Unity 2017版本上是2.0之后开放的,也就是说2.0之前是没有这个选项的。我们测试时发现,把这个选项关掉后,帧率确实提升了很多,提升了5-6帧左右,我们发现它对中低端硬件的渲染影响还是比较大的。

我们与Unity官方技术支持交流,他们说针对不同的游戏,这个选项可能选择自动的会比较好。但是测试下来发现,可能因为我们的游戏对3D和渲染光照方面使用的不是很多,所以去掉该选项,使用Never可能效果会更好。



因为我们的游戏表现上看起来是一款2D游戏,所以对镜头上的HDR和抗锯齿MSAA不是很实用,所以我们会在Camera组件中,去掉勾选Allow HDR和Allow MSAA这二个选项。

还有光照这块,因为游戏没有使用实时光,所以我们在Lighting设置去掉Realtime Lighting和Mixed Lighting选项。调整了这些选项后,帧率持平了原来的游戏表现。



Q2:资源问题

下面是转换上的资源问题。球球到现在为止的皮肤总量已经超过4千多个,也就是意味着我们在转换过程中要排查每一个资源,和旧的资源去比对,会不会有显示上的问题。这是非常巨大的工作量。



这边一个问题就是,我们有一些美术同学可能前期从一些旧的资源里,使用Mesh导出的文件包含中文的命名,这是为以后埋了一个坑。

虽然在Unity 4.7里没有问题,会显示一个横杠,不会显示中文名,显示上不会有问题。但同样的资源转到Unity 2017后,显示上会出现一些引用丢失的情况。

我们分析过后,发现Meta文件中的Unicode码丢失了,所以需要手动地把这些复制过去,所以这是当时解决问题比较棘手的地方,因为当时都是手动复制的,幸好这些中文的资源不是特别多。



还有就是转换之后粒子缩放的问题。因为球球的皮肤之间是互相叠加的,叠加之后为了做相互的叠加效果,会有Z轴的压缩。所以转换之后,粒子的缩放模式变成了Hierarchy模式,根据主节点一起缩放。

这个问题导致的效果是,Z轴上的粒子表现缩放会有缩放的显示问题,会有穿插,最后表现的效果是和大小缩放后的效果不是很一致。

我们向Unity反馈过这个问题,Unity也在跟踪处理这个问题。我们现在改成了Local模式,因为我们自定义了一个缩放的脚本来控制球体和粒子放大缩小后的效果。



Q3:打包问题

接下来分享我们碰到的一些打包上的问题。



我们的美术资源现在有6G多,在旧版本中打包耗时非常长,耗时通常要半个小时左右。在资源量非常大、冗余之后,工程启动也非常慢。

升级Unity 2017之后,资源在打包速度和工程开启速度上都有些提升,但还是没达到理想的情况。

我们采取的方式是把老旧资源拆解到另外一个工程里面,保证二个工程的引用是统一的,Guid也是统一的。这样在老工程中的资源是不进行打包处理的,只打包新的资源,这样提高了很多打包速度,Unity打开美术工程资源的速度也会非常快。



我们在Unity 4.7导出的是一个Eclipse的项目,所以在打包时哪怕文件很多也不会有打包失败的情况。但是使用Android Studio的时候,如果使用默认设置的话,会出现打包失败。

这个失败问题比较奇葩,它不会给你提示错误,只是打包时间非常非常漫长,甚至在最后没有结束的时间。

我们也查了很多资料了解这个问题,最后发现是要调整缓存,在打包Android Studio时,如果本身包含的文件非常多,要记得把缓存改大一些,要不然打包时会有问题。



在导出iOS工程时,我们会导出XCode工程,发现每次导出时Framework Search Paths的目录,就是库引用的目录每次都会被清空。

我们有很多第三方的库是需要被引用的,而且打包是自动的,iOS这边导出后会自动设置好,所以后面改了方法,是在导出时使用PBXProject.SetBuildProperty方法,把需要引用的库再动态地添加上去,来解决这个问题。



客户端版本

这是我们测试的一种方式。我们游戏对玩家手感操作的敏感度可能非常高,也就是说,如果一个版本发布后,和之前的手感有所差别,对我们是比较灾难性的结果。

所以我们测试使用二个版本,一个叫预览版,一个叫正式的线上版。玩家正常玩的都是线上版,然后我们会推送给玩家预览版,预览版的账号和服务器是通用的,只有客户端不同,一个是普通的是Unity 4.7版本,另一个是升级之后的Unity 2017的版本。

我们让玩家体验这二个版本,并且给反馈,因为玩家会在同一个手机上体验二个版本,所以给出的反馈都是比较真实的,都是比较及时有效的。我们觉得这个方法是最有效的测出问题的方法。



版本兼容,渠道更新

我们线上其实一直存在二个版本,因为我们早期尝试使用过5.x版本去升级。当时做完后发现效果并不好,而当时盲目乐观地直接用5.x版本进行开发,导致新制作的资源都回退掉了。

我们进行Unity 2017版本升级的时候,直接拆成了二个版本,也就是说正式开发过程还在Unity 4.7上,无论是美术还是程序,都在老版本开发。

线上还会同时存在老版本和新版本,开发的内容和功能在Unity 4.7版本更新好后会合并到Unity 2017的版本,并同步更新出去。二个版本一般会有三个月的兼容期,尽量让玩家把测试期缩短,让玩家在里面反馈问题。

我们会在部分渠道先上传一些版本,然后小范围地进行更新,目的是不影响玩家的情况下进行更新,担心新版本的兼容性会存在问题。



球球优化

下面讲一下球球的优化,前面我们讲了球球的升级,其实升级的目的是想通过升级的一些手段去做新一轮的优化。

以前我们会从技术角度去做问题的排查和优化,例如:玩家网络有问题,反映延迟很高。我们觉得把TCP换成UDP,并且调到比较好的主干网络或机房网络,会解决这些问题。其实并不然。

有一次我参加《球球大作战》的见面会,一个玩家吐槽他连接自家WiFi时非常卡,延迟非常高。他上网查问题,搜了一些帖子,发现有人回复说把防火墙关掉,他尝试后发现真的好很多。出现这个问题我想的是可能他的网络把UDP常用端口屏蔽掉了,然后只能走不是UDP常用的端口。

通过这个问题,我们发现玩家往往发现的问题不是我们要优化的点。我们从技术角度想的一般是网络上换一个网络底层,把DrawCall降低,以为这样就解决了问题。其实并不是,我们要从玩家的角度去查找到这些问题。

制定美术资源标准

我们之前的美术标准都是一刀切,例如:最高不可以是多少Drawcall、面数、骨骼数。

但美术在制作资源的时候,如果低于这个标准,例如很简单的资源,美术会觉得反正低于这个标准,那么就多加一些特效。如果超过这个标准,但是又是重点的付费道具,短时间无法优化好。

我们总结发现,美术资源标准要差异化。

下图是我们新制定的美术标准。



对于美术或游戏来说,我们的道具分普通的道具和炫酷的道具,我们要把档位精细化,有界定的指标确定一般的档位是多少,然后是比较炫酷道具的指标,再定最大指标。

这样美术操作时会觉得比之前灵活很多,会知道自己制作的资源属于什么档位,然后按档位去做优化。

LOD优化

还有就是针对游戏的LOD优化,因为《球球大作战》看上去更像是一个2D游戏,和3D游戏的LOD优化不太一样。

我们使用的方法是皮肤像素占屏幕像素的比例差,进行高低品质资源的切换,在球体非常小的时候,我们会提供低配的提前渲染好的图片。

因为我们试过简化特效粒子,发现不管是工作量还是效果都不是很理想,后来我们发现玩家主要注意的视野都是大球,而不会很关注小球。所以我们采取的方法是,提前渲染好图片,替换到比较小的资源上,在玩家球体很小时,使用图片渲染。



手机性能分类

对于手机机型划分,很多优化方式对玩家或多或少有影响,所以我们想针对不同机型对游戏做优化。最开始其实没有按机型分,因为我们觉得机型太多无法划分。

我们的方法比较投机取巧,那就是使用CPU型号去做手机型号分档。网上可以找到CPU梯度图,不同CPU在不同档位,只要获取玩家的CPU信息就可以对应到不同的档位里面。

但测试后发现这个方法不太乐观,因为我们遇到一个现象:有的手机CPU处于中档,但是屏幕分辨率却非常高,这时会出现整体性能表现降低的现象,所以我这种方式不太靠谱。



我们最后选择的方法是:由于游戏运营已久,有大量的玩家帧率卡顿日志,所以我们通过玩家的帧率、每局游戏得到帧率差值、最高最低值等,决定该局游戏的帧率范围。

然后过滤出来手机在运行时是处于高档机型、低档机型、还是中档机型。这个分档比较靠谱,虽然这样涉及机型较多,但准确性比之前的方法高很多。

我们发现周边的同事都在不停的换新款手机,所以我们会习惯认为玩家的手机也在不停更新换代。通过游戏数据我们发现千元机占了60%多的用户,这也让我们把优化重点放在这些手机型号上。

网络卡顿

下图是我们每局结束都会上报的网络使用情况,我们还没对数据做处理,而是对上报结果进行分析。

我们觉得玩家手机使用4G基站网络,或使用WiFi,过程是路由器到主干网,主干网到游戏服务器。这只是把主要网络情况监控下来,后期会做一些筛选和定制化的策略,例如一些提醒,这是我们后面要做的事。



小结

在《球球大作战》优化之路的下篇中,我们将继续分享本次演讲巨人网络资深技术徐宇峰讲述后期游戏制作中的优化方式,敬请期待。












上一篇我们分享了《球球大作战》优化之路客户端主程王国祎部分,本文将继续由资深技术徐宇峰讲述后期游戏制作中的优化方式。





演讲内容

大家好,我叫徐宇峰,负责《球球大作战》的性能优化。

《球球大作战》现在拥有五亿多的玩家,为了吸引如此庞大的玩家群体,我们提供给玩家更炫更酷的皮肤,这些美轮美奂的皮肤,让《球球大作战》的游戏画面更加绚丽多彩,但随着皮肤日益精致,性能问题开始日益突出。



我们的皮肤正面看起来很简单,从侧面看,皮肤由精美模型与很多特效层组合而成。

皮肤的材质大部分为半透明。大量的半透明材质无法合批渲染,导致单套皮肤Draw Calls达到82个,面数1.1万以及骨骼40个。



《球球大作战》最核心技能就是分身吃球,而当玩家分身之后,Draw Calls更是暴涨,游戏中玩家最大16分身时,Draw Calls有820多,面数达17.7万。



在实际游戏中,多玩家多皮肤分身后,Draw Calls经常能轻松过千,下面视频是我们内部的极限测试版情况。

大家能看到,Draw Calls最低有400-500,最高达到2000多, 如此高的Draw Calls导致游戏的帧率急剧下降,卡顿严重。而球球作为一款竞技游戏,性能与体验至关重要。

我们团队采用各种优化方法:


  • 模型贴图合并:模型与贴图尽可能的合并在一起,利用Unity的动态合批渲染,减少Draw Calls。
  • 减少半透明材质:半透明会带来融合运算,其次重叠的半透明物体无法合批渲染,导致Draw Calls增加。
  • 减少粒子系统:粒子会增加CPU运算,还会增加Draw Calls,每套皮肤的粒子数量我们控制在40个以内.
  • LOD系统
  • 降低分辨率:皮肤的贴图普遍采用512k,部分贴图在低端机器上降低到256k。




我们来看看优化对比。

下面视频是一个LOD系统的效果对比,左边是高性能机型高画质,右边是低端机型流畅画质。左右相互对比可以看到,右边的皮肤少了些特效与动画,贴图分辨率也相应降低。

通过以上优化,游戏性能大约提升52%,但画面品质同样遭受损失,在中低端机器上尤为明显,这点很容易引起玩家的不满。

美术团队也希望所有机型,画面尽可能的完美,并且过少Draw Calls极大限制了美术的高水平发挥。

《球球大作战》优化的难点是皮肤分身后Draw Calls暴涨的问题

我们想到用RenderTexture来降低Draw Calls峰值,但皮肤有太多半透明,渲染管线中对于透明相关的处理是在管线后期进行的。由于不同物体是按照顺序渲染的,对透明的处理方式是混合,实际上就是shader输出颜色与此像素位置已有颜色的合并过程。

下图中的混合公式是Unity中最标准的混融模式Blend SrcAlpha OneMinusSrcAlpha。



假设将Camera背景的颜色设置为全黑色(0001)或全白色(1111) ,分别进行渲染,渲染后的颜色分别为Cblack、Cwhite,得到公式1和2。公式中蓝色为已知数,紫色为未知数,2个公式可以求出2个未知数。

具体代码请参考:http://wiki.unity3d.com/index.php/AnimationToPNG

下面看看具体制作流程。



我们把原资源用单相机渲染到RenderTexture,相机每帧切换黑白背景,形成连续序列帧,这是因为单个相机能节省更多的Draw Calls,但如果动画速度过快,就必须使用双相机保证品质。

RT经过GPU做算法剔除,输出到多张RenderTexture。RT我们采用512分辨率,一共40张,格式为ARGBHalf,真机占用内存约为20兆,目前市面上主流手机内存大部分为2G以上,所以内存很充足。具体用到那种分辨率与RT数量的多少,需要根据不同机型做适当调整。



多张带RT的RenderTexture组成一套序列帧,利用Plane切换RT做成序列帧动画。序列帧会循环渲染,从RT1渲染到40,再回到第1张。

Plane读取RT时也是循环读取,最后序列帧动画放到场景中与半透明背景,半透明皮肤以及UI等进行融合。

下面我们来看看原资源与RT资源的实时效果对比。这是原素材与RenderTexture的实时效果对比,原素材由十几层特效叠加,而RenderTexture只有单个面。



大家看看不同资源的效果对比,新技术首先必须保证美术品质才能投入使用。





在美术品质保证后,再看看优化前后Draw Calls对比。

当分身不断增加时,Draw Calls以线性增长,大家可以看看下面的Draw Calls图表,从最开始63暴涨至900多。

在RT模式下,分身的增加带来Draw Calls的个位数增加,同时可以看到在RT模式下,因为我们利用多张RenderTexture,每个分身的动画帧是错开的,动画并不完全一样。

我们再看看真机数据对比,测试平台为普通千元机。

如下图所示,左图分身数从1至16,普通模式Draw Calls从63暴涨至917,翻了14.5倍,每一次分身数量的翻倍都让Draw Calls剧烈变化。而RT模式从64到83只增加19个。

有图CPU消耗图,在RT模式下,CPU的消耗非常平稳,而普通模式最大分身时消耗已经翻倍。



再来看看FPS与内存消耗。

如下图所示,帧率在普通模式下,16分身帧率已经降低到25,加上UI与其它逻辑消耗,已经产生游戏卡顿。而RT模式帧率非常平稳。

内存方面因为RT用了40张16位的512贴图,内存大约多20MB,这是RT模式唯一消耗点。实际应用中我们会根据机器的内存容量,控制RT的数量与分辨率。



《球球大作战》同屏有上千物体,每帧数千个物体的位置、大小、动画、网络数据等伴随着产生大量逻辑运算。

主要逻辑有:


  • 利用插值函数使物体的移动更加平滑。
  • 玩家吃球后重量会增加:根据重量来计算球的尺寸与前后位置,尺寸越大物体越靠近摄像机。
  • AI状态机:玩家根据游戏状态,如二个玩家距离接近时,会播放调侃动画,吃掉其他玩家时播放炫耀动画;
  • 相机视野计算:玩家所有球的数量与尺寸变化,都伴随着相机位置与FOV调整,每个分身必须在相机视野内,最大分身尽可能处于屏幕中心;
  • 其它逻辑:还有网络数据解压缩、解密、背景迷雾、UI运算等。

以上这么多的实时运算量会对CPU产生巨大压力。



我们利用Unity 2018的ECS系统,把所有逻辑做分类,纯逻辑运算做成PureECS,其他部分做成HybridECS。数千物体的逻辑运算,尽可能分配到多个核心。

这极大的提升游戏性能,并且更快更复杂的运算让物体的移动、旋转更加平滑和细腻,增强游戏的用户体验。



上述的优化方法,部分处于《球球大作战》的试用阶段,我们一直都在不断尝试和创新,使用各种优化方式,让《球球大作战》拥有更好的用户体验,并不断焕发新的活力!

我的演讲到此结束,谢谢大家。

小结

我们感谢《球球大作战》的创作团队给带来的精彩分享。




评分

参与人数 1元素币 +13 活跃度 +12 展开 理由
源支始 + 13 + 12

查看全部评分

2019-11-26 17:30:48  
 赞 赞 0

使用道具 登录

3个回答,把该问题分享到群,邀请大神一起回答。
2#
感谢楼主分享
回复 收起回复
2019-11-26 18:29:29   回复
 赞 赞 0

使用道具 登录

3#
感谢楼主分享。
回复 收起回复
2021-8-23 15:37:00   回复
 赞 赞 0

使用道具 登录

4#
感谢楼主的分享~~~
回复 收起回复
2021-8-27 17:21:24   回复
 赞 赞 0

使用道具 登录

CG 游戏行业专业问题

手机游戏引擎手游引擎Unity3D技术
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表