《球球大作战》优化之路(下)

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


演讲内容

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

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


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

皮肤的材质大部分为半透明。大量的半透明材质无法合批渲染,导致单套皮肤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

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

如下图所示,左图分身数从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。数千物体的逻辑运算,尽可能分配到多个核心。

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


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

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

作者:徐宇fen  
原地址:Unity官方平台

最新评论
暂无评论
参与评论

商务合作 查看更多

编辑推荐 查看更多