「翻译」Unity中的AssetBundle详解(六)

故障排除

本节介绍通常在使用 AssetBundles 的项目中出现的几个问题。

Asset 重复

当对象被构建到 AssetBundle 中时,Unity 5 的 AssetBundle 系统会发现对象的所有依赖关系。这是使用资产数据库完成的。此依赖关系信息用于确定将包含在 AssetBundle 中的对象集。明确分配给 AssetBundle 的对象只会内置到该 AssetBundle 中。当对象的 AssetImporter 的 assetBundleName 属性设置为非空字符串时,对象将被“显式分配”。在 AssetBundle 中未明确分配的任何对象将包含在所有的 AssetBundles 中,这些 AssetBundles 含有1个或多个引用未标记对象的对象。
如果两个不同的对象分配给两个不同的 AssetBundles,但都有一个公共依赖对象的引用,则该依赖对象将被复制到两个 AssetBundles 中。重复的依赖关系也将被实例化,这意味着依赖对象的两个副本将被视为具有不同标识符的不同对象。这将增加应用程序的 AssetBundles 的总大小。如果应用程序加载其父对象,这也将导致将两个不同的对象副本加载到内存中。

有几种方法来解决这个问题:

  1. 确保内置到不同AssetBundles中的对象不共享依赖关系。任何共享依赖关系的对象都可以放置在相同的AssetBundle中,而不会重复它们的依赖关系。

    • 这种方法通常对于具有许多共享依赖关系的项目是不可行的。它可以生成碎片的AssetBundles,以至于必须频繁地重新构建和重新下载,而不方便和高效。
  2. AssetBundles 切片,以便不会同时加载共享依赖的两个 AssetBundles。

    • 这种方法可能适用于某些类型的项目,例如基于关卡的游戏。然而,它仍然不必要地增加了项目的AssetBundles的大小,并且增加了构建时间和加载时间。
  3. 确保所有依赖资产都内置在自己的 AssetBundles 中。这完全消除了重复资产的风险,但也引起了复杂性。应用程序必须跟踪 AssetBundles 之间的依赖关系,并确保在调用任何 AssetBundle.LoadAsset API 之前加载正确的 AssetBundles。

在 Unity 5 中,通过位于 UnityEditor 命名空间中的 AssetDatabase API 跟踪对象依赖关系。正如命名空间所暗示的,此 API 仅在 Unity 编辑器中可用,而不在运行时可用。 AssetDatabase.GetDependencies 可用于查找特定对象或资产的所有直接依赖关系。请注意,这些依赖关系可能有自己的依赖关系。此外,AssetImporter API 可用于查询分配给任何特定对象的 AssetBundle。
通过组合 AssetDatabase 和 AssetImporter API,可以编写一个编辑器脚本,以确保将 AssetBundle 的所有直接或间接依赖关系分配给 AssetBundles,或者两个 AssetBundles 没有共享尚未分配给 AssetBundle 的依赖关系。由于重复资产的内存成本,建议所有项目都有这样的脚本。

精灵图集重复

