搜索 Unity

幕后揭密:Unity工作流的速度提升

2021年7月5日 类别 Engine & platform | 20 分 阅读
Black gradient background with a overlay of white graph lines and the words "2021.2 Feature Preview"
Black gradient background with a overlay of white graph lines and the words "2021.2 Feature Preview"
分享

Is this article helpful for you?

Thank you for your feedback!

快速的原型制作是每个创意工作的核心之一。在这篇博文中,我们将介绍Unity在优化编辑器核心功能上所作的努力。这些改进旨在帮助用户在开发的每个环节实现快速迭代,涵盖了从资源导入到游戏的构建与部署等各个方面。

当游戏项目逐渐步入正轨时,游戏原型开始投产、内容逐渐丰富,编辑器性能是提高团队生产力的一个重要要素。因此,编辑器性能和迭代速度将是2021年的开发重点之一,相关详情可在路线图介绍中了解。

资源的导入、创建、打包、分发与加载

Unity编辑器在处理大多数内容时,需要先将源文件转换为适用于游戏或实时应用的格式。在资源导入后,引擎会将这些转换后的文件与相关数据储存在Asset Database(资源数据库)中。这时,如果某个文件修改了磁盘路径,Unity会刷新这个数据库;如果脚本经过了修改,则引擎会重新加载整个C#域。在项目部署到目标平台时,Unity的构建系统将其打包成二进制文件,用于在目标平台上分发和运行。

Asset workflow

在所有这些步骤中,Asset Database是实现可靠、高性能和可扩展导入流程的核心技术。

但除次之外,编辑器迭代时间还受许多部分的影响,包括导入程序、压缩工具、编辑器核心代码及构建管线。在本篇博文中,我将分享自己从相关工作人员处了解到的细节,帮助你充分利用起Unity 2021.2。

编辑器启动时间优化

鉴于Asset Database占用了主要的项目启动流程,我们希望通过优化数据库的代码来测试其实际影响。Asset Database团队的高级工程师Javier Abud和Jonas Drewsen合作使用一个包含90万个资源的测试项目建立了一个基准测试框架,借此提出了一系列启动时间的优化和改进。两人还开发了一套自动化数据记录工具,用于记录数据库对Unity编辑器性能的影响。

"有许多成果目前就在我们手边,但有些时候我们也需要一些发散性思维。我们每周能在测试项目上减少大约15秒的启动时间,这些优化接着会应用到22个真正的项目中进行验证,以此来保证在大项目中卓有成效的优化不会在真正的小型项目中适得其反,”Javier Abud表示。举例来说,团队有效地减少了线程或排序时的内存分配,并推出了项目文件及文件夹并行处理的方法。在Unity 2021.2中,一个包含90万个文本资源的项目其启动时间成功从3分36秒减少到了1分17秒,而小型项目的启动时间平均加快了8.7%。

资源导入

Import Activity(导入活动)窗口

Javier还开发了一个称作“Import Activity Window”的新工具,可显示出资源导入的原因、导入过程的耗时,以及可能作为依赖项被导入的资源。工具详情可在该论坛帖中了解。

模型和纹理处理的速度提升

如果将编辑器的启动流程以饼图表示,我们发现模型和纹理的导入通常会占有最大的比重。这里,我们来尝试导入《Book of the Dead: Environment(死者之书)》 项目所有的纹理、模型、预制件和场景。

Image displaying BOTD Assets import time (PC platform), in seconds and the comparison between 2020 and 2021

源数据(包括346种纹理、133个模型、214个预制件、6个场景)的大小为2.25GB。时间统计在配备Windows操作系统、AMD ThreadRipper 1950X(16线程)和SSD硬盘的设备上完成上,测试分别比较了Unity 2020.3.10、2021.1.9和2021.2 alpha(a19)。

在默认设置下,2021.2 alpha导入时间仅为114秒(相较2021.1快了1.27倍)。如果再启用四个导入程序形成并行资源导入,导入时间将缩短为77秒。并行资源导入的设置可在Project Settings > Editor > Refresh下找到。

如果再到Build Settings窗口中启用Force Fast Compressor(强制快速压缩)选项来减少迭代时间,所有资产的导入时间将仅为38秒——相比于2021.1版整整快了3.8倍!整个优化不会改变纹理的大小或格式,而是用更少的运算生成了尽可能好的压缩纹理像素。

模型导入

优化团队的Richard Kettlewell自进入2021年周期以来一致专注于加快模型导入速度。“(该领域)有许多问题和相应的方案,但都并不显眼,”他解释说。“举个例子,逐个为每个顶点分配内存在处理大型网格表面时速度会非常缓慢,而部分算法可通过运行一个预处理通道来计算某块网格所需的总内存,然后以块为单位分配内存。此外,很多导入流程都会处理文件的每个表面、顶点、动画或材质。如果能将其拆分为独立的部分再并行导入,导入速度便会有极大的提升。”

