AssetBundle简介

Asset资源 包含:Mesh、Material、Textrue、Audio、Scripte、etc……


AssetBundle :Asset的集合,压缩,动态载入,本地缓存。  --(Unity Pro专有)


--AssetBundle VS Resource
Resource:
Resource资料夹
resources.assets文件
2G限制
首次需完全下载

AssetBundle : 
需要Editor脚本创建
动态下载

--AssetBundle的应用:
是Unity引擎记忆体管理机制的基石
适用平台:web player、Standalone OSXintel/Windows/Linux、Iphone、Android、PS3、XBOX360、Wii……

特殊:
Unity Web Caching License 中只能缓存AssetBundle 

-------------------------------Unity AssetBundle的基本用法--------------------------------------
创建AssetBundle:
1.通过Editor脚本创建
1.1 BuildPipeline.BuildAssetBundle()
--将project资料夹中的任意Assets打包成一个AssetBundle.
--一般适用于对单个大规模场景的部分。
1.2 BuildPipeline.BuildStreamedScenceAssetBundle()
--将一个或多个场景中的资源及其所有依赖打包成一个AssetBundle.
--一般适用于对单个或多个场景进行集中打包。
1.3 BuildPipeline.BuildAssetBundleExplocitAssetNames()
--将Project资料夹中的任意AssetS打包成一个AssetBundle
--可以为AssetBundle中每个Asset命名

-------------------------创建AssetBundle的选项-------------------------------------------------------------
1. BuildAssetBundleOptions.CompleteAssets --保证每个Asset本身的完整性(如物体上的Transform,mesh,collider等)
2. BuildAssetBundleOptions.CollectDependencies --包入每个Asset依赖的所有资源。
3. BuildAssetBundleOptions.DeterministicAssetBundle--使每个Object具有唯一的Hash ID,便于以后查找。
4. BuildAssetBundleOptions.UncompressedAssetBundle--不进行资源压缩。(很少使用,一般用于调试)

--------------------------下载远端Server的AssetBundle--------------------------------------------------------
1.WWW类方法:(W/O Cache)
1.1 通过构造www类对象来下载AssetBundle --(无法cache缓存下载到的资源)
1.2 同时创建解压缩
void Start(){
--开始下载
WWW www = new WWW("http://myServer/myBundle.unity3d");
--等待下载完成
yield www;

--获取指定的主资源并实例化
Instantiate(www.assetBundle.mainAsset);

var myLoadedAssetBundle = www.assetBundle;
var asset = myLoadedAssetBundle.mainAsset;
}
2.WWW类方法:(W/Cache)
2.1 WWW.LoadFromCacheOrDownload  --会将下载到的资源cache(缓存)到本地。(web平台有50M大小限制,Android与IOS没有)
2.2 载入Cache中缓存的Asset
void Start(){
WWW www = WWW.LoadFromCacheOrDownload("http://myServer/myBundle.unity3d",5);
yield www;
if(www.error != null){
Debug.Log(www.error);
return;
}

var myLoadedAssetBundle = www.assetBundle;
var asset = myLoadedAssetBundle.mainAsset;
}

-------------------------------如何载入AssetBundle对象-----------------------------------------------
1.WWW类方法和属性:--直接通过www.assetbundle属性来创建assetBundle记忆物体。
function Start(){
WWW www = new WWW("http://....com/.../,,,jpg");
yield www;

var myLoadedAssetBundle = www.assetBundle;
}
2.通过API动态创建 --AssetBundle.CreateFromMemory();从内存里的数据动态创建AB
--主要用于对数据进行加密
String url = "http://www.mywebbute.com/mygame/assetbundles/assetBundle.unity3d";
IEnumerator Start(){
WWW www = new WWW(url); --开始下载数据
yield return www; --等待下载完成

byte[] encryptedData = www.bytes; --获取到加密数据
byte[] decryptedData = YourDecryptionMethod(encryptedData); --解密

AssetBundle bundle = AssetBundle.createFromMemory(decryptedData);--从byte数组创建AB

--now you can use your AB 。the AB is not cached
}
3.通过API动态创建:--AssetBundle.CreateFromFile();从磁盘(文件)动态创建AB,仅支持非压缩的AB

