2016-06-22 17:06:16 ywjun0919 阅读数 1438
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4639 人正在学习 去看看 张刚
1. 加载顺序问题,被依赖的资源必须先加载完成。 
2. Shader依赖丢失问题:Editor版、Android版 均正常,但在IOS上丢失。

      问题现象:丢失的文件Shader1 与 Shader2具有相同Shader名,且文件内容完全一样,但是Shader1没有丢失被依赖,改名后也不行
      问题原因猜测:编译IOS平台与其他平台有区别(文件相同的Shader会出问题)
      解决方法:批量替换使用Shader2的材质
      **该问题的具体原因还未找到**
2017-11-13 22:53:53 u014361280 阅读数 232
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4639 人正在学习 去看看 张刚

unity 《专题系列》资源打包 Asset Bundles 


第五节 Asset Bundles 依赖打包和加载


一、依赖打包是什么,为什么要依赖打包

1、依赖打包,即是多个物体拥有相同的部分抽出来单独打包,这些多个物体就和单独打包出来的资源形成了依赖关系,叫做依赖打包,如下图



2、为什么要依赖打包,根据上图,我们就可以清楚看出,把共同部分提出来单独打包,可以节省资源占用,省空间,一定程度提高效率等好处,如下图





二、加载依赖包的方法

1、加载Sphere时,不加载依赖包,就会出现丢资源的紫色显示,如下图



2、加载Sphere时,一起加载依赖资源的方法(依赖资源在前加载,或后加载都没有关系,只要记得加载,系统就会自动找到对应依赖资源),如下图

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEngine.Networking;

public class LoadAssetBundle : MonoBehaviour {

	// Use this for initialization
	void Start () {
        //2.2 LoadFromFile 方法加载
        //AssetBundle的存放路径
        string path = "Assets/AssetBundles/sphereab.unityab";
        AssetBundle ab = AssetBundle.LoadFromFile(path);
        //取得所需要的资源
        GameObject go = ab.LoadAsset<GameObject>("Sphere");
        //加载生成到场景中
        Instantiate(go);

       //加载mainfest文件
        AssetBundle manifestAB = AssetBundle.LoadFromFile("Assets/AssetBundles/AssetBundles");
        AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

        foreach (string name in manifest.GetAllDependencies("sphereab.unityab"))        
        {
            //打印相关资源的信息
            print(name);
            //加载对应依赖资源
            AssetBundle.LoadFromFile("Assets/AssetBundles/"+name);
        }

    }
}





参考资料:

声明:如无意中涉及侵权到您的内容,请及时沟通修改,谢谢



2015-12-04 16:43:30 hfvip123 阅读数 1011
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4639 人正在学习 去看看 张刚

大家好,这我鄙人第一次真真正正的写博文害羞害羞,弄了个科比的头像,唉,科比这个赛季结束要退役了,从初中到现在十几年了,都一直支持着科比,至于为什么那么喜欢科比,打篮球的人都应该懂得害羞

这篇文章主要是记录一下unity3d中NGUI依赖关系打包以及资源的动态加载的一些事,其中文中有些内容是借鉴和参考了网上一些博主的文章,如有不足之处,希望看官们能够指出委屈委屈··················

1,先做一个公共的图集,这里命名为com,做好一个预设,如图:然后里面就一张图。

2,然后做两个预设A和B,其中A和B都分别引用到了com的图集,如图:


最后出来是这样:

3:将com,A,B打包成unity3d文件供下载。如图:


4,:资源加载,首先我们先加载A和B,最后在加载com,看看有什么情况发生,如图:


A也是如此的,为什么呢,引用到相关的脚本和图集都没有,那是因为把com作为了公共分享的资源,他涉及的一切相关的资源都会变成公共的资源:


[MenuItem("Tools/依赖关系打包")]
    static void Execute()
    {
        string SavePath = "Assets/U3DFiles/";
        if (!Directory.Exists(SavePath))
        {
            Directory.CreateDirectory(SavePath);
        }
        BuildAssetBundleOptions buildOp = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
            | BuildAssetBundleOptions.DeterministicAssetBundle;


        BuildPipeline.PushAssetDependencies();
        // 共享资源
        Object sharedAsset1 = AssetDatabase.LoadMainAssetAtPath("Assets/Prefab/com.prefab");
        BuildPipeline.BuildAssetBundle(sharedAsset1, null, SavePath + sharedAsset1.name + ".unity3d", buildOp, BuildTarget.StandaloneWindows);
        // 其他共享资源


        // A Prefab 使用到com.prefab和Refractive Atlas.prefab
        BuildPipeline.PushAssetDependencies();
        Object p1Asset = AssetDatabase.LoadMainAssetAtPath("Assets/Prefab/A.prefab");
        BuildPipeline.BuildAssetBundle(p1Asset, null, SavePath + p1Asset.name + ".unity3d", buildOp, BuildTarget.StandaloneWindows);
        BuildPipeline.PopAssetDependencies();


        // B Prefab使用到com.prefab和Refractive Atlas.prefab
        BuildPipeline.PushAssetDependencies();
        Object p2Asset = AssetDatabase.LoadMainAssetAtPath("Assets/Prefab/B.prefab");
        BuildPipeline.BuildAssetBundle(p2Asset, null, SavePath + p2Asset.name + ".unity3d", buildOp, BuildTarget.StandaloneWindows);
        BuildPipeline.PopAssetDependencies();


        BuildPipeline.PopAssetDependencies();
        AssetDatabase.Refresh();
        Debug.LogWarning("收集依赖关系成功");
    }

