原文地址

这是侑虎科技的文章,感谢作者贾伟昊供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群465082844)

作者个人主页:https://zhuanlan.zhihu.com/p/36930662,同时,作者也是U Sparkle活动参与者哦,UWA欢迎更多开发朋友加入U Sparkle开发者计划,这个舞台有你更精彩!

四月份的博客也欠下了,大部分业余的时间花在准备UWA DAY 2018的分享上面。当时也说了,做这次分享也算实现了我去年的一个“小愿望”,借这个机会认识了不少做技术的朋友。回到杭州之后,也有不少人跟我要PPT,讨论一些分享中的细节。在准备分享的时候,因为时间关系,也将一些计划扩展开的内容删除掉了。所以这次想再根据准备时候的逐字稿整理一篇博客,以作记录,也为没有参加UWA DAY 2018的朋友提供参考。

所以这篇博客的主题还是以这次分享的核心内容为主线,顺便把PPT的内容也提供出来(以引用块或者(补)的方式标注,以方便听过分享的朋友阅读)。

题目和提纲

这次分享的题目是《Connecting The Dots——基于团队的持续优化之道》。优化是一件琐碎而又繁复的事情,它通常是一个又一个的点,而我们如果要让一个比如说30人甚至50人的大型团队,花1到2年的时间去开发一款大型的手游项目,不但需要了解和掌握这些优化的细节,而且要借助团队的力量在整个游戏开发的生命周期过程中不断地进行持续优化,才能够让优化效果可以保持下去。

162241thcj1uq7nxqm77nc.png
在聊具体的分享内容之前,我想先抛出这样一个问题——在优化这样的过程中,程序应该承担一个什么样的角色?

162242swvypj8ntb4hojh4.png
这也是和我刚才所想要聊的持续优化关联性非常大的问题。在优化过程中,程序可能有两种角色,一种是像救火员这样的角色,哪里冒火了,就去扑灭它。我自己也有过作为救火员去做优化的经历。另外一种工作方式是像园丁一样,可能不需要特别紧急地在最后关头才处理那些性能问题,而是从项目的初期就开始规划整个项目的性能指标,然后让整个团队可以按照指标的要求合理地产出美术资源、编写代码,从而让整个产品一直处于一个比较健康的状态。

救火员的职责很有挑战性,同时也比较容易做出成就感,比如我也有过用1到2周时间让游戏的性能有非常大提升的经历。而园丁在做的事情可能看上去比较普通,都是些日常且琐碎的事情。在游戏开发中,这两种角色并不冲突,而是同时存在的。但是在我的理解里,对于性能更友好的状态,是让团队里的成员都在以一个园丁的角色在工作,从根本上来保持游戏的性能一直处于一个较好的状态。因为——每一个神级优化的背后,都隐藏着一个2B的bug!

那这次分享我就想从这样三个方面来聊一下我所理解的以“园丁”的角色来让团队进行继续优化的方式。

162244jxj2ij7wo93dyxxw.png
首先是美术资源的优化,美术资源是一个会对客户端运行效率产生非常重要影响元素之一,我想和大家聊一下,怎么样让我们团队可以在美术资源产出方面一直保持一个比较好的状态。然后我想回归到程序的本职工作,从一个更加宏观的角度来讨论一下程序代码的部分要怎么样去做一些优化,对于代码质量和一些底层模块的设计,如何去做一些提前的思考和设计。第三部分,团队开发效率的优化,这块可能看上去跟性能优化的题主没有直接的关系,但是在我看来优化不仅仅是游戏运行效率优化,而且应该包括整个团队开发效率的优化,这也是在项目开发过程中非常重要的部分。

1.美术资源优化

首先来看一下美术资源优化的部分。

162245qhlyp9091ploypos.png
大家在日常开发中可以感受到,对于美术资源部分,美术和程序,尤其是要进行性能优化的程序,他们的关注点会有不同。美术更多的是关注美术效果是不是足够的好,而程序可能更多的关注美术资源在设备上的运行效率是否可以达到目标帧率,这其中就有一些目标导向上的冲突。我认为,解决这一冲突的一个非常重要的手段是尽早来建立合理的美术资源制作规范。

