Unity可寻址对象:始终有足够的内存

图片

您带领一个由数名程序员和美术师组成的团队,致力于将精美的PS4 VR游戏移植到Oculus Quest。您有六个月的时间来做。您的第一步是什么?让我们尝试使用Unity可寻址对象。

您了解必须同时解决几个相当困难的任务。对于您而言,有些困难比其他困难,这取决于您在每个领域的经验。如果您选择其中哪一个最剥夺了您的睡眠,那将会是什么?

我想以下几点:大约70%的读者会说,将游戏移植到Quest时最大的问题是CPU / GPU性能。我可以回答:很可能您是对的。提高生产力是VR游戏中最难的领域之一。这种类型的优化需要对产品进行彻底的研究,这需要时间。有时,进一步的优化是不可能的,因此,您通常必须摆脱昂贵的游戏玩法和图形元素。让玩家失望是危险的。

速度,速度,速度... Quest平台在这方面能期待什么?生产率如何?事实是,如果您已经有开发它的经验,那么您就会知道,尽管它具有移动性,但它的功能却出奇的强大。

“来吧,作者,你为什么在说谎?打开第二个浏览器选项卡后,手机开始减速。您如何说移动平台可以提高生产力?”

巨大的区别在于Quest主动冷却系统,该系统为其CPU / GPU提供了其他任何移动平台都无法提供的巨大优势。这是一个强大的风扇,可以吹掉头发上的灰尘,并防止处理器融化在您的脸上。

此外,与标准的Android相比,更专业的OS在渲染虚拟现实(惊喜)方面得到了更好的优化。在过去的几年中,移动硬件已开始迅速赶上固定平台。

但同时,我不会否认以72 fps的频率进行恒定渲染的任务将非常困难,尤其是对于来自强大平台的VR游戏端口而言。当我们谈论Oculus Quest时,您可以想象Snapdragon 835带有屏幕,电池,四个摄像头和一个风扇。

看起来像缺陷的东西实际上可以被视为优势。这个移动平台是铁含量极低的经过充分研究的设备。可以说,有千种已知的技巧可以将CPU和GPU的负载快速降低到可接受的水平。如果您有兴趣,那么可以在我的后续文章中阅读。在本文中,我们将把性能排除在外。

与PS4相比,我们在这个问题上的关注可能是Quest具有一半的硬件特性:RAM容量。即,该卷的RAM从8 GB减少到4 GB。这是一个近似值,因为在这两个平台上,操作系统都不允许完全使用它们,因此您可以跟踪生态系统功能所需的几个子系统。在Quest中,您最多可以使用2.2 GB的RAM。如果更多,那么混乱已经开始。

“但是你所说的混乱是什么意思?” 事实是,对于游戏而言,实现正确的内存管理至关重要。发生这种情况是因为我们有两个限制:

  • 硬内存限制:如果超过一定阈值,则操作系统将终止游戏
  • 软存储限制

显然,我们不希望第一或第二发生在游戏中。您能想象一个在过去两个小时内输掉比赛的球员的愤怒吗?是的,他一定会去应用程序商店,并且不会在那儿说任何令人愉快的事。

当然,保证的2.2 GB RAM的可用性不是很多。通常,对于从一开始就不断监视统计信息的新项目来说,这不是问题,但是对于硬件较弱的端口,这无疑是一个难题。

如果您过去曾处理过类似的端口,您将很快意识到将可用RAM数量减半变得极其困难。这在很大程度上取决于游戏架构准备好进行此类更改的程度,但是在大多数情况下,这只会导致眼泪。

减少内存需求的最流行策略是更改资产的压缩参数,优化脚本,减少着色器变化等。通常,第一个解决方案是更改纹理的导入选项,但如有必要,可以使用网格,动画和声音的压缩。问题在于这种技术通常很复杂,并且有自己的上限

并非所有平台都支持相同的导入参数:为不同的设备开发时,装配管线的成本显着增加,更不用说质量保证,设计图形和编程的复杂性。例如,这是否支持Android ASTC设备,或仅支持ETC2(以及其中的任何一个)?哦,我们仍然需要64位版本,但与此同时,我们希望保留32位版本的播放器。我们需要为游戏中的每个更新创建和测试多少个APK?如果您想简化生活,那么您不应该仅依靠这些技术。

因此,我们需要更深入。当然,我们希望一切都尽可能简单,尤其是在创建端口时。与不移植游戏相比,完全回收游戏以提高性能是一个更糟糕的选择。作为本文主题的一部分,我将展示最重要的优点之一:您将学习如何在短短几个小时内将所需的内存量减少一半

