上一章:【Unity3D技术文档翻译】第1.7篇 AssetBundles 补丁更新
本章原文所在章节:【Unity Manual】→【Working in Unity】→【Advanced Development】→【AssetBundles】→【Troubleshooting】
AssetBundles 问题及解决方法本章节涉及一些使用 AssetBundles 的项目的常见问题。
资源重复(Asset Duplication)从 Unity5 开始的 AssetBundle 系统会在 Object 被打包进 AssetBundle 的时候,查找所有它的依赖。这是基于资源数据库(Asset Database)实现的。依赖信息用于确定将要被包含进 AssetBundle 的 Objects 集合。
被明确指派了 AssetBundle 的 Objects 将只被打包进该 AssetBundle。一个 Object “被明确指派”的意思是:Object 的 assetBundleName 不为空。
如果 Object 没有被明确指派给一个 AssetBundle,那么该 Object 将会被包含进所有引用了该 Object 的 AssetBundles 中,无论 AssetBundle 中有一个还是多个 Objects 引用了它。
如果有两个不同的 Objects 被分别指派给两个不同的 AssetBundles,并且这两个 Objects 都对另一个 Object 有引用,那么该 Object 将被拷贝进两个 AssetBundles。重复的依赖同样会被实例化,这意味着被依赖的 Object 的两份拷贝会被认为是两个不同的 Objects,且拥有各自的 id。这将增加应用 AssetBundles 的大小。如果应用加载了这两个 AssetBundles,那么就会导致内存中加载了两份 Object 的拷贝。
这里有些方法可以解决这样的问题:
确保被打包进不同 AssetBundles 的 Objects 没有共同的依赖。把任何有共同依赖的 Objects 打包进同一个 AssetBundle ,避免重复依赖。
这个方法通常不适用于那些有很多共同依赖的项目。并且这个方法会导致作为整体的 AssetBundles 被频繁地重新构建和重新下载,造成不方便和不高效。
分割 AssetBundles,使得拥有共同依赖的 AssetBundles 不会同时被加载。
这个方法对于特定类型的项目可能有效,比如以关卡为基础的游戏。然而,这会增加项目的 AssetBundles 大小,并且增加构建的次数和加载的次数。
确保所有被依赖的资源被打包进它们自己的 AssetBundles。这就完全排除了重复资源的风险,但是同样的这会使情况变的复杂。应用必须追踪 AssetBundles 间的依赖关系,并且确保在调用任何 AssetBundle.LoadAsset 方法之前,正确的 AssetBundle 已经被加载好。
在 Unity5 中是通过 UnityEditor 命名空间下的 AssetDatabase 方法来追踪 Object 的依赖。正如命名空间表明的,这个方法只能在 Unity 编辑器中使用,而不是在运行时。AssetDatabase.GetDependencies 方法可被用于定位一个 Object 或者资源的所有直接依赖。注意,这些依赖可能各自也有依赖。此外,AssetImporter 方法可用于查询某个 AssetBundle 中包含的 Object。
组合使用 AssetDatabase 和 AssetImporter 的方法,就可以编写编辑器脚本,确保一个 AssetBundle 所有的直接或者间接依赖都被打包进一个或者各自的 AssetBundle 中;或者任意两个有共同依赖的 AssetBundles,被打包进同一个 AssetBundle。考虑到重复资源造成的内存开销,建议所有项目都有一个这样的脚本。
Sprite 图集重复(Sprite Atlas Duplication)当 Unity5 中资源依赖的计算代码,和自动生成 Sprite Atlas 结合使用的时候,会出一点奇异的问题,下面的部分将描述这一点。
任何自动生成的 Sprite 图集,都会和图集生成的 Sprite Objects 一起打包到 AssetBundle 中。如果 Sprite Objects 被分配给多个 AssetBundles,那么 Sprite Atlas 就不会被打包为一个 AssetBundle,并且出现资源重复;如果 Sprite Objects 没有指明 AssetBundle,Sprite Atlas 同样不会被打包为一个 AssetBundle。
想要确保 Sprite Atlas 不重复,需要检查划分到同一个 Sprite Atlas 的 sprites (Tag 相同)要被指明为相同的 AssetBundle。
(Unity 5.2.2p3 会有额外的图集问题,在 Unity 5.2.2p4 已修复,建议用尽可能新的版本,这里不再赘述)
Android 纹理相关问题由于 Android 生态系统严重的设备碎片化,经常需要将纹理压缩为不同的格式。所有 Android 设备都支持 ETC1 格式图片,然而 ETC1 格式不支持透明通道。如果应用不需要 OpenGL ES 2 的支持,解决问题最简洁的方法就是使用 ETC2 格式,该格式需要 OpenGL ES 3 的支持。
然而大多数应用都需要适配老旧设备,因此 ETC2 格式可能无法使用。解决这个问题的一个办法是使用 Unity5 的 AssetBundle 版本变量。(你还可以查看 Unity 安卓优化指南,来了解更多其他解决方案的细节)