162246du66yef41y47fyuo.png
这其实是一个美术资源制作的过程,首先通过在立项时制作Demo来确定适合的美术资源规范,然后通过给美术灌输效率意识、提供辅助工具让美术在制作资源的过程中可以严格按照规范进行,最后是要借助QA的力量对产出的资源进行检查,确保达标。

1.1 规范制定

为什么制定美术规范这么重要呢?我想借自己之前的一个项目中的真实经历来聊一下。

162247suqqq46nwhh0q700.png
《无尽战区·觉醒》这款手游是我作为主程带领团队开发的第一款手游项目。当这个项目进行到中期的时候,收包了一批场景的资源。在使用这些资源的时候发现它们的运行效率明显偏低,Profile发现面数和DrawCall都超标了。面数很简单,使用减面工具进行减面即可,DrawCall也使用类似Unity的Static Batching的方式进行优化,但是结果发现一些场景的DrawCall只能从400减少到300多,并不能达到预期。仔细检查发现很多模型无法合并的原因是使用了端游常用的一种贴图制作方法——四方连续的贴图。这种方式虽然可以使用很小的贴图尺寸通过tiling制作出精细的效果,但是对于DrawCall敏感的手游来说并不合适。最终项目又请了好几个外派美术进行资源的整合和制作,导致多花费了几个周时间和几十万的美术成本。虽然对于大公司来说几十万的美术成本不算什么,但是我依然觉得这是我作为一个主程的失职——因为没有提前和美术沟通好制作方法,导致了这样的问题发生。所以在出来创业的项目中,在项目最初期Demo制作完毕之后,客户端团队就和美术一起制作了非常详细的美术资源制作规范。

制定规范的步骤大致可以整理为如下的几个部分:

162248hdna5d6y0a8zza8j.png
在制定美术规范的第一步是要进行游戏信息的收集,因为不同的游戏类型以及镜头视角会对美术资源的制作产生非常大的影响,比如2.5D和3D自由视角的游戏是有不同的制作和优化方式。

在收集了足够的信息之后,需要和美术敲定一些大的技术方向,比如线性空间、HDR和动态光影等。线性空间是团队应当提前关注的一个点,我个人的观点是在写实的游戏风格中,能上线性空间还是尽量使用线性空间,对于美术效果的提升还是很有帮助的。在正确的基础上,才更容易出正确的效果。Unity目前的版本和OpenGL ES 3.0的普及率,个人观点是完全可以在移动平台上使用线性空间的。当然这也要考虑具体项目的内容以及开发团队成员的能力和经验等因素。HDR的开关在Unity中还是比较简单的,但在性能方面对于带宽的影响比较大,收益也不小,建议追求效果的团队提虑。动态光影是我们研发团队的美术特别想追求的一个效果,但是因为我们项目今年要上线,而且要考虑低配的效果,所以程序一直卡着不让场景使用全实时的动态阴影,而是尽量使用烘焙的方案。

确定目标机型就不多说了,考虑主流的高中低三档,建议提前购买一些设备方便后续的性能测试。我对于这三档的基本分类大致如下(这个也可以参考UWA测试中的机型选择):

 

 

高档:大部分iOS设备,主流的安卓旗舰设备;

中档:少部分希望支持的iOS设备,比如目前的iPhone 5s、6/6s,ipad mini等,1-3年前的旗舰以及1-2年的1500元左右的安卓设备;

低档:1-3年前的千元机。

162249qom99cb9d93hoa9l.png
接下来是要针对面数和DrawCall这两个核心点,对整体的标准进行定义,并将这些标准分配到场景、角色、特效、UI等资源分类上。因为这些不同类型的资源是由不同的美术同学产出的,他们之间通常不会去沟通各自的性能消耗,因此需要针对每部分进行规则的细化。