----------------------------如何载入AseetBundle中的Assets:-------------------------------------------
1.载入任意AB中的Assets
1.1 AssetBundle.Load() --载入AB中指定名字的Object
1.2 AssetBundle.LoadAsync() --异步载入AB中指定名字的Object
1.3 AssetBundle.LoadAll() --载入AB中所有的Object

2.载入通过BuildPipeline.BuildStreamdScenceAssetBundle()创建的AB中的Assets时
2.1 Application.Loadlevel() --载入新levle,并销毁前一个Level的所有资源
2.2 Application.LoadlevelAsync() --异步载入新level,并销毁前一个leve的所有资源
2.3 Application.LoadlevelAdditive() --载入新levle,不销毁前一个level的资源
2.4 Application.LoadlevelAdditiveAsync()--异步载入新level,并不销毁前一个level的资源。
注意:载入之前必须调用Www.assetBundle

--------------------------如何产生实体Asset对象:
1.产生1个Asset对象:
function Start(){
WWW www = new WWW("http://myServer/myBundle.unity3d");
yield www;

Instantiate(www.assetBundle.mainAsset); --实例化 指定的main Asset
}
-------------------------------------------------------------------------------------------------------------
如何释放GameObject对象:
1.GameObject.Destroy(); --仅释放GameObject本身
如何释放AssetBundle & Assets:
1. AssetBundle.Unload(false); --仅释放AssetBundle本身
2. AssetBundle.Unload(true);--释放AB及从它载入的Assets
3. Resource.UnloadUnusedAssets() --仅释放没有引用的Assets

---------------------------------AssetBundle使用示例:
1.创建:
const String cubePath = "Assets/Cube.prefab";
const String castAssetBundlePath("Assets/StreamImgAssets/SimpleAssetBundle.unity3d");

var cube = GameObject.CreatePrimitive(peimitiveType.Cube);
primitiviety.CreatePrefab(cubePath,cube,XXX.ConnectToPrefab);
UnityEditor.AssetDatabase.SaveAssets();
Object.DestroyImmediate(cube);

--create the asset Bundle
Var assets = UnityEditor.AssetDatabase.LoadAllAssetAtPath(cubePath);
BuildPipeline.BuildAssetBundle(assets[0],assets,testAssetBundlePath);

2.载入/卸载
var www = new WWW(url);
yield return www;

AssetBundle bundle = www.assetBundle;
var cube = bundle.Load("cube");
--clean up
bundle.Unload(true);
www = null;
bundle = null;

使用AssetBundle动态载入场景
AB之间的依赖(1):将Assets之间的依赖放在不同的AssetBundles中。

------------------------------建立AB之间的依赖:----------------------------------------------------------
1.建立依赖:
1.1 BuildPipeline.PushAssetDependencies()
1.2 BuildPipeline.PopAssetDependencies()
(两者同时适用于BuildAssetBundle和BuildStreamedScenceAssetBundle)
2.顺序载入:
2.1 必须严格按照依赖关系进行载入  例:Mat ->Cuble/Cylinder
3.如需增量式发布:
3.1 DeterministicAssetBundle选项
-----------------------建立AB之间的依赖:--case1
1.通过push/PopAssetDependencies()以及BuildPipeline.BuildAssetBundle()将一个场景分割成多个相互依赖的AB.
2.使用XML或其他档案格式描述这样的依赖关系
3.使用Www.LoadFromCacheOrDownload动态下载描述文档和各个AB
4.按照场景描述档,调用AssetBundle.Load()方法来动态载入和拼接场景。
--示例 (cube与cylinder都要使用材质mat,将cube与mat打到一起)
BuildPipeline.PushAssetDependencies();