以下部分描述了与自动生成的精灵图集结合使用时,Unity 5 的资产依赖关系计算代码的一个奇怪癖。任何自动生成的精灵图集将被分配给包含生成精灵图集的 Sprite 对象的 AssetBundle。如果将精灵对象分配给多个 AssetBundles,则 Sprite 图集将不会分配给 AssetBundle,并将被复制。如果 Sprite 对象未分配给 AssetBundle,则 Sprite 图集也将不会分配给 AssetBundle。为了确保精灵地图集不被重复,请检查标记在同一精灵图集中的所有精灵被分配到相同的资产组合。
在 Unity 5.2.2p3 及更老版本中,自动生成的精灵地图集将永远不会分配给 AssetBundle。因此,它们将被包含在任何含有其组成中的精灵的任何 AssetBundles 中,以及引用其组成中的精灵的任何 AssetBundles。
由于这个问题,强烈建议使用 Unity 的精灵打包程序的所有 Unity 5 项目升级到 Unity 5.2.2p4, 5.3 或任何新版本的Unity。
对于无法升级的项目,此问题有两种解决方法:

  1. 简单的:避免使用 Unity 内置的精灵封隔器。由外部工具生成的 Sprite 地图集将是正常的资产,可以正确分配给 AssetBundle。
  2. 困难的:将所有使用自动分配精灵的对象分配给与精灵相同的 AssetBundle。
  • 这将确保生成的精灵图集不被视为任何其他 AssetBundles 的间接依赖关系,不会被重复。
  • 该解决方案保留了使用 Unity 的精灵打包程序的工作流程,但是它降低了开发人员将资产分成不同 AssetBundles 的能力,并且在任何参考图集的组件上的任何数据更改时强制重新下载整个精灵图集,即使是图集本身没有变化。

Android Textures

由于 Android 生态系统中的设备配置差距严重,通常需要将纹理压缩成几种不同的格式。虽然所有 Android 设备都支持 ETC1,但 ETC1 不支持Alpha通道的纹理。应用程序不需要 OpenGL ES 2 的支持,解决问题的最简单的方法是使用所有Android OpenGL ES 3设备支持的 ETC2。
大多数应用程序需要在不支持 ETC2 的旧设备上运行。解决这个问题的一种方法是使用 Unity 5 的 AssetBundle 变体。 (有关其他选项的详细信息,请参阅 Unity 的 Android 优化指南。)要使用 AssetBundle 变体,使用 ETC1 不能被干净压缩的所有纹理必须与纹理唯一的 AssetBundles 隔离。接下来,使用供应商特定的纹理压缩格式(如 DXT5,PVRTC 和 ATITC),创建足够的这些 AssetBundles 变体来支持 Android 生态系统的非 ETC2 功能片段。对于每个 AssetBundle 变体,将包含的纹理的 TextureImporter 设置更改为适用于 Variant 的压缩格式。
在运行时,可以使用 SystemInfo.SupportsTextureFormat API 检测不同纹理压缩格式的支持。该信息应用于选择并加载包含受支持格式压缩的纹理的 AssetBundle 变体。有关 Android 纹理压缩格式的更多信息,请点击此处

iOS 文件句柄过度使用

以下部分中描述的问题已在 Unity 5.3.2p2 中修复。 Unity 的当前版本不受此问题的影响。在 Unity 5.3.2p2 之前的版本中,Unity 将在 AssetBundle 加载的整个时间内为 AssetBundle 保留打开的文件句柄。这在大多数平台上不是问题。但是,iOS 限制进程可能同时打开 255 的文件句柄数。如果加载 AssetBundle 超出此限制,将导致加载失败,并显示 “Too Many Open File Handles” 错误。对于试图将其内容分成数百或数千个资产分类的项目,这是一个常见的问题。对于无法升级到 Unity 修补版本的项目,临时解决方案有:

  • 通过合并相关的AssetBundles减少使用的AssetBundles数量
  • 使用 AssetBundle.Unload(false)关闭 AssetBundle 的文件句柄,并手动管理加载的对象的生命周期

Unity 的 AssetBundle 浏览器工具

注意:此工具是 Unity 的标准功能的附加功能。要访问它,你必须从 GitHub 下载它,并从标准 Unity Editor 的下载和安装中单独安装。该工具使用户能够查看和编辑其 Unity 项目的 AssetBundle 的配置。它能防止创建无效软件包的编辑,并通知你现有软件包的任何问题。它还提供基本的构建功能。使用此工具替代选择资产并在检查器中手动设置其 AssetBundle。它可以放入 5.6 或更高版本的任何 Unity 项目中。它将在 Window > AssetBundle Browser 中创建一个新的菜单项。Bundle 配置和构建功能在新窗口中分为两个选项卡。