162250h6sg7y384ut768ut.png
场景部分强调一下贴图“像素密度”的概念。在制作场景的时候需要提前定义贴图使用的像素密度,否则会导致贴图精度过高或者不够等问题。所谓的“像素密度”是指在正常的游戏视角下,一个一立方米的Cube应当使用多少尺寸像素的贴图。这个在场景制作的初期应当定义好,美术才好去使用正确的贴图尺寸,否则到后期优化可能发现大量超标的贴图在使用,如果此时已经进行了贴图的合并,美术修改的工作量会非常大。

162251bkmguk9iha9i9zu9.png
角色部分的规范需要把面数和DrawCall的标准细化到每个角色中,这时候需要和策划沟通期望的同屏显示人数,根据不同的游戏类型会有很大的差异。比如《崩坏3》不会同时有很多战斗单元,因此可以给每个角色非常高的精度,而像《御龙在天》这样的国战游戏,追求百人同屏的效果,对于每个角色的消耗限制就会比较大。

骨骼数量的部分最好在前期和美术沟通好,比如手指骨骼的减少和合并,脚部骨骼的简化,来减少CS骨骼的数量,给飘带等Bone骨骼留出足够的空间。因此美术规范制定的过程并不是单纯的程序给美术添加制作限制,而是一个和美术一起来讨论如何在有限的资源下制作出更好效果的过程。

162253zluv7kt7whmimh7c.png
162254qte2eyl6pmfyloon.png
UI制作规范是我们初期没有特别关注的部分,也因此踩了一些坑:

UI组件数量较多导致加载顿卡。我们有些复杂界面有上千个GameObject,几百个UI组件,这是非常恐怖的。我们测试发现UI的Prefab加载的时间消耗在Unity 5.5.6上和UI组件的数量几乎成线性关系。这里补充一张我们测试的GameObject数量和加载时长的测试结果图(横轴是GameObject个数,纵轴是单纯的Prefab加载的时间消耗,单位秒,测试环境:小米Max2):

162257bpvcnc1nvvnvzqcn.png
因此建议其他团队提虑UI部分的异步加载和分块加载。(或者升级引擎到5.6.5+或者2017.3+,对于Prefab的加载速度有了很大的提升)

UI中的粒子特效建议提虑异步加载,我们最初直接放在了UI的Prefab中,不但因为Unity不支持Prefab的嵌套导致维护麻烦,而且因为每一个ParticleSystem的初始化都占用一个几乎固定的时长(我们自己测试在PC上也大约有3ms左右),导致UI初始化的时候非常卡。使用一个间接的引用,就可以比较容易地做到既方便更新又可以异步加载。

162259isoqpzs6o92soi69.png
最后针对标准,要进行真机的压力测试,并且在组内推广,形成大家都认可的美术资源制作规范。

1.2 美术资源制作

在确定好美术资源的制作规范之后,就是需要在美术铺量制作的阶段让美术可以按照规范进行资源的制作,在这个阶段程序需要注意去做的事情我觉得有两点:

 

 

帮助美术建立效率意识;

为美术提供便利的制作和检查工具。

162300mkdrjjk9qpcqq2cd.png
在我们这样的一个初创团队里,没有经验丰富的TA存在,而且有部分美术同学之前来自外包团队,对于游戏运行时的效率意识比较薄弱,因此需要客户端程序同学不断和美术沟通来灌输对于游戏运行效率的关注。通常的做法包括日常的沟通、规范和技术点的分享等。

而在提供便利的工具方面,除了教会美术使用Unity已经提供的那些性能检查工具(Batches和面数查看、Overdraw、Mipmaps、Wireframe等渲染模式)之外,我们也为美术提供了非常多的开发和检查工具。

162301ndicrn391mx7ri43.png
162302wjvo6u5k6cxhnknk.png
从截图中可以看到我们为美术提供了大量的工具,选择几个来着重介绍一下:

1.2.1 场景镜头同步功能

