Epic设计师:《堡垒之夜》如何做多平台优化
《堡垒之夜》是一款百人同场、动态丰富的开放世界游戏,玩家的可视距离非常远。因此在跨平台移植中,开发团队要考虑游戏中哪些东西需要被剔除,又如何剔除。与此同时,如何让游戏在手机、游戏机和PC的跨平台联机中保证同步,也是开发团队在移植中面临的一大挑战。
《堡垒之夜》是一款开放大世界游戏,游戏内百人同场、全动态、可破坏、可建造,玩家的可见距离非常远。如何平衡效率和效果是移植中需要考虑的事情。
在全平台开发中,我们面对的最大问题不仅仅是开发完PC开发手游,各自跑各自的,而是不同的平台之间可以联机战斗。我们要保证游戏在手机、游戏机和PC上是同步的,否则会带来游戏不平衡。我们目标在PC和高端的游戏机上跑到60帧,移动平台和低端PC共享优化方案;通过减少Draw call,减少三角面等,优化shader,减少内存开销等方式提高效率,同时保持视觉效果。
在优化之前我们内部有一个报告。我们会用各种工具统计两个版本之间的优化差异,这样可以非常好地跟踪优化的效率。
《堡垒之夜》中的建筑由非常多的模块组成,同时每个模块又可以破坏。一个建筑有三到四百个模块,一个城市折算下来有十几个建筑,再加上地面其他的物件,一个小镇很轻松就可以到达到几千个模块。
对于普通的游戏或者普通的方案,我们可以利用一些比较激进的剔除方式,比如把远处的直接裁减掉——很多游戏都是这么做的,大家似乎也能够接受,但这么做不是很优雅、不是很高级。
而且《堡垒之夜》是全平台对战游戏,如果各平台剔除不一致,Game Play就会不平衡。
另一种方式尝试直接使用HLOD。我们可以把很多模型和材质合在一起,但是中近距离的品质是无法接受的,非常的LOW。而且HLOD无法部分被摧毁,在中远距离无法反映实际模块已被摧毁的状态,如用狙击枪、远程武器可以穿透,所以这个方案不合适。
于是我们提出了DHLOD的概念,就是可破坏的HLOD,它的面数和品质介于原始模型和HLOD之间。
那么怎么制作HLOD呢?我们可以把原始所有的模块合在一起,这样面数非常多,于是我们决定使用原始品质的第三级的LOD合在一起。第三级的LOD品质制作的非常精巧,我们采用了手动产生LOD的方式而非自动生成,比如说手动调整模型法线产生一些硬边。
我们用HLOD工具获得最LOW的那级LOD合并在一起,材质也合并在一起;这些HLOD合并的参数设置可以作为一个资源,资源在不同的地图、不同的建筑之间共享,而不需要每个建筑在生成DHLOD时设置它的参数。
合并完成之后,DHLOD还需要具备可破坏的功能。中距离如果被破坏掉,DHLOD相应的区域也要取消掉。具体做法我们使用了坍塌顶点的方式,在制作时每个模VC中给与了一个唯一的2D index 作为标记; 地图在生成时为每栋建筑生成一张G8 的RT,游戏中当玩家敲掉其中一个模块时,在RT相应的位置写入一个黑色的象素,然后使用模块的VC作为UV来采样这个象素,对它进行顶点的坍塌,来达到隐藏的目的。
同样植被在远距离我们也需要在保证效果的同时保证效率;我们不希望它在远处被裁切掉,于是利用了HLOD加上IMPOSTOR的方式。
IMPOSTOR简单的说是通过shader,在简单的quad模型上绘制采样类似flipbook贴图的不同区间图像,来匹配摄像机的视角从而模拟真实3D的方式。这极大的降低了三角面的开销。然后把做完的IMPOSTOR作为HLOD的一部分来减少DC数量。这个过渡非常平滑,因为每种树都需要单独的贴图和材质,这对贴图的开销以及内存可能会有一些占用。
如果直接用HLOD合成,那么会面数既高效果又差。但用了Impostor加HLOD,三角面就会比较低,而且效果比较好。制作上,我们提供了两种工具,一个是Engine Content下已有提供的Render To Texture工具,另外一种是Ryan brucks提供的Plugin
● Render To Texture
https://docs.unrealengine.com/en-us/Engine/Content/Tools/RenderToTextureTools/3
● Plugin
https://github.com/ictusbrucks/ImpostorBaker
而对于草的优化,一方面在于三角面的处理,另一方面是材质,以及密度。三角面上我们多增加了LOD;模拟摆动的动画在材质上做了简化,并去掉了比较废的Rotate(旋转)节点,使用Pan(平移)的方式来模拟摆动。
地形的优化这块,主要是在层数上减少,比如从PC上9层减少到手机上的4层;还降低了材质的复杂度。在流程上,我们自己做了BP的工具,它可以在9层的范围下工作,可以自动利用BP工具把它合成4层,不再需要为了针对某种平台专门去处理。最后呈现的效果与原先差别不大,主要的区别在于我们去掉了层与层之间过渡的细节,如果没有这些细节,草和土之间过渡会比较模糊,有了这些细节这些过渡会比较清晰。
场景的优化主要在于合并物件,怎么合并?我们有一个POI的概念,就是在一个兴趣点附近的物体会合成一块,面比较少的物件合在一起。合并物体要增加包体的大小、需要平衡。
在手机上,我们为场景的LOD做了非常激进的切换,并且在4.20版本中新加了一个MinLOD,就是最小LOD的剔除。与此同时,玩家在游戏中制造的墙面或者建筑物的面是非常多的,要将它尽量的简单,尽量的用LOD,面数尽量少且品质尽量高。另外,手机上Mask的开销非常大,我们可以让模块被建成以后瞬间切换成非透明的材质,这样就可以减少开销。
视距剔除方面,我们采用了逐平台调整视距的方法。我们先将低端平台调成合适的距离,高端平台再往远处加,这样对游戏体验会比较好。除此之外,我们还利用DetailMode剔除了一些装饰,所有的物体作为BP都可以逐个设置参数,以及设置绘制的距离。
风暴云的话,一个要处理的是面数,另一个是材质复杂度。于是我们分割了风暴云的模型,利用视锥剔除减少了渲染的面数,并仅在透明区域做了材质Mask的变化,以减少透明的开销。
另外,《堡垒之夜》中的阴影是动态的,它会根据太阳的起落而不停转动。我们不想去掉游戏中的远距离阴影,但如果它是动态的,那会非常费性能,所以我们也做了一些优化。
优化的方法是假阴影。简单来说,就是使用模型制作假阴影,用Quads模型,用光影方向改变Quads的形状化方向。在贴图上,我们对每种类型的树做了四个方向剪影,做入RGBA通道里面,然后添加距离场效果。
材质的实现主要分为两块:一块是阴影形状的变化,简单来说就是利用光线的方向产生权重,来决定使用贴图的哪个通道来改变阴影的形状;距离场的作用是在形状切换时产生形状变化的混合。另一块是使用Vertex Shader做Quad的旋转以及拉伸模拟。
角色优化则分为顶点和材质复杂度两块。顶点可以参考一下每级的数量,MinLOD设置为1。LOD1去掉了头骨,LOD2去掉了手指和一些骨骼。LOD的生成参数,比如需要多少面,多少屏幕比例进行切换等,都可以存成一个资源,这个资源对不同角色可以反复利用,不用再重复设置。
Sections的话,我们将其合并为四个——头、身、背包、武器。在PC上我们使用Mask来隐藏身上的某些附件;移动端为了优化材质,使用了Opaque材质,同样通过VS坍缩顶点的方式来进行隐藏和显示。
在角色动画方面,一些长动画比如滑行,会很占内存。于是我们在手机上用一些简单的Pose加上一些Additive的Noise动画来模拟,减少内存的开销。
灯光方面则去掉了一些动态灯光的支持,减少Shader Permutation的数量,也降低了渲染开销。
在特效上,我们去掉了在手机平台很占内存的Morph target,因为实现这些Morph动画效果的贴图无法Steam和被压缩。其次,我们结合Significance设置其重要性,来决定其tick 频率以及是否被绘制等。再者,我们使用固定边界盒,设置好它的大小,从而极大减少了CPU的开销。
由于很多特效是透明的,而透明材质的光照非常耗时,所以我们将手机上的透明材质换成了简单的光照模型。另外,我们通过在材质中去掉一些之前没有用的静态分支,来减少Shader数量,同时也去掉了一些极大增加手机开销的环境特效,比如云雾等。
另外,《堡垒之夜》中掉落物品的种类很多,它们在PC上包含很多不同的部分,比如背景、前景、特效、勾边等。在手机上,我们首先将所有部分合成为一个物体,然后材质上做了简化,另外一些描边效果和之前材质的静态分支也去掉了。
最后在贴图上,我们从不能Stream贴图和大贴图着手,另外UI也是挺大的一块。我们为UI做了mip, 根据分辨率的需求在特定平台上使用特定级别的UI,并重复利用了一些贴图,使用Device Profile在不同的平台设置不同平台的Texture group 参数来减少内存开销。