zoukankan      html  css  js  c++  java
  • AssetBundle使用心得【资源加载】

    0.资源加载方式

    1. 静态资源 Asset下所有资源称为静态资源
    2. Resources资源 Resources目录下,通过实例化得到的资源
    3. AssetBundle资源 又称为增量更新资源

    1.什么是AssetBundle包(下面称为AB包)

      一种存放在硬盘上压缩文件组形式,包含序列化文件(Manifest)与资源文件(Resources)。压缩包的压缩算法包括LZMA(流式压缩)与LZ4(块压缩)算法,前者压缩比例更高解压耗时更大。

      PS:www使用后是需要销毁的!!!www.Dispose();

    2.AB包打包原则有哪些

    • 引用同意贴图、材质、模型的资源最好一起打包
    • 一起展示的部分最好一起打包,比如一个场景,一个面板等
    • 导出目录一定要存在,不存在导出会失败
    • 加载资源时请务必清空一次缓存区!!重要!重要!

    3.AB场景资源打包

    • 打包前把需要的shader放到Edit/ProjectSetting/Graphics 的Always Includes Shaders上,不然加载后会出现shader关联不上的问题

    方式1.场景打包方式0 (打成多个资源包)


    • 设置要打包的场景资源

    • Editor中导入如下代码
    using UnityEngine;
    using System.Collections;
    using UnityEditor;
    using System.IO;
    
    public class ABSceneAll 
    {
        [MenuItem("Custom Editor/Version1CreateAB")]
        static void CreateSceneVersion1()
        {
            //清空一下缓存
            Caching.CleanCache();
    
            //路径
            string outPath = Application.streamingAssetsPath + "/AssetBundle";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }
    
            //检测所有的AB包资源创建Manifest文件 这里选择的是不进行任何特殊要求
            AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(outPath, BuildAssetBundleOptions.None, BuildTarget.Android);
    
            //存储txt文件
            if (manifest != null)
            {
                string txtPath = Application.streamingAssetsPath + "/AssetBundle" + "/gamehall.txt";
                string manifestPath = Application.streamingAssetsPath + "/AssetBundle" + "/AssetBundle.assetbundle";
                string temp = "";
    
                //得到所有的需要打AB包的资源名 
                string[] assetBundleNames = manifest.GetAllAssetBundles();
    
                //提示信息 & 安全校验
                if (assetBundleNames.Length != 2)
                {
                    EditorUtility.DisplayDialog("错误提示", "这是个安全校验,表示已经出问题了打包的场景过多", "确定");
                    return;
                }
                
                for (int i = 0; i < assetBundleNames.Length; i++)
                {
                    temp += assetBundleNames[i] + "" + manifest.GetAssetBundleHash(assetBundleNames[i]).ToString() + "
    ";
                }
                temp += "前二十位:" + manifest.GetAssetBundleHash(assetBundleNames[1]).ToString().Substring(0, 10) + manifest.GetAssetBundleHash(assetBundleNames[0]).ToString().Substring(0, 10);
    
                FileStream fs = new FileStream(txtPath, FileMode.OpenOrCreate, FileAccess.Write);//创建写入文件 
                StreamWriter sw = new StreamWriter(fs);
                sw.WriteLine(temp);//开始写入值
                sw.Close();
                fs.Close();
            }
            
    
            //资源刷新
            AssetDatabase.Refresh();
        }
    }
    View Code
    • Custom Editor中选择对应选项进行打包(这里打出来的包就包含了Manifest文件,2个不同的AB文件)
    • 读取方式如下代码
    /***************************************
    Editor: Tason
    Version: v1.0
    Last Edit Date: 2018-XX-XX 
    Tel: 328791554@qq.com
    Function Doc: 
    
    ***************************************/
    
    using UnityEngine;
    using System.Collections;
    
    
    public class MyTest : MonoBehaviour 
    {
        void Awake()
        {
    
            StartCoroutine(LoadScene());
        }
    
        private IEnumerator LoadScene()
        {
            Caching.CleanCache();
            //加载多个文件 Manifest + AssetBundle资源
            WWW downManifest = WWW.LoadFromCacheOrDownload("file://" + Application.streamingAssetsPath + "/AssetBundle" + "/AssetBundle", 1);
            //加载时间 600 * 0.1s 最长加载60s
            for (int i = 0; i < 600; i++)
            {
                if (downManifest.isDone)
                {
                    break;
                }
                if (i % 3 == 0)
                    Debug.Log("加载进度:" + downManifest.progress.ToString("#0.00"));
                yield return new WaitForSeconds(0.1f);
            }
            if (downManifest.isDone)
                Debug.Log("文件目录加载成功 ----- √");
            else
            { 
                Debug.Log("文件目录加载失败 ----- X");
                yield break;
            }
    
            AssetBundleManifest abm = downManifest.assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            string[] abResourcesNames = abm.GetAllAssetBundles();
            for (int i = 0; i < abResourcesNames.Length; ++i)
            {
                WWW downResource = WWW.LoadFromCacheOrDownload("file://" + Application.streamingAssetsPath + "/AssetBundle" + '/' + abResourcesNames[i], 1);
                for (int n = 0; n < 600; n++)
                {
                    if (downResource.isDone)
                    {
                        break;
                    }
                    if (i % 3 == 0)
                        Debug.Log("加载进度:" + downManifest.progress.ToString("#0.00"));
                    yield return new WaitForSeconds(0.1f);
                }
                if (downResource.isDone)
                    Debug.Log(string.Format("文件[{0}]加载成功 ----- √", i));
                else
                {
                    Debug.Log(string.Format("文件[{0}]加载失败 ----- X", i));
                    yield break;
                }
                
            }
    
            Application.LoadLevel("S1");
    
            yield return null;
            
        }
    }
    View Code

    方式2.场景打包方式1(打成1个资源包)


    • 设置要打包的场景资源

    • Editor中导入如下代码
    using UnityEngine;
    using System.Collections;
    using UnityEditor;
    using System.IO;
    
    public class ABSceneAll 
    {
        [MenuItem("Custom Editor/Version0CreateAB")]
        static void CreateSceneVersion0()
        {
            //清空一下缓存
            Caching.CleanCache();
    
            //路径
            string outPath = Application.streamingAssetsPath + "/AssetBundle";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }
            
            string TtargetPath = outPath + "/MY01.AB";
            string[] Scenes = { "Assets/Scene/S0.unity","Assets/Scene/S1.unity" };
    
            //打包场景
            BuildPipeline.BuildPlayer(Scenes, TtargetPath, BuildTarget.Android, BuildOptions.BuildAdditionalStreamedScenes);
    
            //资源刷新
            AssetDatabase.Refresh();
        }
    }
    View Code
    • Custom Editor中选择第一个选项进行打包(这里打出来的包就是一个AB文件)
    • 读取方式如下代码
    /***************************************
    Editor: Tason
    Version: v1.0
    Last Edit Date: 2018-XX-XX 
    Tel: 328791554@qq.com
    Function Doc: 
    
    ***************************************/
    
    using UnityEngine;
    using System.Collections;
    
    
    public class MyTest : MonoBehaviour 
    {
        void Awake()
        {
    
            StartCoroutine(LoadScene());
        }
    
        private IEnumerator LoadScene()
        {
            Caching.CleanCache();
            //资源加载 对应单一资源
            WWW download = WWW.LoadFromCacheOrDownload("file://" + Application.streamingAssetsPath + "/AssetBundle" + "/MY01.AB", 1);
            yield return download;
            Application.LoadLevel("S1");
            download.Dispose();
    
            yield return null;
            
        }
    }
    View Code

    AB包卸载


    1.减少内存消耗

    2.可能导致丢失的情况

    AssetBundle.Unload(bool _b); ----- 这里不是静态函数,前面要写获得的AB包对象 

    True: 强制卸载,不管有没有引用

    False:卸载没有用的资源

    踩坑


    1. AssetBunlde不区分大小写 所以建议全部用小写
    2. Resources和AssetBundle路径不同,Resources是相对路径,AssetBundle都有
    3. 依赖关系一定要处理好,不然包体会很大
    4. AssetBundle.CreateFromFile不能加载压缩过的AssetBundle,需要用www加载?!
    5. 资源间的关系必须是强关联,不能有资源通过代码里面的“Resources.Load<Type>”“Shader.Find”等弱关联连接,因为它不会被打包进AB包(已测试,非常关键)
    6. 如果你要把资源包放在StreamingAssets目录下进行资源加载,注意三端的路径是不一样的(这就很虚浮!)

        

    #if UNITY_EDITOR || UNITY_STANDALONE_WIN
            string finalPath = "file://" + Application.dataPath + "/StreamingAssets";
    #elif UNITY_ANDROID
            string finalPath = "jar:file://" + Application.dataPath + "!/assets";
    #elif UNITY_IPHONE
            string finalPath = Application.dataPath + "/Raw"
    #endif
    

      

    Shader&AB包的关系!


     1.首先场景中关联了材质的shader是会被打包到AB包中的(如果没打包进去,就去菜单栏 Edit -----> ProjectSetting ----> Graphics -----> Always Included Shaders 中进行添加)

      EG:后面我又做了个实验,通过AssetBundleBrower检查过一次,发现确实打包进去了,但UITexture的Shader还是存在问题,使用上需要格外小心,最好还是给引用的地方放一份Shader,ε=(´ο`*)))很是无奈啊!!!!

     2.但是存在一些问题,比如加载AB的场景可能会存在“关联丢失”的问题,表现出来的方式就像是shader没有被打包,但是当你重新点选同样的shader后又恢复了!这就很坑爹,原因不明

     3.那么如何解决这个问题呢,我参考了网上的一个方法,测试成功表示可行,在需要挂在新shader的父物体下面加上如下脚本即可,相当于它帮你记录了关联,然后运行时重新关联了一次!(适用于Mesh UGUI)

     4.当然如果你的代码里面存在创建模型这种骚操作,上诉挂载的方式是肯定行不通的,那就需要你自己加一句代码来重新关联咯,如:“m_materials[0].shader = Shader.Find("Custom/CutLineShader");”

    /***************************************
    Editor: Tason
    Last Edit Date: 2018-XX-XX 
    Tel: 328791554@qq.com
    Function Doc: 
    在需要自定义的使用自定义shader的物体的最上层父物体上加上这个
    脚本可以保证shader关联不丢失
    Version: 0.0.1 测试版
    ***************************************/
    
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class ShaderBD : MonoBehaviour 
    {
        private List<Material> thisMaterial;
        private List<string> shaders;
    
        void Start()
        {
            thisMaterial = new List<Material>(6);
            shaders = new List<string>(6);
    
            MeshRenderer[] meshRenderer = GetComponentsInChildren<MeshRenderer>();
            int length = meshRenderer.Length;
    
            for (int i = 0; i < length; i++)
            {
                int count = meshRenderer[i].materials.Length;
                for (int j = 0; j < count; j++)
                {
                    Material _mater = meshRenderer[i].materials[j];
                    thisMaterial.Add(_mater);
                    shaders.Add(_mater.shader.name);
                }
            }
    
            SkinnedMeshRenderer[] meshSkinRenderer = GetComponentsInChildren<SkinnedMeshRenderer>();
            length = meshSkinRenderer.Length;
    
            for (int i = 0; i < length; i++)
            {
                int count = meshSkinRenderer[i].materials.Length;
                for (int j = 0; j < count; j++)
                {
                    Material _mater = meshSkinRenderer[i].materials[j];
                    thisMaterial.Add(_mater);
                    shaders.Add(_mater.shader.name);
                }
            }
    
    
            for (int i = 0; i < thisMaterial.Count; i++)
            {
                thisMaterial[i].shader = Shader.Find(shaders[i]);
            }
        }
    }
    View Code

     总结:如果需要使用AB包进行场景打包,那么NGUI上使用的Shader,需要单独放在整合包(ABLoad的项目)中,如果是UGUI或者Mesh使用Shader,请在父物体上挂载上述脚本进行关联!!!!后续持续关注

    对了!下面是AssetBundleBrower(查看打包内容的UnityEditor 工具,直接导入Editor,在Window窗口中就能找到它了!支持5.6以上版本)

    链接:https://pan.baidu.com/s/1BN2EofgVXIthKiAIq3JPyg 密码:mg8i

  • 相关阅读:
    java smtp 发送邮件
    Java 数据库连接配置
    kettle基础操作数据同步
    Java上传文件到服务器指定位置
    Java 操作word
    Java 导出Zip文件
    Java 遍历二叉树字符串
    一款基于vue.js 和node构建个人博客项目
    CSS选择器介绍和优先级
    CSS Position属性
  • 原文地址:https://www.cnblogs.com/jwv5/p/9079139.html
Copyright © 2011-2022 走看看