"我们还采用了更快的内存分配程序用于给导入时的暂时性内存",他继续说,“这给各个阶段都带来了些许速度提升。我们还要感谢所有在百忙之中分享问题模型给我们的艺术家们,如果没有这些内容,我们就无法进行测试并优化!"

Unity 2021.2现在可以为文件中的多个网格模型同时生成法线、切线和光照贴图UV。在测试中,某文件原先需要花33分钟导入(其中30分钟耗费在生成光照贴图UV上),而在优化后总导入时间可被降低至11分钟,减少66%。包含多个网格模型的文件将受益于此优化,原本缓慢的导入流程将有极大的速度提升。

我们还将其他模型导入流程进行了多线程处理,包括:

  • FBX动画的导入
  • 顶点缓存优化程序的运行
  • 网格三角变化(将多边形转变为三角形)
  • SketchUp顶点处理

纹理导入的优化

Quality of Life团队负责了纹理导入部分的优化,继续推进2021.1周期初期的既定目标。在2021.2中,团队再一次更新了ASTC压缩程序,进一步提速30%,并提高其在不同CPU上的运行稳定性。另外,BC7的压缩速度约为原先的2至3倍。 

Build Settings的Force Fast Compressor(强制快速压缩)选项也是团队的优化举措之一。Aras Pranckevičius解释说:“如果纹理质量并非特别紧要,你可以使用更为精简的压缩流程(‘Force Fast Compressor’),或者设定限制全局的导入纹理大小。” "如果我现在将2GB的纹理导入成安卓ASTC格式,与原先的20分钟相比,整个导入流程可在两分钟内完成,唯一的缺点是画质的损失会稍微多一点。但它仍非常适合快速的迭代。”

Graph displaying the BOTD switch to Android+ASTC, in seconds comparison from 2020.3 to 2021.4

创作优化:更快、更流畅的编辑器操作

编辑器打开大型、扁平层级的场景将快90%以上

场景根目录(即层级视图顶层的GameObjects)通常会按顺序存储为一个相互关联列表,因此其加载和合并会耗费不少性能。此前,场景在打开时编辑器会依次将每个根对象添加到列表中。每一条目会在场景中加载时会被添加到列表中,而每个新GameObject都必须在列表里新建一个条目。但现在,新添加的根对象将作为dynamic_array储存,列表仅在需要时会进行排序并相互关联。由此,编辑器打开测试场景的时间可以减少90%——从17秒减少到仅1.45秒。

Graph displaying the time to open a scene in editor with a graph comparing before optimization and after optimization on a scale of 10000 to 50000

小优化带来大胜利

Performance Optimization团队的是Unity帮助客户与内部大项目优化编辑器使用的主力。随着游戏越来越大,原本几秒钟的等待可能会逐渐发展成一个大问题。 

Peter Hall是Unity 2021.2中性能优化的主要负责人,在他的众多速度优化方案中,其中一个是对大型场景对象拖拽与选取的流程优化。在内部的测试场景中,整个流程花费了78秒,作为优化的基准参考。“在Profiler中的数据记录显示,大部分时间都花在了从GameObjectTreeViewDataSource.RevealItems中调用来的BaseHierarchyProperty::Find上。函数会将层级中的所有父对象写入到根目录下,但对象仅会被逐条写入。如果使用IHierarchyProperty.FindAllAncestors,这段运算的耗时可降低到50毫秒左右,速度可提高约1400倍。”

编辑器内还有其它地方也有了提升,运行大型项目的速度已经变得更快,比如新建材质快了2倍、场景对象全选快了1.6倍、复制/粘贴游戏对象快了50%。

版本构建

在进入测试和优化阶段时,游戏在设备上的迭代速度会变得非常关键。因此,我们投入了大量的时间和精力来全面优化了软件包构建管线。例如,Unity 2021.2的Scriptable Build Pipeline(可编程构建管线)与Build Cache(构建缓存)运行速度有所提升。

优化的一个主要重点在于让运行版构建流程仅打包新添的改动,而非整个项目内容。我们最近就改进了Unity本身的构建方式,并将同样的方法应用到了运行版构建和脚本编译中。由此,Unity 2021.2 Beta测试版现在支持Windows、macOS、Android、Linux和WebGL的增量式版本构建,并支持C#脚本方案的增量式编译。这项改进将在未来逐步推广到剩下的平台上。

"Unity在构建运行版时做了很多事情。首先,我们将所有场景、资源及游戏管理程序序列化为数据文件来创建运行数据。该流程由原生C++代码完成,"脚本团队的Jonas Echterhoff解释说。"当数据创建完成后,我们再调用一个后期处理方法。每个平台都有各自的方法代码。后处理程序因平台而异,但一般都包含二进制运行文件和相关文件的复制与内存分配、IL2CPP代码到原生数据库的编译、以及符合平台要求的数据压缩和打包等。这种后处理逻辑便是新构建系统中新添的内容。" 新系统对每次构建的输入输出及相互间的依赖都有记录,因此只会重新运行必须的构建步骤,并在可能时以多线程完成构建。

