《不可思议之梦蝶》从PC版移植到Nintendo Switch经验分享(下)
在《不可思议之梦蝶》从PC版移植到Nintendo Switch经验分享(上)中,队友游戏制作人李喆分享了需要针对Switch平台开发的内容以及开发中Unity版本的选择。
本文将重点分享《不可思议之梦蝶》的各种优化方法。
演讲内容
下面分享一下包体尺寸的优化。
Switch对包体尺寸并没有太大的要求,因为游戏也同时移植到Android和iOS平台,所以我们也是顺便优化一下包体。
优化方法的主要方法是控制台的Editor Log,每次Build的时候都会在Editor Log中生成非常详细的游戏资源占用容量及比例信息。
通过正向的从工程里查找资源,很难发现哪个资源是不是真正打入包里了。有些资源你觉得好像是用了,但实际上根本没有进到包里。有些资源你觉得根本没有,但它可能会通过材质球或间接引用方式还会进入包的安装部分。
所以通过Editor Log,可以完全清楚看到哪些是在包里,哪些是不在包里的,肯定要把包里的东西进行重点优化。
优化的重点目标就是纹理,一般3D游戏最占容量的可能就是纹理了。Switch平台是支持ETC2和ASTC这二种纹理压缩格式的,这类格式是可以被显卡直接解压的,所以纹理会很快速的载入,然后在压缩时会产生非常大的压缩率。
一般找到纹理之后,要去覆盖对应平台的设置。我们可以切换不同压缩格式,压缩格式也不是越小越好,因为压缩的纹理是有显示效果上的损失的。我们要平衡最终的显示效果和包体体积的关系。
还有一项注意的事情是:如果烘焙了Lightmap和Shadowmap的话,这些纹理实际上是不压缩的。为了获得比较好的查看效果,在PC上也用不着压缩,所以在移动设备上时,我们可以针对平台单独设置Lightmap和Shadowmap的压缩,这样可以大幅度减少包体容量。
我们会很明显察觉到阴影和光照的显示效果变化,并且要对这些进行适中的平衡。其实Switch平台显示的分辨率是比较低的,掌机模式只有720P的画面,下降一些不会有太大变化。
还有一个比较容易忽视的Mip Maps。游戏里会有一些高清的Logo或菜单图标,美术在考虑到后期迭代时,会把图标做得比较大,一般会做到1024或512这种格式,但在PC上其实也不在乎。
如果把Mip Maps这个选项勾掉的话会减少很多存储的容量。很多用在UI上的图片是没有远近区别的,所以Mip Maps不会产生实际上的显示效果。
上图是我们的Build Report,也就是刚刚说的Editor Log的截屏。下面我一步步拆解这个截屏给大家看看,分析一下优化的方法。
上图是第一部分,我们可以看到排序按照:纹理、Mesh、动画、声音、Shader,还有其它的资源、Level场景、Script脚本、Unity自带的库Included DLL、其它File header这些内容。
整体看下来打包之后是1.8G,这并不是实际的打包结果。Android的APK打包出来后,实际上安装后的容量就是这个数字。在APK里面还会再次压缩,基本上会压缩到800多MB的样子。
Switch平台的压缩打包结果应该在1.2G左右,后续还会有一次打包的压缩,这个打包压缩在机器安装以后就解压了,所以在机器上就会占到1.8G的容量。
第一段信息显示了三个数据:60Mb、40Mb、25Mb,这是游戏手绘的动画片。它们都是1080P的,60M并不算很大,而且它们对游戏有很重要的作用,所以我们没有进行特殊的处理。
第二段信息显示是16MB这种都是TTF文件,也就是字体。在游戏里,因为需要支持多语言,例如:韩语和日语,所以要将特殊字体放进去,每个字体都占这么多的容量。大家也要提前想到这点,但如果仅针对中国出一个国服版本,不支持多语言,这些东西都可以删掉。
第三段信息是FBX文件,它们实际上并不是模型,里面存了很多动画,所以文件会有3.9MB的大小,这就比较大了。
上图倒数第二行其实是一个Shader,这是从资源商店买的Toony Colors Pro。它是用于卡通渲染的Shader。但Shader的变体比较多,其实Unity自带的Standard Shader也有这个问题。
变体比较多的Shader在打包时,每个变体都会单独出一个文件,最后会把这些文件汇总成一个,就有3MB多。大家一般不会想到Shader会占那么多容量,但是它因为有那么多变体,所以它只能有这么大。
由于Toony Colors Pro是购买的,我们也不太会改动它,它也非常复杂,工作非常多,所以就只能放在里面。而且我们是在后期才发现这个问题,因此也不好改了。现在我们已经会自己做Shader了,生成的Shader是非常有目的性的Shader,它可以很小很小,一般的Shader,也就是单独功能的Shader可能1K都不到。
所以大家要考虑如果打算自己做Shader的话,就要尽量避免使用这些外部的公共的资源。因为这些资源是通用性的Shader,所以会产生很多没有用的存储。
最后说一下Levels,其实就是场景,从上图可以看见Levels现在有500多MB,为什么有这么大呢?一般制作完一个场景大小大概也就是10-20MB左右。《不可思议之梦蝶》有一个特殊的点,:它都是在室外的开放环境,所以有很多建筑的Mesh。这些Mesh非常大,因为本身它引用FBX文件,它的存储不会占用太多的地方。
我们要进行优化,因为Draw Calls实在太多了。就算切换到静态模式,自动的静态合批在中间可能会被动态的材质球打断合批,在Frame Debugger中可以看到,它的合批是被打成一段一段的。
当物体很多的时候,Draw Calls数非常高。这对显卡没有太大要求,但对CPU压力比较大。Draw Calls数值高在PC上是几乎没有影响的,但是在Switch平台和移动平台上,CPU的压力是非常大的。
我们进行了一个合并工作,就是Mesh烘焙。我们是通过Mesh Baker来完成的,真的非常有效果。Mesh Baker有一个合并的方式,支持按照簇来合并,我们可以把想合并的静态的Mesh选入进去,在工具里去设定覆盖每个簇也就是每个球的半径大小,这个球半径内包含的所有零碎Mesh,它都可以帮你烘焙成一个。
上面不同的材质球都可以通过子Mesh的方式去挂接上去,Mesh Baker会自动帮你合并这些簇。合并簇的一个好处是,静态合批是在运行前就已经处理好了,就是已经完全固化好的一个合批。
此外,Unity有Occlusion Culling遮挡剔除,如果一个物体被另一个物体完全遮挡的时候,它在摄像机渲染上是可以自动拿掉的。变成一簇一簇的话就会很好理解。例如:站在音响后的这些人就可以完全不渲染,这可以极大的提高渲染的性能,所以这是合并Mesh的目的。
合并Mesh之后,可能会让场景变得非常大,但我们可以把Mesh再导出单独的Prefab来,然后放在游戏的资源里去挂接,但结果是一样的,它的体积并不会变小。
为什么会变大呢?大家可以想象一个石头大概有100面,场景里这样的石头可能有1000个。分簇的时候,一块地方包含花花草草,一共会有50个物体,它会把它们合成一个。
合成一个之后,原来共用的FBX文件就没有用了,它就单独生成了一个顶点数非常多的新模型,其实是新的Mesh。因此它的存储容量会大幅度提升,而且这个Mesh本身是不太容易压缩的,所以体积会变得非常大。
为了提高渲染性能和整体的结果,肯定是要丢失一些东西。我们在纹理压缩上进行了很大处理,让出了很多空间给Mesh。
关于纹理,项目从一开始,没有优化纹理压缩格式之前,就包括所有的Lightmap和Shadowmap加起来有2G多,完成纹理压缩格式的针对性设置后,纹理最后加起来才600多MB。
在iOS上,我们把它切换到ASTC的格式后,2G多的纹理可以压缩到180多MB,可以有将近10倍的压缩。所以大家一定要记住这种方法,这是非常有效减少包体的办法。
最后是提升渲染性能。刚刚也说到CPU开销如果太大的话,对帧率的影响是很大的。
大家玩3D游戏多了之后,可能只认为显卡对游戏性能的影响比较大,但实际上关于CPU的开销,我与很多开发者交流,其实项目一开始优化时,CPU跑不动,降低帧率的结果几乎都是百分之百的。
大家一般都不会去考虑CPU占用的问题,拼命去堆功能。这样可能没错,但是最后一定要优先处理CPU开销,才能节约出大量的时间给其它的逻辑,比如没法减少开销的物理引擎,包括一些其它逻辑上的运算。
在Switch平台上,对于显示帧数,有一个单独的工具NxGraphicDebugger。它使用起来和Unity自带的Frame Debugger其实是相似的。这里我没办法分享放NxGraphicDebugger的截图,因为主机平台对开发者有NDA,包括游戏里运行时出现的日志和所有工具图像的截屏,都是不能公开的。
我们努力进行优化,基本上面谈及这些方面的内容,并没有针对游戏有什么巨大的改动,我们的游戏在Switch平台可以从8帧优化到40帧。其实还不算很好,我们本来想要60帧。
但我可以跟大家分享一个经验,Unity打包出来的程序,如果使用Standard Shader,有人做过极端的测试:在Switch平台到底能运行几个Standard Shader的物体在游戏里?它们都是动态物体,不是静态物体,最后测下来只能运行6个Cube,超过6个之后就不能稳定在60帧了。
具体我也没有对运行原理有太多研究,但最后结果是:可能这和Standard Shader的复杂计算有关系,它把Shader换成Unlit非光照Shader以后,即使放入100个Cube也可以稳定在60帧。所以大家在Switch,尤其在掌机模式下也不用苛求60帧,我觉得可以稳定在30帧就已经很不错了。
上面这个视频是在2018年6月9日凌晨1点,《不可思议之梦蝶》第一次在Switch上运行。当时很开心,我本来以为优化基本上没希望了,但经过一些黑洞般的调试后却可以了。
在此之前,我大概经历了一个星期的时间,游戏没有任何画面是可以在Switch上显示出来的,当时根本运行不了,还出现了各种各样的问题,游戏每次都会闪退,根本不知道为什么。
刚刚忘记说了,如果使用第三方插件,在Switch移植的过程中,第一次一定要记得先把插件先关掉,看看游戏到底能不能运行,有没有问题。
一开始闪退后,我们花了3-4天,最后发现是Wwise的一个设置错了,导致每次崩溃都是因为Wwise而崩溃,而且第三方引擎的簇其实在簇日志上输出是非常非常少的,根本不知道是为什么。其实是完全一个瞎调试的状态。
后来通过项目经验的不断积累,我开始把不同的插件都关掉,最后通过排除发现是第三方插件的问题。大家也可以使用这种方法进行折半查找,把项目关掉一半,看看另一半有没有问题,使用快速查找的方法去发现问题。
最后把第三方插件排除掉之后,这是License已经申请到的结果,游戏可以跑起来了。但这个场景其实是Boss战的场景,内容量其实非常少,只有一个Boss和自己,此时运行只有8-10帧的状态,虽然大半夜跑起来让人很兴奋,但其实结果并不算太好。
经过一个星期的优化,上面这个视频还是这个场景,大家可以看到游戏已经顺利运行起来了,它已经可以稳定在30帧以上了,就是这么一个状态。
在优化过程中,我们经历了太多的调试和处理,最后又经过大概一个月的时间,《不可思议之梦蝶》每个场景在Switch上都可以稳定在30帧以上,当然也关闭了一些功能。
再说再一些其它经验。使用Post-Processing Stack后期处理特效包对屏幕特效做处理,它在Switch这类移动平台的开销是非常大的,特别在CPU占用上是很大的。
经过我们调试,后期处理中动态屏幕AO和Bloom效果的占用都比较大,我们最后一定要想一些替代方案。如果可以接受的话,就把它直接关掉。
我的分享到此结束了,大家如果有什么技术上的问题,可以邮件联系我,咱们一起切磋,一起交流,谢谢大家 !
小结
我们感谢队友游戏制作人李喆给带来的精彩分享。更多Unite大会精彩内容分享,尽在Unity Connect平台(Connect.unity.com)。
下载Unity Connect APP,请点击此处。 观看部分Unity官方视频,请关注B站帐户:Unity官方。
推荐阅读
《不可思议之梦蝶》从PC版移植到Nintendo Switch经验分享(上)
如何将Unity以库形式集成到原生iOS和Android应用
官方活动
活动一:Unity官方教师培训课程
7月29日-8月2日将举办Unity官方教师培训课程,现诚邀广大教师一同学习分享Unity最新技术,探讨Unity在教育教学中的创新应用。[了解详情......]
培训时间:7月29日-8月2日,共5天
报名地址:
https://www.bagevent.com/event/5329696
活动二:Unity K12暑期编程体验课报名开启
我们将从7月13日~8月24日每周六13:30-16:00举办Unity K12编程免费体验课程,欢迎10~15岁的青少年进行报名。[了解详情......]
报名地址:
https://www.bagevent.com/event/5330872
点击“在看”,表达你的态度