Unity Addressables 的使用相关
随着 Unity 的 Addressables 逐渐完善, 已经可以替代其它的打包加载卸载等工具的功能了, 今天做了一下测试, 有那么几个挺好的地方 :
1. AssetReferenceT
2. 有一些贴心设计比如场景如果加入到 Addressables Groups 中的话, 如果被 Build Settings 引用到, 会自动取消引用 :
场景会自动取消引用, 如果强行勾选 Build Settings 里的场景, 会自动删除 Addressables Groups 中的引用. 这样就保证了场景不会在打包时重复了.
不过场景打包的资源仍然跟 Addressables 是分开管理的.
比如下面这样, Test001 勾选为默认场景, 场景里有一张贴图 :
而在场景中又通过代码加载同样一张贴图, 就会变成这样资源重复了 :
说明场景的贴图是被 Resources 那边管理的, 这张贴图只能通过 Resources.UnloadUnusedAssets(); 来卸载.
所以场景还是用一个空场景作为起始场景, 再通过 Addressables 加载其它场景就行了.
5. 以前 AssetBundle 会出现的默认材质 Shader 重复编译问题, 猜测应该没问题, 测试看看 :
看来一般状况下不管怎样打包和分包, 都不会造成材质 Shader 的重复编译了.
-------------------------------
看了一下生成出来的 AssetBundle 包, 感觉并不是很正确, 这里的场景是引用了一个 Prefab, 而所有的材质和贴图引用都是通过 Prefab 来的, 如果我只对场景进行打包的话, 得到的是下面这样的结果 :
如果把场景和 Prefab 都进行打包的话, 得到下面的结果 :
可见场景的大小并没有改变, 并且 Prefab 的大小也是跟场景差不多, 这就说明场景和 Prefab 都把引用资源给打包了.......
查了一下, 原来是创建材质 Group 的时候代码添加错误导致的, 通过代码创建需要制定相应的控制器, 这里记录一下 :
public static ListSchemaTypes { get { return new List () { typeof( UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema), typeof( UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema), }; } } private static void AddNewAsset(UnityEngine.Object asset, string groupName) { var settings = AddressableAssetSettingsDefaultObject.Settings; if(settings) { var assetPath = AssetDatabase.GetAssetPath(asset); var group = settings.FindGroup(groupName) ?? settings.CreateGroup(groupName, false, false, false, new List { settings.DefaultGroup.Schemas[0] }, SchemaTypes.ToArray()); if(group) { var guid = AssetDatabase.AssetPathToGUID(assetPath); var entry = settings.CreateOrMoveEntry(guid, group); entry.SetAddress(assetPath, true); } } }
PS : 创建资源 Group 可以创建很多个, 或者在一个Group 里面选择分开打包, 下面的都得到差不多的包, 材质全是独立的 Assetbundle 包, 不知道在加载时有没有性能差别.
对于不把材质作为显式打包的设置的话, 只引用场景和 Prefab, 状况就回到前面资源重复的状态了 :
可以猜想到重复引用的资源, 仍然会被重复打包. 那么加载出来的资源, 就必然又会重复了 :
材质重复
图片也重复了
重新把材质引用到 Addressables Group 里面来, 就正常了 :
所以目前来说, 它还不是一个手动就能维护的打包系统, 仍然需去厉遍所有资源的引用数量, 重复引用资源仍然要自己控制生成相应 Groups, 要不然资源加载的控制也是无从说起的. 目前它的好处就是把 Shader 的编译问题给解决了, 这在以前是个老大难问题......
而且通过查看文件大小, 可以看出 Addressables 把多余的变体给删除了 :
同样的材质 Addressables 和普通 BuildPipeline.BuildAssetBundles 打包出来的大小天差地别, 应该是在标准材质的变体上
PS : 不过之前测试时用了两个 Canvas 和 AssetReferenceT
又错了, 之前测试的时候是把两个 Canvas 放在同一个 Group 里面了, 而且 AssetReferenceT
当两个 UI 处于不同的包的时候, 并且没有图片的显式引用的话, 仍然会在打包和加载的时候造成重复.
再来看看图集的使用情况, 最近很奇怪 Unity 右键菜单找不到创建 SpriteAtlas 的操作.......
创建了两个 spriteatlas, 因为图片没有加入 Addressables 所以是灰色的, 加载通过先加载 SpriteAtlas 然后再获取下面的图片, 跟我们的常识一样, 能够正常合批.
可是如果把其中的一些图片加入到 Group 里面来, 就容易出问题了 :
加入前
加入后
应该是图片独立出去之后, 作为普通图片存在了, 并且非PO2所以图片不压缩, 就很大.
如果独立的图片跟 SpriteAtlas 同一个包, 它又能够作为图集的一部分了 :
尺寸也恢复了, 所以如果有需求, 需要把图片和图集放在同一个包里. 不过即使这样通过 SpriteAtlas 加载出来的图片, 跟直接通过资源加载的图片, 仍然是不同的, 这个需要记住 :
Addressables.LoadAssetAsync("Assets/Atlas/SA2.spriteatlas").Completed += (_atlas) => { imgs[0].sprite = _atlas.Result.GetSprite("bg_icon"); Debug.Log("spriteatlas : " + imgs[0].sprite.name); Addressables.LoadAssetAsync ("Assets/Sprites/SP1/bg_icon.png").Completed += (_sp) => { imgs[1].sprite = _sp.Result; Debug.Log("sprite : " + imgs[1].sprite.name); Debug.Log(imgs[0].sprite == imgs[1].sprite); }; Addressables.LoadAssetAsync ("Assets/Sprites/SP1/ic_pos.png").Completed += (_sp) => { imgs[2].sprite = _sp.Result; Debug.Log("sprite : " + imgs[2].sprite.name); }; };
结果没有什么意外, 不过从 SpriteAtlas 来的图片, 是一个克隆, 可能每次通过接口获取都会造成克隆.
意外的是通过资源加载的 Sprite, 它们都能够正确合批, 比如上面的三张图, 能够在一次 draw 中绘制......根据观察, 通过上面的资源接口加载出来的 Sprite, 也是依赖于 SpriteAtlas 的, 自动加载了图集. 所以目前看来, 图集都是能正确合批的.
---------- 一些补充 ------------
1. 在 Group 编辑的时候可以看到一般新加资源会自动命名为带了扩展名的路径, 这个就保证了它的唯一性, 不过在不断修改的过程中比如 Assets/A.mat 文件位置变为 Assets/Materials/A.mat 之后, 它在 Addressables 里面的 Key 也是不会变的, 还是老样子, 好处是代码不需要变动.
问题是如果又加入一个 Assets/A.mat 资源, 就会有两个相同的名称资源了 :
就会造成混乱, 其实还是永远保持路径为 Key 才是最准确的, 虽然会因为资源位置移动造成代码需要修改的情况.
PS : 在这个面板右键有一个快捷方式简化 Key 名称, 可是没有还原 Key 为文件路径的方法, 有点搞笑 :
只能用代码去改回 :
var settings = AddressableAssetSettingsDefaultObject.Settings; if(settings) { foreach(var group in settings.groups) { foreach(var entry in group.entries) { entry.SetAddress(entry.AssetPath, true); } } }
2. 文件夹也能设置为 Addressables 资源, 估计跟 Resources 一样能够读取整个文件夹 :
测试了一下, 不行...
文件夹拖入 Group 只能展现文件夹, 如果里面的资源没有勾选 Addressable 的话, 是灰色的, 如果勾选了的话就变成跟 Assets/Materials 同级的了, 不能放到里面去了......
不管在任何设置下, 都不能通过 Assets/Materials 作为 Key 来加载文件夹下的资源 :
Addressables.LoadAssetsAsync("Assets/Materials", (_obj) => { }).Completed += (_list)=> { var mats = _list.Result; foreach (var mat in mats) { Debug.Log(mat.name); } };
会报错......既然不能加载, 为啥要让文件夹也能放到 Addressables 系统里, 理解不能.