var assets = UnityEditor.AssetDatabase.LoadAllAssetAtPath(materiaPath);
BuildPipeline.BuildAssetBundle(assets[0],assets,"AssetBunldes/mat.unity3d");

BuildPipeline.PushAssetDependencies;
assets = UnityEditor.AssetDatabase.LoadAllAssetAtPath(cubePath);
BuildPipeline.BuildAssetBundle(assets[0],assets,"AssetBundle/cube.unity3d")
BuildPipeline.PopAssetDependencies();

BuildPipeline.PushAssetDependencies;
assets = UnityEditor.AssetDatabase.LoadAllAssetAtPath(cylinderPath);
BuildPipeline.BuildAssetBundle(assets[0],assets,"AssetBundle/cylinder.unity3d")
BuildPipeline.PopAssetDependencies();

BuildPipeline.PopAssetDependencies();

-----------------------------建立AB之间的依赖:--case2
1.通过Push/PopAssetDependencies()以及BuildPipeline.BuildStreamdScenceAssetBundle()将多个场景建立为多个相互依赖的AB,即将每个Level或多个level打包成依赖于其他AB的AB
2.使用XML或其他档案格式描述各个level的前后顺序
3.对于不存在依赖关系的AB,使用Application.Loadlevel()或Application.LoadlevelAsync()来载入每个场景
4.对于存在依赖关系的AB,使用Application.LoadlevelAdditive()或Application.LoadlevelAdditiveAsync()来载入和动态拼接场景。
注意:载入前必须调用www.assetBundle
--示例 (cube与cylinder都要使用材质mat,将cube与cylinder打到一起)
@MenumItem("Build/BuildWebPlayerStreamed")
Static function MyBuild(){
String[] level1 = {"Assets/Level1.unity3d"};
String[] level2 = {"Assets/Level2.unity3d"};
String[] level3 = {"Assets/Level3.unity3d"};

BuildPipeline.PopAssetDependencies()
BuildPipeline.BuildStreamdScenceAssetBundle(level1,"Streamed-Level1.unity3d",BuildTarget.WebPlayer);
BuildPipeline.PushAssetDependencies()
BuildPipeline.BuildStreamdScenceAssetBundle(level2,"Streamed-Level2.unity3d",BuildTarget.WebPlayer);
BuildPipeline.PushAssetDependencies()
BuildPipeline.BuildStreamdScenceAssetBundle(level3,"Streamed-Level3.unity3d",BuildTarget.WebPlayer);

BuildPipeline.PopAssetDependencies()
BuildPipeline.PopAssetDependencies()
BuildPipeline.PopAssetDependencies()

}
--载入
function Start(){
var bundle1 = WWW.LoadFromCacheOrDownload("http://mywebbute.com/Streamed-Level1.unity3d",1);
yield bundle1;
var level1 = bundle.assetBundle;
Application.LoadLevelAdditive("level1");

var bundle2 = WWW.LoadFromCacheOrDownload("http://mywebbute.com/Streamed-Level2.unity3d",1);
yield bundle1;
var level2 = bundle.assetBundle;
Application.LoadLevelAdditive("level2");
}
---------------------------------建立AB之间的依赖:--case3(常用)
1.通过BuildPipeline.BuildAssetBundle()将若干个场景内部的共用资源编译若干个AB
2.通过Push/PopAssetDependencies以及BuildPipeline.BuildStreamdScenceAssetBundle()依次将每个Level打包成一个AB
3.使用XML或其他档案格式描述各个level的前后顺序以及每个Level对于共用资源的依赖关系
4.使用Application.loadLevel() & Application.LoadlevelAsync()载入每个场景。

在Editor和Runtime之间共用资料:
1.场景描述档:ScriptableObject
2.适用于描述动态分割场景:
2.1代码分割场景
2.2打包至多个AssetBundles
2.3将分割资讯记录在ScriptableObject中并保存至Asset
2.4载入时先载入分割资讯并根据其载入AssetBundles

