MMO游戏优化经验分享沙龙总结

如题所述

昨天去上海参加了UWA公司的张鑫和张强进行了一场关于MMO游戏开发和性能优化的沙龙,活动链接为: UWA优化日上海站|传统MMO手游性能该如何突围? 。虽然第二场场景分块加载部分的内容没有预期中对目前的项目那么有帮助,再加上最后因为赶火车没有听完Q&A的环节就离开了(然而还是没有赶上火车,此中悲苦就不提了。。。),有些疑问没有提出来讨论,略有遗憾,但对于我这样一个刚刚接触Unity的新兵来说,收获颇丰。因此这里做一个简单的记录和整理,只包含现场讨论我印象比较深的一些点,与讲座内容的顺序没有直接对应关系,更加详细、条目性的内容可以参考官方放出的正式文档。

张鑫博士介绍了UWA成立这一年多时间内做过的事情,我还是比较赞赏有组织在做这件事情的,可以说是Unity引擎和用户之间除了官网文档和官网技术支持之外的一座桥梁。虽然说他们目前的存在价值和盈利方式依赖于Unity引擎和这样一个生态圈,但是对于程序员来说,它们比单纯的引擎部门接近游戏产品,和做产品的比又更纯粹,没那么功利,介于两者之间。如果有合适的机会我还是挺想做一做这样的事情的,哈哈~

目前来说,能有这样的一群人帮忙提供一些技术上的分享,一些坑可以拿出专门的时间和精力去踩和分析,对于没有引擎组的小团队来说是非常好的事情。

张鑫博士提到他们提供热更新方案,会后单独问了一下还是只支持Android的版本,Lua方案的热更新还没有人力去做。希望后面可以有人力来做一些这方面的踩坑和性能优化工作……

在UI系统的优化中,着重提到了Mesh重建的过程,这通常是一个消耗最大的部分,因此也是优化需要关注的重点。在NGUI中,这一过程发生在Panel的LateUpdate函数中——由于NGUI是插件的形式,因此这一过程是在C#中的,每次需要改变渲染网格时都会销毁内存中的mesh进行重建操作。而对于UGUI来说,这一过程是在Cavas的BuildBatch中进行的,已经被封装成了Native的实现,因此在UGUI中这部分 没有额外的堆内存分配 ,这也是UWA官网把UGUI在运行时分配的堆内存大小标准定义为小于2M,而NGUI的建议标准是小于20M的核心原因。

那么,如何降低UI系统中Mesh重建的次数呢?主要从以下两点出发:

上述两点分别对应两个优化思路:

针对第一点,除了不要进行不必要的ui修改操作之外, 对于需要频繁切换的复杂界面 ,张鑫博士给出的建议是:

一个使用案例是背包界面,有大量的item,创建过程消耗也会很大,如果内存允许的话,使用上述方法会有最小的性能开销。

而尽量减少Mesh重建影响的范围则对应一个基本原则—— 动静分离 ,即把不需要动态改变和需要频繁地动态改变的组件分离出来。按照上述的第二点,可以使用canvas进行 动静分离 。就是说比如某个组件下面挂的东西是一个会动态变化的部分,那就把它独立成一个canvas。比如仍然以背包界面为例,滑动内容会导致界面的变化,在滑动过程中每帧都会有Mesh的重建操作。把滚动的部分做成单独的Canvas,这样背景图片和标题等部分就不会被每帧重建了。

这里需要着重注意的是一些会频繁改变的动态部分,比较容易遗忘,比如聊天中的 动态表情,角色坐标信息 的显示等部分,在开发过程中需要着重注意。

之前有讨论过 动静分离 的概念,但是进行分离的基本规则和原理并不是很清楚,张鑫博士的沙龙从性能分析的具体数据出发,结合具体函数的作用,讲解得清晰透彻。
另外有几点关于ui优化的笔记:

UWA做了一个血条性能分析的Demo,也是和UI有关。

通常MMO游戏中血条会比较多,比如一些PVP或者PVE玩法中,血条会有几十个甚至上百个,他们会随着怪物的死亡等消失,又会随着新的怪物产生而重新出现。这里需要注意的点有如下几个:

多线程渲染是我在网易的时候跟过的一个大坑。。。当然不是我做的开发,而是我们项目比较早在使用引擎组做的这一功能,从集成过程到做兼容性测试遇到过很多问题,比如某些设备上莫名其妙的Crash。

张鑫博士说他们从他们的经验来看,Unity 5.3版本之后多线程渲染的功能已经是一个比较稳定的版本了,现在已经有正在运营的项目在开启多线程渲染。因此整体上还是可以比较放心地开启的。多线程渲染对于PostEffect的提升效果很大,他们做了一个测试可以让CPU消耗从平均20ms降低到平均2ms,也有项目开始之后出现顿卡。

与之前了解的一样,开启多线程渲染之后的性能提升效果根本上和是CPU瓶颈还是GPU瓶颈有关,不同设备效果不同,不同游戏的瓶颈也不同,因此要各个项目自己测试来看,因此UWA官方的说法是——