那不是很好吗?

好吧,让我们问我:在您的情况下,这真的可能吗?我会回答:这取决于初始条件,但是根据我的经验,答案是。 Unity可寻址对象可以在这里提供出色的服务。诀窍是什么?您必须投资并掌握流程。但是这样的工作流程将使您赢得当月的雇员称号。

如果您有兴趣,请继续阅读。

在本文中,我们将从传统的资产管理转向基于可寻址对象的资产管理。为了说明这一过程,我们将简化的老式项目移植到Unity可寻址对象的新时代。

您可能会问一个问题:为什么不只显示实际工作的结果?

在一个没有竞争的世界中,我只向您展示我创作的所有材料。但是,在现实世界中,我很可能为此受到惩罚。然后他们会让我入狱。

因此,我提供了帮助:我们将制定一个项目,介绍您明天在下一个项目中将面临的所有困难首先,我们将Unity可寻址对象带入我们推荐的软件包系列

在这篇文章中,我将向您介绍Addressables,以便您可以在几分钟内实现自己的Unity Addressables系统


Unity可寻址对象:为什么需要它们?


应注意这一重要部分。我们的任务是识别优化内存使用并快速实施的简单方法。有多种方法可以执行此操作,但是最强大且同时最简单的方法之一是加载第一个场景并启动分析器。为什么?

由于可以在游戏进行的任何时间识别游戏非优化架构,因此最快的检查方法是对第一个场景进行概要分析。这样做的原因是为了防止万一,经常过度积极地使用脚本,例如包含指向所有资产的链接的单例脚本

换句话说,许多游戏通常都具有无所不能的脚本,脚本创建了指向资产链接的地狱无论当前是否正在使用该组件,该组件都会使每个资产保持不变。

那有多糟?

情况有所不同。如果您的游戏可能受内存限制?那么这是一个非常冒险的决定,因为随着添加资产数量的增加,游戏将无法很好地扩展(例如,考虑未来的DLC)。如果您正在为异构设备(例如,Android)进行开发,那么您将没有单个内存。每个设备都有自己的容量,因此您必须依靠最坏的情况。如果用户突然切换以回复Facebook上的消息,则操作系统可以随时决定终止该应用程序。当他回来时,一个惊喜将等待他-游戏已经关闭。

好玩吗?

绝对不。

使情况复杂化的事实是,如果您以后决定(或有人为您做出决定)将游戏移植到另一个功能较弱的平台上,同时又保持了交叉玩法,那么您只能祝您好运。您绝对不会面对这样的技术问题。

另一方面,是否存在适合传统资产管理的情况?当然是。如果您正在开发统一平台(例如PS4),并且从一开始就了解大多数需求,那么全局对象的优势可能会超过改进的内存管理系统的额外复杂性。

因为您必须承认:如果旧的全局对象适合您,它可以存储我们所需的一切,这是一个简单的解决方案。它将简化代码并预加载所有引用的资产。

尽管如此,对于寻求最大程度利用铁资源的开发人员来说传统的内存管理是不可接受的您正在阅读一篇文章,这意味着您想提高自己的技能。所以现在是时候去做了。

认识Unity可寻址对象。

Unity可寻址对象的项目要求


如果您打算只阅读这篇文章,那么屏幕就足够了。如果您想和我一起做所有事情。那么您将需要以下内容:

  • 聪明的心
  • Unity 2019.2.0f1或更高版本
  • 带有GitHub的1级项目(下载zip或通过命令行)
  • 深入研究Unity可寻址对象的内在欲望

git存储库包含三个提交,每个级别用于一次发布(除非我混淆了一些内容并使用修订创建了一个提交)。

直接从GitHub下载ZIP格式的项目


1级开发人员:传统资产管理


我们将从最简单的资产管理方法开始。在我们的案例中,为此,我们必须列出指向组件中天空盒材质直接链接的列表

如果您与我一起这样做,则准备工作将只需三个简单步骤:

  1. 从git下载项目
  2. 在Unity中打开一个项目
  3. 点击播放按钮!

精细。现在,您可以单击按钮来更改天空盒。如此原始...无聊。据我了解,到目前为止还没有Unity可寻址对象。

很快您就会明白为什么我们要忍受这些无聊的时刻。

首先,我们的项目结构如何?它依赖于两个主要系统。一方面,我们有一个Game manager对象。该组件是主要脚本,用于存储指向Skybox素材的链接并根据UI事件进行切换。很简单