需要 Unity 版本在 5.6 以上

用法 —— 配置

注意:此实用程序处于预发布状态,因此,我们建议在使用项目之前创建备份。此窗口提供了一个资源管理器界面,用于管理和修改项目中的 AssetBundle。当第一次打开时,该工具将解析后台中的所有 Bundle 数据,缓慢地标记警告或其检测到的错误。它可以与项目保持同步,但不能总是意识到工具之外的活动。要强制快速通过错误检测,或使用外部更改更新工具,请点击左上角的刷新按钮。窗口分为四个部分:Bundle 列表,Bundle 详细信息,资产列表和资产详细信息。

Bundle 列表

左侧窗格显示项目中所有 Bundle 的列表。可用功能:

  • 选择一个 Bundle 或一组 Bundle,以查看资产列表窗格中的 Bundle 中的资产列表。
  • 具有变体的 Bundle 是较暗的灰色,可以扩展以显示变体列表。
  • 右键单击或缓慢双击以重命名 Bundle 或 Bundle 文件夹。
  • 如果 Bundle 有任何错误、警告或信息消息,右侧将出现一个图标。鼠标悬停在图标上以获取更多信息。
  • 如果 Bundle 中至少有一个场景(使其成为场景 Bundle),并且明确包含非场景属性,则会将其标记为有错误。此 Bundle 将不会建立,直到修复。
  • 具有重复资产的 Bundle 将标有警告(有关资产列表部分重复的更多信息,请参见下文)
  • 空 Bundle 将被标记一个信息消息。由于一些原因,空的 Bundle 并不是非常稳定,有时可能会从这个列表中消失。
  • Bundle 的文件夹将被标记为包含 Bundle 中最高的消息。
  • 要修复 Bundle 中重复包含的资产,你可以:
    • 右键单击一个 Bundle 将所有确定为重复的资产移动到新的 Bundle 中。
    • 右键单击多个 Bundle,将资产从所有选定的 Bundle 复制到新的 Bundle 中,或者仅在选择中共享的 Bundle 中。
    • 你还可以将资产列表窗格中的重复资产拖放到 Bundle 列表中,以将其显式包含在 Bundle 中。资产清单功能的详细信息如下。
  • 右键点击或点击 DEL 删除软件包。
  • 拖动 Bundle 将其移入和移出文件夹,或合并它们。
  • 将资源从项目资源管理器拖动到 Bundle 上以添加它们。
  • 将资源拖动到空的空间以创建新的 Bundle。
  • 右键单击以创建新的 Bundle 或 Bundle 文件夹。
  • 右键单击“转换为变体”
    • 这将添加一个变体(最初称为“新变量”)到选定的 Bundle。
    • 所有目前在选定 Bundle 中的资产将被转移到新的变体中。
    • 即将到来的功能:变体之间的不匹配检测。

图标表示 Bundle 是标准 Bundle 还是场景 Bundle。

标准 Bundle 图标

场景 Bundle 图标

Bundle 细节

左下方窗格显示“捆绑列表”窗格中选择的捆绑包的详细信息。如果可用,该窗格将显示以下信息:

  • 总 Bundle 大小这是所有资产的磁盘大小的总和。
  • 当前 Bundle 依赖于的 Bundle
  • 与当前 Bundle 相关联的任何消息(错误/警告/信息)。

资产清单

提供在 Bundle 列表中选择的任何 Bundle 中包含的资产列表的右上角窗格。可用功能:

原文链接:

  1. Troubleshooting
  2. Unity Asset Bundle Browser tool

同系列文章

「翻译」Unity中的AssetBundle详解(一)

「翻译」Unity中的AssetBundle详解(二)

「翻译」Unity中的AssetBundle详解(三)

「翻译」Unity中的AssetBundle详解(四)

「翻译」Unity中的AssetBundle详解(五)

「翻译」Unity中的AssetBundle详解(六)