Unity场景ab包加载压缩(LZ4,LZMA)格式的测试

情况

最近场景越来越大,大概800M的场景加载时间可能长达40秒左右,所以需要测试看看发生了什么。

测试环境

测试环境Win10,21thI5-12600KF,32GRam , Nvidia GF RTX2060 32G
Scene1大小:741M

加载代码

首先放上部分的加载场景的代码:

        public float sceneprog;
        public AsyncOperation sceneAsync;
        async public Task LoadScene(string path)
        {
            sceneprog = 0f;
            await Task.Delay(10);
            StreamAssetVer sav = GameJsonMain.inst.Get(path);
            if (sav == null)
            {
                Debug.LogWarning("不存在的场景:" + path);
                return ;
            }
            if (!sav.isab)
            {
                Debug.LogWarning("场景isab必须对勾:" + path);
                return;
            }
            float loadtime = Time.realtimeSinceStartup;
            float computloadtime;
            float ratetime = 0.9f;
            //Application.backgroundLoadingPriority = ThreadPriority.Low;
            
            Debug.Log("LoadScene - begin ..."+ Application.backgroundLoadingPriority);
#if UNITY_EDITOR && TESTRES
            string[] dirs = UnityEditor.AssetDatabase.GetAssetPathsFromAssetBundle(path);
            //Object[] listobj = new Object[dirs.Length];
            if(dirs.Length == 0)
                Debug.LogWarning("找不到这个资源:" + path);
            for (int i = 0; i < dirs.Length; i++)
            {
                string assetPathAndName = dirs[i];
                LoadSceneParameters ls;
                ls = new LoadSceneParameters();
                ls.loadSceneMode = LoadSceneMode.Additive;
                
                sceneAsync = EditorSceneManager.LoadSceneAsyncInPlayMode(assetPathAndName,ls);  // .LoadSceneInPlayMode(assetPathAndName, ls);
                sceneAsync.allowSceneActivation = false;
                while (sceneAsync.progress < 0.9f)
                {
                    sceneprog = sceneAsync.progress;
                    await Task.Delay(100);
                    Debug.Log("load - " + sceneprog);
                }
                //sceneAsync.allowSceneActivation = true;
                //listobj[i] = null;
            }
            sceneprog = 1f;
            //Debug.Log("load1 - " + sceneprog);

            computloadtime = Time.realtimeSinceStartup - loadtime;
            Debug.Log("LoadScene unity- load file time : " + computloadtime);
            return ;
#endif
            Task<UnityWebRequest> task;
            if (sav.include)
            {
                task = streamingAssetsLoader(sav);
            }
            else
            {
                task = AssetsLoader(sav);
            }
            await task;
            UnityWebRequest www = task.Result;
            if (www.result != UnityWebRequest.Result.Success)
            {
                www.Dispose();
                return ;
            }

            computloadtime = Time.realtimeSinceStartup - loadtime;
            Debug.Log("LoadScene - load file time : " + computloadtime);
            //这个LoadFromFileAsync函数的路径不需要file://
            AssetBundleCreateRequest abRequest;
#if UNITY_EDITOR
            abRequest = AssetBundle.LoadFromFileAsync(sav.savepath.Replace(filelink, ""));
#else
            if(Application.platform == RuntimePlatform.Android)
            {
                abRequest = AssetBundle.LoadFromFileAsync(sav.savepath);
            }
            else
            {
                abRequest = AssetBundle.LoadFromFileAsync(sav.savepath.Replace(filelink, ""));
            }
#endif
            abRequest.allowSceneActivation = false;
            
            while (!abRequest.isDone)
            {
                sceneprog = abRequest.progress;
                await Task.Delay(100);
                //Debug.Log("ab:"+ sceneprog);
            }
            abRequest.allowSceneActivation = true;
            AssetBundle ab = abRequest.assetBundle;

            computloadtime = Time.realtimeSinceStartup - loadtime;
            Debug.Log("LoadScene - load AssetBundle time :" + computloadtime);
            //Debug.Log("ab1:ok," + sav.path +" - "+ sav.url);

            sceneAsync = SceneManager.LoadSceneAsync(sav.path, LoadSceneMode.Additive);
            sceneAsync.allowSceneActivation = false;
            while (sceneAsync.progress < 0.9f)
            {
                sceneprog = ratetime + sceneAsync.progress * (1- ratetime);
                await Task.Delay(100);
                //Debug.Log("load:" + sceneprog);
            }

            sceneprog = 1f;
            computloadtime = Time.realtimeSinceStartup - loadtime;
            Debug.Log("LoadScene - load LoadSceneAsync time :" + computloadtime);
            await Task.Delay(300);
            
            //sceneAsync.allowSceneActivation = true;
            //SceneManager.LoadScene(ab.GetAllScenePaths()[0]);
            //Object[] objs = ab. ab.LoadAllAssets();
            www.Dispose();
            ab.Unload(false);
            return ;
        }

大致代码分为2部分,在编辑器下#if UNITY_EDITOR && TESTRES 使用编辑器加载方式。

首先我们直接用编辑器通过UnityEditor.AssetDatabase.GetAssetPathsFromAssetBundle(path);方法来载入,大概需要5.5-7秒时间。为什么AB包需要那么久 ?

异步和同步加载测试

所有有了下面的AB包测试。
因为是AB包下载,所以关闭宏定义TESTRES ,我在想是不是使用了AssetBundle.LoadFromFileAsync来异步加载的,所以比较慢,所以把函数改为了AssetBundle.LoadFromFile,发现:

同步LoadFromFile方式:33秒
异步LoadFromFileAsync方式:38秒

时间都挺长的,发现有一个修改后台CPU级别的函数Application.backgroundLoadingPriority。

  • ThreadPriority.Low - 2ms
  • ThreadPriority.BelowNormal - 4ms
  • ThreadPriority.Normal - 10ms
  • ThreadPriority.High - 50ms
    改为了High,发现测试的结果相差不大。

压缩方式的对比

把场景的AB包我又打包成了无压缩格式和LZ4格式。我们看看测试结论
默认我的场景是LZMA格式

LZMA : 38秒
无压缩: 4.8秒
LZ4 : 4.7秒

结论

LZ4的压缩方式解压速度非常快和无压缩相差不大,压缩后大小比无压缩强的多,这种不需要从公网下载资源的推荐LZ4。

知识点

LZMA通过UnityWebRequestAssetBundle加载的LZMA格式AB包将自动重新压缩为LZ4压缩,并缓存在本地文件系统上。而通过自己写的下载方案,则可以调用AssetBundle.RecompressAssetBundleAsync API重新压缩。

参考:

https://zhuanlan.zhihu.com/p/342694796

Gzip_vs_Bzip2_vs_LZMA_vs_XZ_vs_LZ4_vs_LZO

https://segmentfault.com/a/1190000019656656

你可能感兴趣的:(Unity,unity,lzma,lz4,loadscene)