using UnityEngine;

public class Manager : MonoBehaviour
{
    [SerializeField] private Material[] _skyboxMaterials;

    public void SetSkybox(int skyboxIndex)
    {
        RenderSettings.skybox = _skyboxMaterials[skyboxIndex];
    }
}

Manager通过使用RenderSettings API为UI系统提供了将特定材质应用于场景的功能

其次,我们有一个CanvasSkyboxSelector。该游戏对象包含一个画布组件,该组件呈现一组垂直分布的按钮。每个按钮在按下时都会调用前述的Manager功能,该功能会根据按钮的ID替换渲染的天空盒。换句话说,每个按钮OnClick事件都会调用Manager对象SetSkybox函数。很简单,不是吗?


Unity可寻址对象-场景层次结构

现在该开始了。让我们打开分析器(ctrl / cmd + 7Window-Analysis-Profiler)。我将假定您熟悉此工具,这意味着您知道如何使用顶部记录按钮录制几秒钟后,将其停止并查看指标:CPU,内存等。有什么有趣的吗?

性能非常好,考虑到项目规模,这不足为奇。您可以简单地将这个项目变成一个VR游戏,并且我保证没有一个玩家会感到不适,就像Eve:Valkyrie中那样

在我们的例子中,我们将重点放在内存部分。在简单查看模式下,您将看到以下内容:


1级资产管理-简单的内存分析

纹理大小值似乎太大而无法一次显示一个Skybox,是吗?惊喜正等待着您:在许多未优化的游戏中都可以找到类似的模式,您将引领游戏的发展。但就我们而言,这只是一组天空盒在其他项目中,这些将是角色,行星,声音,音乐...

如果与您合作处理许多资产的责任在于您,那么我很高兴您正在阅读本文。我将帮助您过渡到可扩展的解决方案。

魔术的时间到了。将内存分析器切换为详细模式。看它!


1级资产管理-详细的内存分析

该死的,这是怎么回事?所有的Skybox纹理都已加载到内存中,但一次只显示其中一个。看到我们得到了什么?这种原始体系结构占用多达400 MB的空间

鉴于这只是未来游戏的一小部分,因此这绝对不适合我们。解决此问题本身将成为下一部分的基础。

总结:

  • 传统资产管理涉及直接链接
  • 因此,所有对象均不断加载
  • 该项目无法很好地扩展


2级开发人员:Unity可寻址流程


在游戏中,我们从第1级开始,这很适合我们,但是一旦我们弄清了游戏规则,就该离开安全的城墙并提高等级了。这就是本节的内容。

现在下载2级项目

正如我们之前在探查器中看到的那样,即使仅动态使用了一个天空盒,也将所有天空盒都加载到内存中。该解决方案无法扩展,因为在某些阶段,我们将受到可为玩家提供的不同资产变体数量的限制。我可以提供什么建议?不要将游戏的兴趣仅限于用户。

让我来帮助你。铲起传统资产管理的越狱隧道。让我们向集合中添加一个有趣的新工具:Unity Addressables API

我们需要做的第一件事是安装Addressables软件包。为此,请转到窗口→包管理器


Unity软件包管理器-Unity可寻址对象

安装后,我们需要将材料标记为可寻址对象。选择它们并激活检查器窗口中的可寻址标志。


管理2级资产(Unity可寻址对象)

因此,我们礼貌地要求Unity将这些材料及其纹理依赖性包括在可寻址对象数据库中。该数据库将在构建期间用于将资产打包成大块,可以在游戏中的任何时间轻松加载。

现在,我将向您展示一些很棒的东西。打开窗口->资产管理->可寻址对象。猜猜这是什么?这是我们渴望实现的数据库!




亲爱的读者,管理资产级别2 Unity可寻址对象是主窗口,这是简单的部分。现在,乐趣开始了。

我希望您访问上一节中的老朋友:经理先生如果我们检查它,我们会发现它仍然存储到资产的直接链接!我们不需要这个。

相反,我们将教经理如何使用间接链接,即 AssetReference(在虚幻引擎中,它们称为软引用)。