这部分提到如果在观察Profile面板时发现WaitingForJob很高,就说明CPU在等子线程,就已经有性能问题了,当出现PutGeometryJobFence的时候,性能问题就已经很严重了。

MMO开发中角色阴影已经成为了一个标配,UWA经过测试,Unity官方的Build-in ShadowMap的性能还是最好的,推荐使用,只是效果相对差,而且在Mobile设备上无法支持原生的软影(存疑,需要自己测试一下效果)。

而Projector的实现方式比较适合只有一个角色需要阴影的情况,推荐了两款插件:

阴影这块是我们项目目前要研究的重点内容之一,我们在考虑全部动态阴影的方案来部分替代烘焙的LightMap。这部分市面上的产品只观察到韩国的两款Unreal的手游这么来做,之前在网易内部使用Forward Lighting一直都是烘焙的方案。这块如果有朋友了解什么信息还希望不吝赐教~

这是比较有意思的一块内容,之前的思路一直都是大部分情况下统一使用异步加载,只有在明确知道资源非常小,而且不重要的模块使用同步加载的方案,比如一个只有几个面的dummy model之类的。

UWA给出的建议是:在Loading界面中,如果不需要表现平滑的加载进度和加载界面的话,可以使用同步加载,其他的过程中使用异步加载。原因是——

如果觉得加载时间过长,而对于加载过程中的玩家体验不需要过多关注的项目可以参考这一思路。这的确是我之前的经验所没有包含的部分。

另外,在Unity中,对于异步加载来说,也可能会造成顿卡,因为不是所有的过程都是异步的。IO部分可以做到完全异步,但是内存中的初始化的部分过程可能仍然是同步的,比如一张1024 1024大小的贴图异步加载,通常设备上都会可以感受到卡顿,因此建议 大于这个尺寸的贴图统一进行预加载 *。

与此相关的还有一个Unity的小知识。Unity默认每帧给2ms的时间让CPU拷贝内存东西到GPU中,比如贴图、网格顶点等,默认的Buffer是4M大小,因此这里也会影响资源加载到最终渲染到屏幕上的时间。这两个参数是可以调整的,具体接口参考官方文档。另外默认4M正好是一张32位的1024 1024大小的贴图大小,如果使用了2048 2048或者更大的贴图格式,这个Buffer会增大为对应的大小,并且不会在缩小回来。因此建议资源中的最大尺寸可以给一个定义,尽量不要出现只有偶尔几张贴图使用非常大的尺寸的情况。

除了常规的降低骨骼数量和动画曲线数量之外,Unity 5.2之后提供了一个culling Group的功能,用在模型位置一直绑定一个球的方式做碰撞体来优化判定,不在视锥范围的的物体不进行Animator的Update。这一功能主要针对脚本逻辑的Update,Animator没有提供单独的接口根据距离来控制Update频路,一个可行的思路是自己重写其Update接口,然后传入更高的Delta Time来模拟降频的功能。不过以我之前用Havok的降频功能来做性能对比的话,除非角色数量非常高,否则这部分骨骼骨骼的更新的优化空间不是非常大,不过Unity这块具体的数据要进行测试才知道。

Animator中有一个Optimize Game Objets的选项,可以降低Update的消耗,UWA建议使用。这是因为默认情况下每根骨骼都是一个GameObject,每帧骨骼更新之后会需要修改它们的Transform。

对于Animator的Active和Deactive的操作有很大的性能消耗,这在之前斗鱼上的直播中已经提到过了,这里还是像ui一样,建议将角色移出视窗之外的方式来进行缓存,或者只把组件Active和Deactive,来提升性能。

除了上述的一些问题之外,还有一些比较了零碎的笔记,不进行赘述,只记录如下:

这一部分是张强同学做的讲座,基于地形的方式实现了的大世界动态加载功能。其实这部分本来是我期望去听和讨论的部分,以为我们项目正好在进行这块的技术预研,但是我们不是使用地形,而是基于静态Mesh,另外视角我们更倾向于平视而非2.5D,因此这部分对于我们的帮助没有想象中的大。

我个人觉得这部分的一个问题是整个工程是基于一个Demo性质的实现,而非正式的项目,因为时间关系没有在后面进行深入的交流,因此也不清楚目前的实现是否在正式的项目中应用了。一些应用方面的疑问其实讲座正文中没有讲到:

这部分可以直接参考官方给出的PPT,我做的笔记不太多,这里只放了一些没有来及提出的问题,幸好加了两位主持人的微信,回头整理好问题再一并请教,有答复了再修改本文。

这次上海之行,一天时间往返上海杭州,只为了这两场讲座。从收获来说,虽然和预期稍有不同,但是还是很值得的。感谢张鑫博士和张强同学两位主持人的分享,你们辛苦啦 也感谢UWA公司组织这样免费的技术沙龙,祝愿贵公司越来越好 ~

2016年11月26日于杭州家中

温馨提示:答案为网友推荐,仅供参考