IL2CPP速度提升

全新的IL2CPP源码加密功能可生成最少50%的代码。降低构建耗时与可执行文件的体积。由于加密方法稍有不同,新功能可能会轻微影响运行时性能,因此其最适用于减少团队内部的迭代时间。请在该论坛帖中分享新功能对你项目速度的影响。

在2020.3中,IL2CPP便经历过一次大修,使其能够利用多核CPU来生成C++代码,用于运行版的构建。IL2CPP团队的Michael Voorhees表示:“(IL2CPP)代码完成度较高,我们的修改工作也因此受到了诸多限制。我们不得不在库中删除大量的静态字段,然后根据拆分法(divide and conquer)将代码重构。我们还重构了内部API来适应并行和串行编译模式,借此来降低新优化的应用风险。并且,我们还创建了耐用的压力测试场景,再花约一个月进行有效性测试,直到并行编译满足成为默认编译方法的要求。" 多亏了核心硬件使用的提高和优化,IL2CPP编译时间在整个2021.1有了进一步减少。

而在2021.2中,团队着手将编译中最为耗时的步骤——泛型集合的编译并行化。Michael表示: “为了打开新局面,我们用自己的数据模型替代了Cecil。这些改动,外加上许多其它的小优化,使得IL2CPP在2021.2中的编译速度比2021.1快了两倍。”

Graph 2

构建速度有了巨大的改变,特别是对移动端开发者而言。举例来说,最新的2D示例项目《Dragon Crashers》在Unity 2020 LTS中采用的是非增量构建法,如果脚本有了改动,要为ARMv7和ARM64构建将耗时91秒。而在Unity 2021.2中,新的增量构建工具仅花了44秒,不到前者的一半。

AssetBundle的高效加载

Image of a virtual underwater scene with a hand holding a recording camera in the bottom right corner
游戏《深海迷航》总共包含了5199个AssetBundle。

对于移动端开发者来说,动态内容分发的重要性日渐凸显,而这种在运行时归档和加载资源的方法极度依赖AssetBundle。然而,每个并行加载的AssetBundle会占用相对固定的内存成本,根据平台的不同,这个成本可从14k到128k不等。

今年春天,Asset Pipeline团队的Kirsten Pilla和Joseph Scheinberg解决了这个问题。Kirsten说:“我们没有为每个AssetBundle建立专门的缓存,而是建立了一个共享的内存页池。为了在大量使用AssetBundles的商用项目中进行验证,我们与Unity Professional Services的Patrick DeVarney合作,在Unknown Worlds的《深海迷航》中测试了优化。" 在加载1616个AssetBundle时,共享内存页池将最初的215.7MB内存占用降到了12.9MB,减少了94%。 

该团队还推出了一个简单的公共API来管理内存预算(AssetBundle.memoryBudgetKB)。

Diagram with a black background showing how the pooled filecacher system works with assetbundle 1, assetbundle 2, and assetbundle pointing back to the memory cache block pool

未来计划

听说大家最喜欢Unity的一点便是快速的迭代,为了保持住这个优势,我们将密切关注客户和内部项目开发中出现的团队生产力问题,还将制作更好的监测工具用于分析影响迭代的内置及软件包功能。在内部开发期间,我们通过监测迭代时间的关键性能指标,来保证未来引擎版本能更快地更新各种规模的项目。

在资源导入方面,我们将逐步向资源按需加载过渡,即使Unity仅在需要的时候导入资源。我们还将努力推进增量式构建在所有平台上的普及,其中iOS平台是我们下一个目标。

如果你在以上功能领域中有具体的提速需求,可以前来Pipelines and Integrations路线图给我们留下你的宝贵意见。 

Unity 2021.2 Beta测试——用户反馈征集中

请与我们分享你对Unity 2021.2速度优化的体验。所有优化现已登陆Beta测试版,你可以在Beta测试公告中深入了解所有的改进。你也可以加入Unity 2021.2论坛告诉我们你的想法。我们将格外留意模型和纹理导入全新IL2CPP代码编译两个功能领域的反馈。我们在此特别鸣谢traVRsal开发者Robert Wetzold以及其它贡献了参考数据的Alpha测试参与者!

如果你想与我们反馈Unity的总体体验,或想与我们一道塑造引擎的未来,那就来加入Unity Pulse吧。作为全新的用户调研平台与社区,我们将在此积极举办用户调查、意向调查、圆桌会谈、用户访谈和小组讨论,以此作为调动资源力量的参考。

2021年7月5日 类别 Engine & platform | 20 分 阅读

Is this article helpful for you?

Thank you for your feedback!

相关文章