List<Object> toinclude = new List<Object>();
String stringholderPath = "Assets/ScriptableAsset.asset";
Stringholder content = scriptableObject.CreateInstance<Stringholder>();
UnityEditor.AssetDatabase.createAsset(content.stringholderPath);
toinclude.Add(UnityEditor.AssetDatabase.LoadAssetAtPath(stringholderPath,typeof(Stringholder)));
BuildPipeline.BuildAssetBundle(null,toinclude.ToArray(),testAssetBundlePath);


----------------------------动态分割实例------------------------------------
1.Character Customization
1.1 http://u3d.as/content/unity-technologies/character-customization/1qs
2.通过载入不同的AssetBundle实现换肤
2.1 将不同的肢体部位极其对应的材质打包到AssetBundle
2.2 根据配置动态载入AssetBundle
-----------------------
1.记录分割资讯
1.1通过切换material来进行换肤
1.2维护Material和AssetBundle的映射信息
1.2.1 CharacterElement列表
1.3将资讯记录到ScriptableObject并放置到名为CharacterBase的AssetBundle中
public class CharacterElement{
public string matName;
public string bundleName;
}
public class CharacterElementMolder :scriptableObject{
public List<CharacterElement> content;
}
-------------------------
1.如何载入:
1.1载入CharacterBase Asset Bundle
1.1.1读取Material和AssetBundles的映射信息
1.2切换Material
1.3载入需要的AB

---------------在大规模地形中的应用
1.将大场景分割成多个子场景
2.将子场景发布成AB
3.动态载入场景


-------------------------------------使用AB的若干技巧---------------------------------------
----------------------AB的版本控制------------------------------
1.可以通过WWW.LoadFromCacheOrDownload(String url, int version, crc:uint = 0)中的version来控制。
2.让参数可以强迫用户端从服务器下载一个更高版本的AssetBundle
--------------------AB的内容校验----------------------------------
1.可以通过WWW.LoadFromCacheOrDownload(url:String , version:int, crc:uint=0 )中的crc来实现。
2.当crc不为0时,如果本地cache中的内容与crc码不符,则说明内容资料损坏,unity会自动重新下载该资料。

API说明:http://docs.unity3d.com/Documentation/ScriptReference/WWW.LoadFromCacheOrDownload.html
----------------如何获取正确的Crc值--------------------
1.只需在本地调用LoadFromCacheOrDownload(url:string, version:int, crc:uint=0)即可。
2.可在url参数中填入assetBundle文件的本机地址,并赋给crc参数一个任意的非0值,这样,在返回的出错信息中,就能看到正确的crc值。

-----------------------------------------------在AB中嵌入脚本---------------------------------------------
1.将脚本编译成assembly
2.创建TextAsset:将assembly保存成.bytes文件
3.将TextAsset打包成AB
4.载入

AssetBundle bundle = www.assetBundle;
TextAsset txt = bundle.Load("myBinaryAsText",typeOf(TextAsset)) as TextAsset;
byte[] bytes = txt.bytes;
var assembly = System.Reflection.Assembly.Load(bytes);

---------------------------------------------AB的加密/解密----------------------------------------------------
1.Assembly没有完美方案
2.三种不完美的方案
2.1使用TextAsset来存储加密资料并打包入AssetBundle
2.2通过自定义算法加密AssetBundle本身,解密后通过AssetBundle.CreateFromMemory创建。
2.3以上两种的结合:
2.3.1将加密的AssetBundle作为TextAsset放在一个未加密的AssetBundle中
---------------------------------如何保护加密脚本------------------
1.Unity脚本
1.1在Ios平台是安全的,与是否使用AB无关
1.2对于其他平台,只能通过前述方法进行。
2..Net assembly + Asset Bundle
3.Native DLL
3.1 Desktop + Pro Only
3.2 存放在Asset/Plugins
3.3 使用[DLLImport]引入native函数
4.Web Player
4.1 不能载入Native DLL
4.2 .Net assembly + AssetBundle + new WWW

你可能感兴趣的:(unity,Assetbundle)