在场景资源制作的时候,需要美术去关注的除了常规的DrawCall之外,还有Overdraw、Mipmap以及面数。Unity已经在Scene View下提供了这三种渲染方式的检查工具,但是在我们的使用中发现,由于游戏运行时镜头规则的复杂和多变,导致美术在Scene View下无法准确判断是否存在资源不合理的情况。因此美术提出希望可以在Game View下查看这些状态。

162303aovoxveuomee611o.png
最初的时候我们也是想在Game View下实现这些不同的渲染方式,并且已经集成了OverDraw的检测方式,基于的也是钱康来建议的Unite2017/OverdrawMonitor。但是后来觉得这种方式会影响美术对于游戏的操作,程序实现起来也要多花一些时间,比如Mipmap的实现效果就不是很满意。后来就想到另外一个思路——在Scene View下来做镜头和Game View下的镜头同步。结果就非常简单,只需要为Game View下的Camera身上添加一个Component就好:

 

 

  1. namespace ThorProfile
  2. {
  3. public class SyncSceneView : MonoBehaviour
  4. {
  5.  
  6. #if UNITY_EDITOR
  7. private SceneView view = null;
  8.  
  9. // Use this for initialization
  10. void Awake()
  11. {
  12. view = SceneView.lastActiveSceneView;
  13. }
  14.  
  15. private void LateUpdate()
  16. {
  17. if (view != null)
  18. {
  19. view.LookAt(transform.position, transform.rotation, 0f);
  20. }
  21. }
  22.  
  23. private void OnDestroy()
  24. {
  25. if (view != null)
  26. {
  27. view.LookAt(transform.position, transform.rotation, 5f);
  28. }
  29. }
  30. #endif
  31. }
  32. }

1.2.2 批量烘焙功能(补)

Unity的烘焙在Unity 5.X的版本速度还是比较低,我们虽然为美术专门购买了CPU强劲的烘焙机,但是比如在制作大世界的时候,因为场景拆分得比较细所以需要一次性连续烘焙多个场景,于是为美术提供了批量烘焙的功能。之前在知乎上也有朋友问过类似问题,代码非常简单,直接贴一下,需要的自取好了:

 

 

  1. [MenuItem(美术工具/烘焙选中场景(同步))]
    • public static void BakeSelectedScenes()
      • {
        • Object[] selectedAsset = Selection.GetFiltered(typeof(SceneAsset), SelectionMode.DeepAssets);
          • foreach (Object obj in selectedAsset)
            • {
              • string scenePath = AssetDatabase.GetAssetPath(obj);
                • Debug.Log(开始烘焙场景: + scenePath);
                  • EditorSceneManager.OpenScene(scenePath);
                    • Lightmapping.Bake();
                      • EditorSceneManager.SaveOpenScenes();
                        •  
                        • //如果有更新Prefab的需求,可以放这里。
                          •  
                          • EditorSceneManager.SaveOpenScenes();
                            • Debug.Log(scenePath + 场景烘焙完成!);
                              • }
                                • }

在我们项目中,对于美术资源的检查主要有三个部分:

 

 

程序检查。程序会根据发现的性能问题进行针对性的检查,比如会使用Profile、FrameDebug工具等进行问题的排查。

我们也是UWA产品的深度用户,购买了专业会员,几乎每个月都会提交一份安卓版本的包让UWA团队帮忙进行在线的性能诊断与优化,频繁的优化周期内可能会每周提交一份包。去年的年底也邀请UWA团队来公司针对我们项目进行了深度优化,发现和解决了不少美术资源的问题。

QA每周的性能测试。每周QA团队会在周版本之后,生成《性能测试报告》,以邮件的方式发送到全公司所有人的邮箱里。

这里以我们的《性能测试报告》为例来说一下QA团队进行性能监测的内容。

1.3.1 包体大小监控

我们经历过在测试上线之前要进行包体大小优化的情况,因此将包体大小的监控放到了每周的性能测试报告里。