5,先加载com,然后在加载A和B,看看有什么不一样:


现在引用到的脚本资源和预设都出来了。

6,所以,做依赖打包的时候,先加载公共部分,在加载其他引用公共资源的东西················好了,今天先到这,这边去打球了,下回再看一下,没有用依赖打包的时候,每个单独打包有多大。

2015-08-27 16:52:13 zjjlittle 阅读数 1749
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4639 人正在学习 去看看 张刚
资源打包
1、美术资源打包
美术资源包括:角色模型,复杂特效,动作,场景
1.注入shader依赖
因为这些资源都可能用到shader,所以批量化的将shader统一注入依赖打包所有的特效,而shader可以挂在一个gameobject上面(shader需要放在Resources目录下)
2.打包后的目标目录
存放在Assets/StreamingAssets目录下,此目录会按原样打包到移动包中,此目录作为热更新操作目录
3.美术的源资源目录
美术资源不用存放到项目开发目录,可以另建一个资源项目,这个项目既可以保存美术资源也可以结合jenkins自动化美术资源打包使用

2、图集打包
在ngui中需要注入公共图集打包,但是在ugui中已经模糊了图集的概念,在打移动包时会自动的打包对应的图集,但是对于需要动态加载的图集,需要将这些图集打成预设,在游戏开始的时候加载到缓存。

3、UI预设打包
如果是ugui就不需要打包公共图集预设,直接打包所有ui即可
为了热更新,ui预设需要打包到StreamingAssets目录
将ui预设存放到Resources目录下,这样可以供pc调试的时候直接看效果,不需要打包。
将每个模块用到的所有预设存放到一个文件夹,并且以该文件夹名作于该模块的assetbundle名,当需要加载某个模块中的某个预设时路径设为用**/模块文件夹名/预设名

资源加载
1.美术资源加载
通过LoadManager进行异步加载管理,将需要加载的资源加入加载队列,然后在内存加载,加载完之后进行回调。其中有一个问题就是在等待队列中,如果我们加载相同的资源直接不加入队列,但实际上我们可能需要同时调用加载同一个地址资源,但是在不需要知道他加载的进度可能在还未加载完的时候在加载相同资源就直接被忽略了。
但是我们可以先加载一个,然后加载回调之后放入缓存,如果其他地方需要用到的话就在直接实例化就可以了。

2.图集加载
2.1.一种是系统默认打出的图集就是静态图集,可以通过
 if (AssetBundles.TryGetValue(path, out ab))
        {
            Object[] obs = ab.LoadAll();

            sprite = ab.Load(spriteName) as Sprite;
        }

2.2.动态加载的图集
需要有一个图集缓存器,对于android系统,对streamAsseting目录不可以直接读写,需要放到可读写目录中,只有放到可读写目录中才可以用AssetBundle.CreateFromFile()方式直接加载

3.ui预设加载
加载路径选择:如果打成AssetBundle包先从可读写目录查找,可读写目录没有找到就去包内的streamingAssets目录查找,如果找不到对应的AssetBundle包就去包内的Resources目录加载。
ui预设加载管理:需要有一个预设缓存器,通过传过去的路径先判断该模块assetbundle时候加载过,如果加载过直接load(预设名)就可以获取。
在pc我们上,一般是不用拷贝到可读写目录,直接在Resouces.Load(路径)就可以获取
值得注意的地方:Android平台下,包内不可以直接用www或者createFromFile方式读取,需要拷贝到可读写目录下,对于包内需要用协程和www组合才可以读取,但是pc和ios都是可以直接读取的。

4.加载简单特效
比如屏幕的飘雪花等,可以直接存放的Resources目录下,用Resources.load()加载

2017-09-19 15:59:33 strugglebydreamlin 阅读数 3238
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4639 人正在学习 去看看 张刚

