挖掘手机硬件的潜力 -- 张黎明:《Unity企业级支持案例与分析》
关于Unite
Unite大会是由Unity举办的全球开发者大会,至今已有10年的历史。Unite现已成为游戏行业,VR/AR行业中最具有权威性和影响力的活动。
张黎明:非常感谢大家来参加今年的Unite,其实我现在看到有的朋友已经不是第一次来参加Unite,我是第三次站在Unite讲台上面,感到非常荣幸。
今天的题目是Unity企业级支持案例与分析,我们Unity在中国的业务已经开展五年时间了,最近一两年时间发展非常快,国内现在规模上排名靠前的游戏开发公司基本上都是我们Unity企业支持服务的客户,最近这一两年,游戏市场也发生了一些变化,现在的厂商已经逐渐都往重度的游戏转型,不像过去两年前,很多公司还是在做休闲游戏,现在几乎我们能见到大部分企业客户都做重度游戏。
开发者都在想尽办法挖掘手机硬件的潜力,在这个过程中,我们也是和企业客户发现了很多问题,在这里希望和大家把这些问题分享出来。
我今天首先介绍一下Unity企业支持服务介绍,后面会讲一下我们在企业支持的过程当中,我们大部分的客户都比较关心的一些话题,最关心就是性能分析,因为游戏开发具体技术来讲,因为每个项目游戏类型不一样,使用的技术也有可能有很大的差别,不同的项目可能不会有很多共同的话题,但是性能是所有项目都非常关心的。
后面也是大家都比较关心的,就是说我怎么样选一个引擎版本,遇到Bug、遇到崩溃会怎么处理等等一些常见问题。
然后简单的介绍一下我们企业的内容,我们有线上支持、性能优化,我们每个月定期进行线上优化,解决一些疑难杂症,可能有一些特殊的Bug处理,对我们企业客户的Bug有特殊的处理流程。
我们还是进入我们的主题,就是我们所有开发者关心的性能优化的问题。性能优化这方面,我们官方的技术支持团队,现在是希望在这三个方面给大家有所帮助。
首先,我们给企业客户提供Project Review服务,到线上做两天的性能优化和性能分析,给出一些意见。下面我们分享我们在分析的过程当中,很多项目都遇到的一些性能问题,我把它总结了一下,然后后边介绍我们做性能分析的时候常见的性能工具,对大家分析性能比较有帮助,最后介绍现在中国技术团队在开发的一个在线性能分析的平台,也是简单的介绍一下。
下面介绍一下Project Review常见问题,首先我们一般开始检查这个项目的资源管理这方面的设置,大家知道要检查一下资源导入有没有问题,这里我总结了一下,其实我们很多项目在资源导入方面都会遇到一些问题。
首先,是一个我们做这个模型导入要使用FBX文件,我们见到很多项目它的模型导入会把Read/Write Enable打开,这里强调一下,这个设置打开一下会导致内存翻倍。
模型导入有三个选项卡,其中一个是动画相关的选项卡,我们默认不是None,即使FBX里面没有动画数据的话,也会默认添加一个Animator的组件,会增加了内存的占用,建议大家检查一下导入设置。
对于音频设置方面,我们建议ios使用mp3,安卓采用vorbis。动画方面我们遇到很多项目动画资源占用过多的内存,一方面我们可以设置动画的压缩,其实可能很多开发者都知道,除了动画压缩之外,还有一个方式就是你要检查一下原始动画制作的时候是按照什么帧率制作出来的。
然后还有音频的一个采用率,一般采用率 20k就够了。音频文件还要考虑是单声道还是双声道,一般情况下用单声道效果是足够的,我们把它压缩成单声道也可以减少内存的占用。
然后对音频的加载情况,我们建议对这些小的音频文件采用Decompress On Load这种模式,因为对小的音频文件的话,你在加载的时候解压缩一次,这样播放的时候不需要重新解压缩,如果每次解压缩会导致手机发烫、续航减少等等问题。
还有经常遇到的问题,我们FBX导入的时候,如果不使用一些Normalmap等特性,你如果开了Normal Tangent导入也都是浪费了内存空间,我们一般都是在项目开始初期决定用不用Normal Map,如果不用的话以后可以把这个关闭掉。
资源管理方面,有客户说通常游戏里面跑到一段时间发生卡顿,我们调查发现是做了Shader编译,我们引擎提供一个功能是Shader.WarmupAllShaders,推荐的使用方式是游戏场景加载完之后,可以调用这个API,把你场景当中引用的Shader帮你预先编译一下,这样游戏过程当中再使用的时候就不会再去调用编译的操作,这样就避免你游戏过程当中产生Shader编译导致的卡顿。
现在Unity官方不再推荐大家使用Resources文件夹,我们未来可能把这个功能关闭掉也是有可能的,因为你把资源放在这里面的话,它是有几个缺点的,第一个缺点你游戏启动的时候,比如说我们手机上面启动这个游戏,它第一步会把Resources文件夹内的文件构建一个索引,这样你后面再动态加载资源的时候,他可以在这里面查找这个文件,这样做导致游戏启动比较耗时,会发现启动黑屏的时间很长,这样对玩家来说这样的体验不太好。
另外,构建索引会占用你更多系统的内存资源。所以说我们建议以后大家不要使用Resources文件夹。
Memory的问题、因为Unity使用C#语言托管了内存的释放,导致开发者不能选择在什么时间去释放内存。如果你的场景非常复杂的话,它需要遍历场景中的所有对象,C#的GC操作会非常耗时。很多游戏里面你玩的过程当中发现游戏卡顿都是内存GC导致的卡顿,关键的一点是游戏过程当中,尤其是每帧的操作的函数里面,尽量不要在堆栈分配内存。
首先,OnGUI是Unity老的UI系统,现在不建议使用OnGUI。另外就是第三方的插件NGUI,也是有它的不足。因为它使用C#开发,会导致堆栈的内存分配,运行时会导致内存的操作。
另外,我们还比较常见的一个问题就是现在手机游戏对画面要求越来越高了,过去两年前很少见到手机游戏用后期特效,现在很多游戏把后期特效打开,后期特效其实有多个问题,首先它的GPU消耗比较高,另外一个消耗是会导致你的内存消耗非常大,因为每个特效都有可能分配你一个全屏幕大小的一个RenderTexture。而RenderTexture因为要用来实时渲染,所以是不能压缩,不像普通的游戏纹理可以使用ETC或者PVRTC格式压缩。所以它对内存的占用非常高,我们经常看到有的游戏后期特效分配了几十兆甚至更高的内存。
另外,我们发现过很多次正常不应该出现的情况,就是有些不需要Alpha通道的纹理在导入时保留了Alpha通道。我们建议大家都检查一下,把这些不必要的Alpha通道都关闭掉。
下面讲一些ProjectReview常用性能分析工具、我们过去最常用还是Unity Profiler、Unity Memory Profiler、Xcode Instrument。
UnityProfiler有一个功能可以把性能分析数据保存,很多开发者并不熟悉。有的时候你发现一个不方便的地方,某个版本测了一个数据,过两天更新版本再测数据想做对比,上一个版本数据找不到,对比也不好对比,比较麻烦。有这样一个功能,我相信还是有很多开发者没有用过。运行的过程中把性能分析数据记录下来保存成一个文件,想看过去版本性能数据的时候,可以再把这个文件重新加载到Profiler窗口里面,可以从这个窗口里面看过去记录下来的分析数据。
然后这是我们5.3提供的一个内存性能分析工具,主要特点就是图形化的检查哪一部分内存占用比较大,我们去年Unity介绍过,今年还是给大家介绍一下,图形化可以一眼看到哪些资源占用内存最多,我首先优化占用内存最多的资源,如果你去优化一个几十K的资源意义会更小一些。
下面介绍很多开发者问的Profiler的一些选项,也是简单给大家介绍一下。Overhead其实4.x就有了,这是Profiler统计不到的时间都会扔到这里面。Unaccounted是5.x新出现的,和Overhead类似。正常情况下这项不会太高,如果发现有很高的情况有可能是引擎的Bug,如果可以把你的场景作为Bug提交给我们官方是最好的。
你的场景里面越复杂,有越多的对象、越多的资源都会导致这两项变多,最直接的优化方式就是把你的场景变得更简单,让它的对象更少。
我们还有几个客户反映过游戏里面有一个选项OnTransformChanged比较多,这主要是UI的消耗,一般UI层级越浅消耗越小,建议UI层级尽量变得少一点。
另外我们在5.3有一个OnTransformChanged的Bug,这是引擎开发过程当中出现的一个失误,我们在5.5去修掉这个Bug,如果你发现你的游戏里面这项比较高,而且用的5.3的话,建议你把引擎升到5.5,这一块会有比较大的优化。
还有开发者问过String.memcpy是什么。Unity里的Struct的赋值是通过String.memcpy实现的。优化可以考虑把每个变量单独赋值,而不是使用Struct的整体赋值,它的性能有可能提升,建议测试对比一下性能有没有变化,再选择使用哪一种方式。
还有有开发者问过PutGeometryJobFence耗时比较多,对网格体顶点进行操作,这种操作就会产生这个消耗,一般是因为使用了很多粒子系统,LineRenderer或者Trail。
我们还有比较常用的是苹果的Instrument,这个工具比较大的优势是可以看到引擎底层函数的消耗,对你分析性能的原因有所帮助,这些工具我们在明天有一场演讲详细介绍,这里不再详细讲,Allocation也是苹果里面自带的一个功能,还有Capture GPU Frame也会在明天的演讲内讲。
安卓上面没有太多好用的工具,相对苹果来讲功能少太多,这里不详细介绍。
这是我们中国区的技术支持团队正在开发的性能测试平台,这个平台现在只有一个代号,正式名称还没有定下来,明天国内技术专场最后一场我的同事会介绍这个平台开发的进度。
经常会有开发者问我哪一个版本的Unity Bug最少,这个问题很难回答,但是我可以给大家一个建议,你怎么去选择适合你的版本。
首先,介绍一下我们Unity版本现在是什么策略发布的,目前我们Unity同时维护三个大版本,我们发布了5.6之后,我们会支持5.4、5.5、5.6版本的维护。如果大家选引擎版本的话,尽量还是选择仍然在维护的版本,不要现在开一个项目再去用5.3。如果你的项目刚立项的话建议选择比较新的版本。如果马上就要上线了,因为5.6刚出来,也不会建议你用5.6的最新版本,因为刚出来的可能Bug多一点,可能到5.6.1或者5.6.2Bug会少一些,如果你的项目刚开始做5.6没有问题,我们大部分客户现在5.5比较多。
然后,还有我们小版本的更新策略,假如我们现在是5.5.1f1,后面如果修Bug的话就会到P1-P2-P3-P4,5.5.1p4之后会是5.5.2f1。其实从5.5.1p4到5.5.2f1同p1到p2没有区别,都是在修Bug,很多开发者看到小版本号增加了就非常紧张,其实小版本增加版本号的话,都是在修Bug,不会增加新的功能,这是我们小版本的一个发布策略。另外我们的版本号只会增加不会减少,也不会停在某一个版本发两个安装包出来,都是不会的。
另外游戏开发中不可避免有引擎升级的可能性,我们有一次帮客户从5.3升级到5.5的案例。这次升级里面,我们发现这个升级里面,Unity 5.5.0打包Assetbundle速度变慢,确实是引擎出的一个Bug,短时间没有那么快修复,日本的团队提供了一个工具在一定的时间内修复,这是一个链接,开源的工具。
还发现关于Lua脚本提示Light.lightmappingMode文件丢失,不认识这个参数,这个问题确实挺奇怪,大家注意一下。Light是在UnityEngine命名空间的,但是Light.lightmapsMode是在UnityEditor命名空间的,不允许在运行时设置这个参数。
另外还发现编译时提示文件丢失,如system.data.dll,因为Unity在5.5升级了C#的编译器,编译检查会比过去更严格。你可以检查一下,重新拷贝这个文件,或者更新一下这个dll文件。
5.5提供新的安卓打包系统Gradle,我们这次升级当中发现了异常,unityexception:unknown project type。通过设置成ADT方式解决这个问题。
Bug处理方面,我们开发者可以提供Bug到我们的QA团队,他们会及时检查你的Bug,安排研发人员进行修复。接下来的讲座会给大家介绍怎么去提交Bug,以及需要注意的各种事项,这里不再去介绍了。
最后,就给大家再介绍几个常见的问题。很多开发者过去给我们提过这个问题,发现Android Assetbundle内存问题,安卓上面的内存消耗比较大,我们在5.6把这个问题现在已经解决掉了,下面Assetbundle只有32k的内存分配,下一个5.4和5.5的Patch版本也会修复这个问题;
另外,Unity5.5中Particle System内存占用变高,5.3只占了10kb,5.5占了30kb;
还有的问题是如果Assetbundle内的Shader使用Shader Feature,我们提供一个功能叫Shader VariantCollection的东西,来解决shader加载特定变体的问题。
还有一个问题,从Assetbundle加载lightmap,还原renderer的LightmapScaleOffset对static batch的物体失效。目前的解决方法是不使用默认的静态合批,而是在还原LightmapScaleOffet之后,使用CombineMesh API来做静态合批。
还有很多项目遇到的构建工程太慢,我们遇到一个项目工程构建可能需要四个小时,我们可以用Cache Server加快资源导入的过程。
最后一个问题不是非常常见,但是如果你想截图提高分辨率的话,它可以提供4倍、8倍分辨率的截图。