162306l1yppg81lvc8yvyc.png
我们会统计整体包体大小、资源占用大小、按照场景、UI、角色、特效等分类之后统计各自的大小,以及如果包体大小有变动,主要原因是什么。这部分使用的工具主要是基于打包时候产生的中间文件来统计分析。如下图所示,左侧是按照文件夹分类的列表,右侧是选中的节点下的所有文件,可以进行排序、关键字过滤,以及多选统计等操作。

162308ynonuwkm4hkoaaou.png
在进行资源大小统计和分析方面,我们也开发了一套在Unity内的根据资源的引用关系进行分析的工具,统计对象为所有要打包出去的资源,可以查看资源之间的引用关系、被引用关系、资源消耗统计(粒子系统数量、GameObject数量等)。借助这个工具可以方便地进行一些不再需要的资源筛查等分析工作。

162308pftteattq3zztnet.png
1.3.2 游戏帧率统计

另外一块需要持续关注的是游戏在设备上的运行帧率。

162309menceda2dr9xug2v.png
我们会分别在高配和低配机器上对战斗外、不同的战斗类型进行帧率的统计,并和之前的记录进行对比。

1.3.3 具体资源的检查

在具体资源的检查方面,由程序提供尽量简便的测试和统计工具,由QA进行自动化的检测,主要包括场景资源检查、场景合法性检查、技能特效检查、UWA GOT性能数据等部分。

162311nmyr2wrzyrzywmf7.png
场景部分主要是统计Batch和面数。我们制作了一个工具,按照填写的检查点在默认镜头下统计四个方向的数据,同时截图记录。这个工具也提供了跳转到指定坐标直接查看检查的功能。

162312pz2usnulxr7nuuuc.png
前文已经介绍了场景的合法性的部分,这里是由QA每周进行一次合法性检查,对于不合法的场景反馈给美术进行修改。

162313sjf88jcge0zqfq4f.png
特效检查主要集中在Drawcall、描述以及粒子数量这几个比较常规的方面,同样会列出不合格的特效让美术修改。

162314b0ex0vkgee4gvl0u.png
162315hzdzpma5dsbgs5ad.png
对于特效的Overdraw的统计,我们是针对技能进行的,因为技能释放过程中会有镜头的轨迹,因此这种方式更加合理。工具的功能是逐个释放技能,然后记录技能释放过程中最大的那帧Overdraw的数据和截图,方便美术排查。

162316v0444j144rol83qo.png
我们也让QA团队在时间充裕的情况下使用UWA的GOT工具进行性能数据的记录,方便程序进行对比和检查。对于内存的统计数据也会从Overview测试中获取。

PPT截图的右下角是工具的制作者在我们组内的外号。标注在这里也说想说明这些工具的开发工作是整个团队一起来分工协作完成的,而不仅仅是分享者的功劳。

1.4 小结

第一部分的最后,我们做一下小结。经过规范制定、规范执行以及资源检查这些步骤,美术资源的优化就形成了一个闭环,这个闭环中的各个环节是由不同职位的同事协作来完成的,程序在其中起到了穿针引线的作用。在规范制定阶段,是由程序和美术主导,同时注意从策划和运营等处收集游戏设计的信息;在美术制作阶段的主角是美术,程序则为美术提供更好用的检查工具辅助美术自查;资源检查阶段由QA主导,程序负责提供便利的自动化检查工具,美术则需要对发现的问题进行修正,同时这个阶段的检查结果也可能反馈到规范制定的内容上,对一些规范细节可能会进行修正和调整。

162317pff1f15vgpei15f1.png
未完待续……

关于UWA:

由侑虎科技开发的游戏/VR应用性能优化平台,目前提供 1)性能诊断与优化 2)资源检测与分析 3)UWA GOT 三大工具,帮助开发者在短时间内大幅度提升性能表现;同时其搭建的知识分享的博客和答疑解惑的互动平台使广大开发者收益。

锐亚教育

锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