写在前面:

很久很久很久。。没有更新了,当然写这个需要坚持,最近因为工作调整转了移动开发,之后的博客更新会以移动开发为主了,当然写博客纯粹是为了记录自己的学习过程,毕竟好记性不如硬键盘嘛,有什么错误的地方还望大家指正。

Unity自5.0开始提供了新的AssetBundle打包Api,以下是新旧Api对比:

旧版:
图1
图1


打包方式:

public class ExportAssetBundles {
        [MenuItem("Assets/Build AssetBundle From Selection - Track dependencies")]
        static void ExportResource () {
            // Bring up save panel
            string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d");
            if (path.Length != 0) {
                // Build the resource file from the active selection.
                Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
                BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, 0);
                Selection.objects = selection;
            }
        }
        [MenuItem("Assets/Build AssetBundle From Selection - No dependency tracking")]
        static void ExportResourceNoTrack () {
            // Bring up save panel
            string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d");
            if (path.Length != 0) {
                // Build the resource file from the active selection.
                BuildPipeline.BuildAssetBundle(Selection.activeObject, Selection.objects, path);
            }
        }
    }

而在目前最新的Unity2017版本中,旧版本的打包方式已经被完全废弃了。

新版打包Api:

图2
图2


public class PackageAssetBundle : MonoBehaviour {
    [MenuItem("Build/Build AssetBundles")]
    static void buildAssetBundles()
    {
        string buildPath = Application.dataPath + "/Assets/Abs";//打包路径
        if (!Directory.Exists(buildPath))
            Directory.CreateDirectory(buildPath);
        BuildPipeline.BuildAssetBundles(buildPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
    }

}

可以看到打包的代码非常简单。

如何指定需要打包的assets?

有几种方式:
第一种是直接在Inspecot面板进行指定:
图3
图3


打包时Api将选择所有你指定了AssetBundle VarName的资源,然后统一进行打包,如图3中该资源被打包后最终会生成cube.ab和cube.ab.manifest两个文件,manifest文件中记录的是cube.ab的信息,如依赖资源等等。

第二种呢是在代码中进行指定:

public class BuildAssetBundlesBuildMapExample : MonoBehaviour
{
    [MenuItem("Example/Build Asset Bundles Using BuildMap")]
    static void BuildMapABs()
    {
        // Create the array of bundle build details.
        AssetBundleBuild[] buildMap = new AssetBundleBuild[2];

        buildMap[0].assetBundleName = "enemybundle";

        string[] enemyAssets = new string[2];
        enemyAssets[0] = "Assets/Textures/char_enemy_alienShip.jpg";
        enemyAssets[1] = "Assets/Textures/char_enemy_alienShip-damaged.jpg";

        buildMap[0].assetNames = enemyAssets;
        buildMap[1].assetBundleName = "herobundle";

        string[] heroAssets = new string[1];
        heroAssets[0] = "char_hero_beanMan";
        buildMap[1].assetNames = heroAssets;

        BuildPipeline.BuildAssetBundles("Assets/ABs", buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
    }
}

当然指定方式灵活度还是不错的,你可以直接Selection,然后再对Selection的资源构造成buildMap,再进行处理即可。

打包说完了,接着就是加载咯。

如何加载?

加载可以分为三个步骤:
1.首先读取Manifest文件,读取需要加载ab(AssetBundle)的依赖资源
2.加载依赖ab
3.加载ab

ok,说了这么多好像。。。

那好吧,接下来还是看个小例子吧.

打包资源如下:

图4
图4


依赖关系:

Prefabs depends Materials
cube.ab depend on texure.ab
capsule.ab depend on emission.ab

我们只需要把材质挂在prefabs上即可,Unity新的打包方式会自动帮我们处理依赖关系的,运行打包代码后得到如下目录:
图5
图5
show in explorer来看看:
图6
图6
如图6所示,打包完成后,在打包路径下生成了一个和当前路径文件夹同名的AssetBundle文件和一个manifest文件,这两个文件是有用的,别随便删除了哈。。。这里写图片描述

但是改个名字什么的还是可以的哈。

接着来看一下文件大小,毕竟我们使用依赖打包的目的是为了减小包的大小不是嘛:

ab size
cube.ab 1.72KB
capsule.ab 1.78KB
texure.ab 147KB
emission.ab 510KB

哎,没错的吧,cube和capsule中确实剔除了材质,大小只有一点多KB,来看一下依赖信息,就是它:
图7
图7
我们可以发现里面清晰的记录每个ab的依赖资源信息。


加载方式

AssetBundle的加载方式有好几种,这里介绍两种常用的:

1.LoadFromFile:

public GameObject loadAssetBundleFiles(string filePath, string manifestBundleName, string abFileName, string prefabFileName)
    {
        /**
         * 1.首先从打包路径获取依赖
         * 这里加载的就是生成的同名文件ab,这里应该是filePath/Abs,当然会这个名称也可以修改
         */
        AssetBundle manifestBundle = AssetBundle.LoadFromFile(getManifestFilePath(filePath, manifestBundleName));
        /**
         * 2.获取依赖资源列表
         */
        if (manifestBundle != null)
        {
            try
            {
                AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");//固定加载方式,通过 assetbundle Abs加载Abs.manifest
                manifestBundle.Unload(false);
                //获取加载ab的依赖信息,参数为ab名称,如cube.ab
                string[] dependsFile = manifest.GetAllDependencies(abFileName);
                if (dependsFile.Length > 0)
                {
                    //根据获取到的依赖信息加载所有依赖资源ab
                    AssetBundle[] dependsBundle = new AssetBundle[dependsFile.Length];
                    for (int i = 0; i < dependsFile.Length; i++)
                    {
                        String fp = generateAbsoluteFile(filePath, dependsFile[i]);
                        Debug.Log(String.Format("depends:{0}:{1}", i, dependsFile[i]));
                        dependsBundle[i] = AssetBundle.LoadFromFile(fp);
                    }
                }
            }
            catch (InvalidCastException e)
            {
                Debug.LogException(e);
            }

            /**
             * 3.最后加载ab
             * 注意这里的LoadAsset的参数是Prefab的名称,无后缀,如cube而非cube.ab或cube.prefab
             */
            AssetBundle ab = AssetBundle.LoadFromFile(generateAbsoluteFile(filePath, abFileName));
            GameObject go = ab.LoadAsset(prefabFileName) as GameObject;
            ab.Unload(false);
            return go;
        }
        return null;
    }

2.WWW加载:

IEnumerator wwwGetAssetBundles(string filePath, string manifestName, string abFileName, string prefabFileName)
    {
        //WWW www = WWW.LoadFromCacheOrDownload(getManifestFilePath(filePath), 0);
        WWW www = new WWW(manifestName);
        yield return www;
        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.LogError(www.error);
        }
        else
        {
            /**
             * 1.首先从打包路径获取依赖
             */
            AssetBundle manifestBundle = www.assetBundle;
            /**
             * 2.获取依赖资源列表
             */
            if (manifestBundle != null)
            {

                AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
                manifestBundle.Unload(false);
                www.Dispose();
                string[] dependsFile = manifest.GetAllDependencies(abFileName);
                if (dependsFile.Length > 0)
                {
                    AssetBundle[] dependsBundle = new AssetBundle[dependsFile.Length];
                    for (int i = 0; i < dependsFile.Length; i++)
                    {
                        String fp = generateAbsoluteFile(filePath, dependsFile[i]);
                        Debug.Log(String.Format("depends:{0}:{1}", i, dependsFile[i]));
                        www = new WWW(fp);
                        yield return www;
                        if(www.error == null)
                        {
                            dependsBundle[i] = www.assetBundle;
                            www.Dispose();
                        }                        
                    }
                }

                /**
                 * 3.最后加载ab
                 */
                AssetBundle ab = AssetBundle.LoadFromFile(generateAbsoluteFile(filePath, abFileName));
                GameObject go = ab.LoadAsset(prefabFileName) as GameObject;
                if (go != null)
                {
                    GameObject.Instantiate(go);
                }
                ab.Unload(false);
            }
        }
    }

代码和第一种加载方式大致相同。

最后说一点使用时需要注意的地方,举个例子,比如说我们有一公用的资源,A、B、C三个ab都需要依赖D,那么在程序中我们需要加载A时会先加载D,然后加载A,这个时候B也需要被加载了,因为程序不知道D已经被加载了,所以再次去读取依赖信息,尝试加载D,这样就会消耗一些cpu的时间了,因此在我们实际开发中应该更加合理的去管理公用的ab资源,对于不常用的公用ab使用过后及时卸载,下次使用再进行加载,而对用经常使用需要常驻内存的ab资源,最好在程序中设置一个标识,标记其是否已经被加载,存在于内存中,然后在加载依赖该公用ab的ab资源时判断该公用ab是否已被加载,当然,也可能会存在一个ab依赖多个公用资源,这种情况就需要开发者更加谨慎的去处理依赖关系了,最好建立统一的管理,做到逻辑清晰。

Over:最后贴出
官网链接:BuildAssetBundles
Demo下载链接(Unity5.x):Demo地址
密码:m4q2


没有更多推荐了,返回首页