查看: 850|回复: 0
打印 上一主题 下一主题

[其他] Unity5.0 AssetBundle 学习心得

[复制链接]

9903

主题

126

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
53488
精华
316

最佳新人 热心会员 灌水之王 活跃会员 突出贡献 荣誉管理 论坛元老

跳转到指定楼层
楼主
发表于 2016-5-30 00:54:43 |只看该作者 |倒序浏览
首先,发下参考链接,阿赵的博客,写得很好:
    再详细的介绍一下Unity5的AssetBundle  以及 Unity5的AssetBundle的一点使用心得

    阿赵文中写过:
    “先来说说最多人关心的[color=rgb(85, 85, 85) !important]问题,Unity自己处理依赖关系。
    实际上来说,所有需要打包成AssetBundle的资源,你是要先赋予它一个assetBundleName的,在它有了assetBundleName之后,实际上它的信息已经存在于AssetDataBase里面了。所以在打包的时候,只需要调用BuildPipeline.BuildAssetBundles方法,它会把记录了的在AssetDataBase里面的所有资源先计算出依赖关系,再拆分打包。这个步骤是一点问题都没有的。要注意的是,你所有依赖的资源都必须赋予assetBundleName,不然,依赖就不会被拆分。”

    我很好奇,使用[color=rgb(85, 85, 85) !important]unity5,这样打包出来的AssetBundle究竟是什么样。于是参照他的方式,做了下实验。
    仍然是4张贴图,名字分别是T1,T2,T3,T4。2个材质球,M1,使用贴图T1,T2,T3。材质球M2,使用贴图T4。2个Cube物体,obj1和obj2,分别使用材质M1和M2.将obj1和obj2做成prefab。
    打包的代码很简单:
  1. using UnityEngine;
  2. using UnityEditor;

  3. public class BuildAssetBundle : MonoBehaviour {

  4.         // Use this for initialization
  5.         void Start () {
  6.         
  7.         }
  8.        
  9.         // Update is called once per frame
  10.         void Update () {
  11.        
  12.         }

  13.     [MenuItem("AssetBundle/BuildAssetBundle")]
  14.     public static void CreateAssetBundle()
  15.     {
  16.         BuildPipeline.BuildAssetBundles("Assets/Output", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
  17.     }
  18. }
复制代码
    1.只打包prefab
点击obj1,new一个AssetBundle name为“obj1”,同样为obj2 new 一个AssetBundle name为“obj2”,分别设置好。使用上面代码生成的菜单,导出AssetBundle。这样打包一共3个AssetBundle文件,分别是obj1,obj2,还有一个跟导出路径同名的output。其余的manifest文件是本地使用,暂时不关注。

    使用如下加载代码测试:
  1. using UnityEngine;
  2. using System.Collections;

  3. public class ImportAssetBundle : MonoBehaviour {

  4.         // Use this for initialization
  5.         void Start () {
  6.         AssetBundle ab1 = AssetBundle.LoadFromFile("Assets/AssetBundle/obj1");
  7.         if(ab1 != null)
  8.         {
  9.             Debug.Log("ab1 create success!");

  10.             Instantiate(ab1.LoadAsset("oBj1"));
  11.             //Object M1 = ab1.LoadAsset("M1");
  12.             //Debug.Log(M1.name);

  13.             string[] names = ab1.GetAllAssetNames();
  14.             foreach (var elem in names)
  15.                 Debug.Log("Asset name is " + elem);

  16.             Object[] objs = ab1.LoadAllAssets();
  17.             foreach (var elem in objs)
  18.                 Debug.Log("Obj is " + elem.name);

  19.             Object[] objsWithSub = ab1.LoadAssetWithSubAssets("Obj1");
  20.             foreach (var elem in objsWithSub)
  21.                 Debug.Log("Obj with sub assets is " + elem.name);
  22.         }

  23.         AssetBundle ab1Manifest = AssetBundle.LoadFromFile("Assets/AssetBundle/Output");
  24.         if (ab1Manifest != null)
  25.         {
  26.             Debug.Log("ab1Manifest create success!");
  27.             string[] names = ab1Manifest.GetAllAssetNames();
  28.             foreach (var elem in names)
  29.                 Debug.Log("asset name is " + elem);

  30.             AssetBundleManifest manifest = ab1Manifest.LoadAsset("AssetBundleManifest") as AssetBundleManifest;
  31.             if(manifest != null)
  32.             {
  33.                 Debug.Log("load manifest success");

  34.                 string[] AllAB = manifest.GetAllAssetBundles();
  35.                 foreach (var elem in AllAB)
  36.                     Debug.Log("AssetBundle is " + elem);

  37.                 string[] AllDependences = manifest.GetAllDependencies("obj1");
  38.                 foreach (var elem in AllDependences)
  39.                     Debug.Log("Dependences is " + elem);
  40.             }
  41.         }
  42.         }
  43.        
  44.         // Update is called once per frame
  45.         void Update () {
  46.        
  47.         }
  48. }
复制代码
     大家自行运行结果记忆会更深刻。
     分析结果发现, ab1.GetAllAssetNames(),ab1.LoadAllAssets() 能取出来的都只有obj1,而我实例化的obj1立方体可是带有材质和贴图的。放开注释的代码
       //Object M1 = ab1.LoadAsset("M1");       //Debug.Log(M1.name);

     运行会报错,说是空引用。明明有贴图,材质,可我们就是没法从AssetBundle取出来,只可能是unity自己将我们没有显式设置AssetBundle的资源密封起来了,不让我们去获取。
     之后的代码
   string[] names = ab1Manifest.GetAllAssetNames();      在实验中得到的只有一个文件,就是assetbundlemanifest,不区分大小写。这个文件包含了所有的依赖关系。
      再看obj1的依赖项
   string[] AllDependences = manifest.GetAllDependencies("obj1");      结果是空的,没有任何依赖项。可是obj1明明依赖了材质M1,还有贴图啊。
      猜测,是因为M1等资源没有打包的原因,我们验证一下。


    2.将材质,贴图与prefab共同打包到一个AssetBundle下
    将M1,T1,T2,T3的AssetBundle设置成obj1,再次打包,最后生成的文件个数没有变化。然而我们运行代码会发现结果出现了部分变化,首先就是M1能够load出来了,验证了只有显示设置AssetBundle name的资源才可以被我们load使用。
    最后的依赖资源,manifest.GetAllDependencies("obj1")获取的还是空,看看GetAllDependencies函数定义,获取的是依赖的AssetBundle的名字。obj1依赖的所有东西都在自身所在的AssetBundle里,自然获取不到值。再一次反省,看SDK的注释含义。。。


     3.将材质,贴图,prefab分开打包
    将M1的AssetBundle设置为M1,重新打包。生成的文件中多了M1的AssetBundle文件。
    继续使用加载代码,前面大部分相同,当然这次你不能从obj1的AssetBunble中去load试图获取 M1了。最关键的部分在最后,这次我们可以使用GetAllDependencies获取到obj1的依赖文件M1了。




   结语
    只打包prefab,省事,但可能造成资源的重复打包,无法复用。如果是唯一性的东西,只有某个物体使用,可以偷懒这么做。但如果想复用东西,老老实实多拆点小的包出来。当然,灵活性最高的就是用4.0那种自己控制的方式。具体的做法根据需求来取舍吧。

分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2025-8-18 09:29 , Processed in 0.179960 second(s), 33 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部