unity3d:Assetbundle模拟加载,同步加载,异步加载,依赖包加载,自动标签,AB浏览器,增量打包
AB自动设置标签
文件夹中每个prefab,单独打包成一个assetbundle,使用于模型,单个UI面板
文件夹内每个文件夹打包成一个assetbundle,适用于图集
所有AB分发器配置数据在Editor/AssetBundle/Database/AssetPackage中,该目录下存在目录的一个映射结构,其中的每个序列化文件对应一个AB分发器
在打包前执行 make tag,通过读上面对应配置,自动设置ab标签与名字
public AssetBundleChecker(AssetBundleCheckerConfig config) { this.config = config; assetsPath = AssetBundleUtility.PackagePathToAssetsPath(config.PackagePath); importer = AssetBundleImporter.GetAtPath(assetsPath); } public void CheckAssetBundleName() { if (!importer.IsValid) { return; } var checkerFilters = config.CheckerFilters; if (checkerFilters == null || checkerFilters.Count == 0) { importer.assetBundleName = assetsPath; string[] bufName = importer.assetBundleName.Split('.'); MenuAssetBundle.m_abNameStr.AppendFormat("public const string {0} = \"{1}\";", bufName[0], bufName[0]); MenuAssetBundle.m_abNameStr.AppendLine(); }
AB打包
采用增量打包方式,只会打包改动的资源
BuildPipeline.BuildAssetBundles(info.outputDirectory, info.options, info.buildTarget);
调用该函数,unity会自动根据资源的标签进行打包,而且是增量打包,
- 对于资源没有变更的bundle包,不会触发重新打包;
- 资源没变,即使生成目录下的bundle包被删除了,unity也不会重新打包;
- 生成目录下的bundle包对应的manifase被删了,会重新打包;
- 可以使用BuildAssetBundleOptions.ForceRebuildAssetBundle参数触发强制重新打包。
打包完毕把md5信息写入
FileStream fs = new FileStream(newFilePath, FileMode.CreateNew); StreamWriter sw = new StreamWriter(fs); for (int i = 0; i < files.Count; i++) { string file = files[i]; //if (file.Contains("StreamingAssets")) continue; string ext = Path.GetExtension(file); if (file.EndsWith(".meta") || file.Contains(".DS_Store")) continue; string md5 = NTG.Util.md5file(file); string value = file.Replace(m_OutputPath + "/", string.Empty); FileInfo fileInfo = new FileInfo(file); int size = (int)(fileInfo.Length / 1024) + 1; //if (value != "StreamingAssets" && value != "StreamingAssets.manifest") sw.WriteLine(value + "|" + md5 + "|" + size); } sw.Close(); fs.Close();
AB包浏览器
方便查看一个ab包内具体包含哪些
黄色的是代表被多个ab包包含的资源
AB异步加载
编辑器下绕过打包模拟加载
if (SimulateAssetBundleInEditor) { string[] assetPaths = AssetDatabase.GetAssetPathsFromAssetBundleAndAssetName(assetBundleName, assetName); if (assetPaths.Length == 0) { Debug.LogError("There is no asset with name \"" + assetName + "\" in " + assetBundleName); return null; } // @TODO: Now we only get the main object from the first asset. Should consider type also. UnityEngine.Object target = AssetDatabase.LoadMainAssetAtPath(assetPaths[0]); operation = new AssetBundleLoadAssetOperationSimulation (target); }
异步加载
static public AssetBundleLoadAssetOperation LoadAssetAsync (string assetBundleName, string assetName, System.Type type,string path = "") { Log(LogType.Info, "Loading " + assetName + " from " + assetBundleName + " bundle"); AssetBundleLoadAssetOperation operation = null; { assetBundleName = RemapVariantName (assetBundleName); LoadAssetBundle (assetBundleName,false,path); operation = new AssetBundleLoadAssetOperationFull (assetBundleName, assetName, type); m_InProgressOperations.Add (operation); } return operation; }
加载依赖项:
- 加载a生成一个AssetBundleLoadOperation,为异步操作加载
public abstract class AssetBundleLoadOperation : IEnumerator { public object Current { get { return null; } } public bool MoveNext() { return !IsDone(); } public void Reset() { } abstract public bool Update (); abstract public bool IsDone (); }
- 找到a所有依赖ab包(例如b,c)
string[] dependencies = m_AssetBundleManifest.GetAllDependencies(assetBundleName); if (dependencies.Length == 0) return; for (int i=0;i<dependencies.Length;i++) dependencies[i] = RemapVariantName (dependencies[i]); // Record and load all dependencies. m_Dependencies.Add(assetBundleName, dependencies); for (int i=0;i<dependencies.Length;i++) LoadAssetBundleInternal(dependencies[i], false,path);
- 把b,c加入到m_DownloadingWWWs中,用www加载
- AssetBundleManager中update判断m_DownloadingWWWs每加载完一项,放入到m_LoadedAssetBundles已加载完ab表中
- 在AssetBundleManager的Update中遍历m_InProgressOperations中每一项AssetBundleLoadOperation,在a的AssetBundleLoadOperation的update中判断它的依赖b,c是否全部加载完(在m_LoadedAssetBundles中找到值),依赖全加载完,执行加载a的自身ab的请求m_Request = bundle.m_AssetBundle.LoadAssetAsync (m_AssetName, m_Type);
- b,c先加载完,a再加载完,AssetBundleLoadOperation中MoveNext返回false,代表执行完毕,可以根据ab包实例化gameobjec之类
同步加载
static private AssetBundle LoadAssetBundleSync(string abname, string abPath = "") { AssetBundle bundle = null; if (!m_LoadedAssetBundles.ContainsKey(abname)) { //byte[] stream = null; string uri; if (abPath != "") { uri = abPath + "/" + abname; } else { uri = AppConst.AbDataPath + "/" + abname; } //Debug.Log("Loading AssetBundle: " + uri); if (!File.Exists(uri)) { Debug.LogError(String.Format("AssetBundle {0} Not Found", uri)); return null; } //stream = File.ReadAllBytes(uri); bundle = AssetBundle.LoadFromFile(uri); //stream = null; LoadedAssetBundle loBundle = new LoadedAssetBundle(bundle); m_LoadedAssetBundles.Add(abname, loBundle); if (m_Dependencies != null && m_Dependencies.ContainsKey(abname)) { for (int i = 0; i < m_Dependencies[abname].Length; i++) { LoadAssetBundleSync(m_Dependencies[abname][i]); } } } else { LoadedAssetBundle loBundle = null; m_LoadedAssetBundles.TryGetValue(abname, out loBundle); bundle = loBundle.m_AssetBundle; } return bundle; }
关于AssetBundle.LoadFromMemroy内存翻倍问题
LoadFromMemroy即使在PC平台也不如LoadFromFile接口,经测试,PC上LoadFromMemroy接口内存的占用大概会高1/5左右,加载时间比LoadFromFile接口慢1/5左右,而且如loy_liu所说的,LoadFromMemroy接口需要先读取byte[]数组,会导致mono内存的分配,而LoadFromFile不会。
在android平台上,内存的对比将会非常夸张,我这边测试的数据是翻了接近3倍。
所以千万别用LoadFromMemroy接口,LoadFromStream接口没有去测试它的性能和内存,据说和LoadFromFile差不多。
https://answer.uwa4d.com/question/5e8ed8c6cd6a9b49fb4a46a3
posted on 2021-11-25 01:26 luoyikun 阅读(127) 评论(0) 编辑 收藏 举报 来源
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!