让我们使组件更漂亮:

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class Manager : MonoBehaviour
{
    [SerializeField] private List<AssetReference> _skyboxMaterials;

    private AsyncOperationHandle  _currentSkyboxMaterialOperationHandle;

    public void SetSkybox(int skyboxIndex)
    {
        StartCoroutine(SetSkyboxInternal(skyboxIndex));
    }

    private IEnumerator SetSkyboxInternal(int skyboxIndex)
    {
        if (_currentSkyboxMaterialOperationHandle.IsValid())
        {
            Addressables.Release(_currentSkyboxMaterialOperationHandle);
        }

        var skyboxMaterialReference = _skyboxMaterials[skyboxIndex];
        _currentSkyboxMaterialOperationHandle = skyboxMaterialReference.LoadAssetAsync();
        yield return _currentSkyboxMaterialOperationHandle;
        RenderSettings.skybox = _currentSkyboxMaterialOperationHandle.Result;
    }
}

发生以下情况:

  • 7, (AssetReference) . , . . .
  • 13: , . ,
  • 18-20 , , , , . , API Addressables, , . — , , addressable-.
  • addressable 23, LoadAssetAsync, yield ( 25), . . !
  • , , , 26. Result, , .


级别2资产管理(Unity可寻址对象)-AssetReference列表

请记住:此代码尚未准备就绪。对飞机进行编程时请勿使用它。我决定为简单起见,牺牲可靠性。

但是足够的解释。现在是时候看到他的行动了。

请按照以下步骤操作:

  1. 在可寻址窗口中,准备内容(构建播放器内容
  2. 然后针对所选平台进行构建
  3. 运行它,然后将分析器(内存)连接到它。
  4. 不要惊讶地放下你的下巴。


2级(统一可寻址对象)-构建播放器内容


级别2内存管理(Unity可寻址对象)-内存分析器

煮熟的资产不是很好吃吗?

当探查器满意时,我喜欢它。现在,我们看到了世界上最快乐的分析器。满意的分析器意味着:首先,即使在Nokia 3210上,也有更多满意的玩家可以玩您的游戏。其次,这些是令人满意的生产者。对于您来说,这意味着您的钱包将得到满足。

这就是可寻址系统的强大功能。

但是可寻址对象带来的额外人工成本很小一方面,程序员需要为异步工作流提供支持(使用协程很容易实现)。此外,设计人员将必须研究系统的功能(例如,可寻址的组),并获得制定明智决策的经验。最后,如果您希望在线托管资产,IT部门将非常高兴您必须配置用于通过网络传输资产的基础结构。

我必须祝贺你。我将解释我们所取得的成就:

  • 正确的内存管理。
  • 更快的启动。
  • 更快的安装时间,减小了商店中的应用程序大小。
  • 设备兼容性增强。
  • 异步架构。
  • 他们打开了在线存储此内容的大门→即从代码中分离数据。

我为如此成就感到自豪。这是我们劳动投资的丰厚回报。

哦,别忘了在采访中提及可寻址对象的经验。

支持材料:创建实例和链接计数。有关此主题的信息可以在我的帖子中找到

可选:替代下载策略。您可以在我的文章中阅读有关它们的信息

总结:

  • 基于可寻址对象的资产管理可以很好地扩展。
  • 可寻址对象增加了异步行为
  • 不要忘记准备内容以进行更改,否则游戏将呈现粉红色!


3级资产管理(??)-网络内容交付

3级资产管理(??)-网络内容交付


在上一节中,我们取得了最重要的突破。从传统的资产管理系统转移到基于可寻址对象的工作流程,从而提高了您的技能。这是该项目的巨大胜利,因为由于时间短,我们提供了扩展资产数量的空间,同时保持较低的内存消耗水平。这项成就实际上将您提升到了2级,恭喜!但是,我们仍然必须回答另一个问题:

这就是全部吗?

没有。我们几乎没有涉及到“可寻址对象”主题,这得益于此功能强大的软件包,还有其他改进项目的方法。

当然,您无需记住使用可寻址对象的所有详细信息,但我强烈建议您简短阅读它们,因为将来您很可能会遇到新的测试,并且您将感谢您进行更深入的研究。这就是为什么我准备了另一个简短指南。

从中您将了解以下方面:

  • 寻址窗口:重要详细信息
  • 可寻址对象分析:不要让内存泄漏破坏您的生活
  • 网络交付:从安装到玩游戏的时间减少
  • 装配流水线集成
  • 实用策略:加快工作流程,消除十分钟的咖啡休息时间

而且,更重要的是,我们将回答以下问题:

  • 发送探查器事件的隐藏含义是什么?
  • AddressableAssetSettings API有多有用
  • 如何将所有这些与BuildPlayerWindow API集成在一起
  • 虚拟模式打包模式有什么区别

我的帖子中提供了 3级指导

All Articles