AssetBundle依赖查找工具
发表于2017-03-20
AssetBundle依赖查找工具
Unity有资源打包,利用AssetBundle,可以将几乎所有的资源都打包封装,只需要提前扫描所有要打包的资源,然后用AssetDatabase.GetDependencies获得所有的依赖,下面就给大家介绍下Unity中的AssetBundle。
AssetBundle依赖查找工具
动因
总揽
原理
实现
控件
AssetBundleName
特例
Builtin资源
默认材质
Sprite Atlas
Shader打包
动因
我们的项目使用Unity5.3.3版本。
在Unity5中,AssetBundle的打包和依赖管理已经简单了很多,我们只需要
AssetBundle依赖查找工具
给资源设置一个AssetBundleName,Unity就会自动完成依赖处理。
但是,有一个很大的问题是,Unity并没有提供一个编辑器窗口来查看每个AssetBundle中到底打包了什么样的资源,以及,是否有资源被打包到了多个AssetBundle中,即发生重复打包,产生了资源冗余
为了解决上面提到的问题,我们开发了一个编辑器插件,来查看AssetBundle的详细信息
总揽
拥有两个tab
AssetBundle列表:
重复打包的资源的列表:
直接资源就是指选择了AssetBundleName的资源
原理
A GUIDE TO ASSETBUNDLES ANDRESOURCES
在这个系列文章中,Unity解释了很多AssetBundle和Resources的底层技术细节,其中,提到
In Unity 5, Object dependencies are tracked via the AssetDatabase API
By combining the AssetDatabase and AssetImporter APIs, it is possible to write an Editor script that ensures that all of an AssetBundle's direct or indirect dependencies are assigned to AssetBundles, or that no two AssetBundles share dependencies that have not been assigned to an AssetBundle.
在我们的的插件中,正式使用了AssetDatabase和AssetImporter来分析整个依赖关系,进而保证分析的结果和实际打包出的AssetBundle保持一致
实现
控件
本插件实现了ListViewDrawer和RefTreeDrawer来简化UI的绘制和管理,实现数据驱动
public static void DrawFoldoutList(
ref bool foldout,
GUIContent title, List dataList,
Action drawFunc,
Dictionary menuItems=null,
Action selectFunc=null)
{
}
AssetBundleName
只有在指定了AssetBundleName后,AssetDatabase才能正确的分析整个依赖关系,但是,要手动设置AssetBundleName显然不是一个好的解决方案
我们使用Json文件来给出命名规则,使用Unity编辑器脚本来解析这个规则并自动设置AssetBundleName
{
"total_dir":[
{"dir":"Assets/Resources/UI/Texture", "prefix":"ui", "suffix":""},
{"dir":"Assets/Resources/UI/Prefab", "prefix":"ui", "suffix":""},
{"dir":"Assets/Resources/UI/Atlas", "prefix":"ui", "name":"atlas", "suffix":""},
{"dir":"Assets/Resources/UI/Atlas/Common/Icon", "prefix":"ui_atlas", "suffix":""},
{"dir":"Assets/Resources/SkillData", "prefix":"", "name":"config", "suffix":""},
{"dir":"Assets/Resources/Table", "prefix":"", "name":"config", "suffix":""},
{"dir":"Assets/Resources/Effects", "prefix":"", "suffix":""},
{"dir":"Assets/Resources/CmtInfo", "prefix":"", "suffix":""},
{"dir":"Assets/Resources/Skill", "prefix":"", "suffix":""},
{"dir":"Assets/Resources/Animation", "prefix":"", "suffix":""},
{"dir":"Assets/Resources/Actors", "prefix":"", "suffix":""},
{"dir":"Assets/Resources/DynamicShader", "prefix":"", "suffix":""},
{"dir":"Assets/StaticShaders", "prefix":"", "suffix":""},
{"dir":"Assets/Resources/ScenePrefab", "prefix":"", "suffix":""},
{"dir":"Assets/Resources/Map", "prefix":"", "suffix":""},
{"dir":"Assets/Resources/Modles", "prefix":"", "suffix":""},
{"dir":"Assets/Resources", "prefix":"", "name":"other", "suffix":""},
],
"child_files":[
{"dir":"Assets/Scene", "prefix":"", "type":"t:Scene", "suffix":"", "loadmode":"dynamic"},
],
"child_directory":[
],
"special_assets":[
],
"static_dir":[
{"dir":"Assets/Scripts"}
],
}
total_dir: 整个目录打包成AssetBundle
child_files: 目录下的指定文件被打包成独立的AssetBundle
child_directory: 子目录打包成独立的AssetBundle
special_assets: 特殊的文件,直接指定
特例
Builtin资源
需要注意的是,使用AssetDatabase的API,并不能获取到对Builtin资源的依赖关系,但是Builtin资源还是会被打包进AssetBundle的
默认材质
一种典型的Builtin资源是默认材质:
如果我们打开了modelImport.importMaterials=false这个导入选项,Unity会给模型指定一个默认的材质,这个材质并不能在我们的工程目录下看到
在这样的情况下,如果我们对每个模型指定一个AssetBundleName,那么在打包AssetBundle时,每个包都会打包一个Default-Diffuse.mat和Default-Diffuse.mat依赖的Standard Shader,这两个依赖已经要占用100K的大小了,影响还是很大的
幸运的是,Unity的AssetPostprocessor提供了OnAssignMaterialModel接口,供我们自定义默认的模型材质
Material OnAssignMaterialModel(Material mat, Renderer renderer)
{
if (mat.name != "Default-Diffuse" && mat.shader.name != "Standard")
{
return null;
}
var newMat = AssetDatabase.LoadAssetAtPath("Assets/DefaultMaterials/Default-Diffuse.mat");
return newMat;
}
通过指定自定义的默认材质,并且把这个默认材质单独打包,Unity就可以自动建立AssetBundle的依赖关系,完美解决这个问题
Sprite Atlas
在UGui中,Atlas是被Unity自动拼合的,这很方便,但带来一个很大的问题就是,这个自动拼合的Atlas会被重复打包的问题
在Unity 5.2.2p4, 5.3和更新的版本中,Unity自动做了点工作
Any automatically-generated sprite atlas will be assigned to the AssetBundle containing the Sprite Objects from which the sprite atlas was generated. If the sprite Objects are assigned to multiple AssetBundles, then the sprite atlas will not be assigned to an AssetBundle and will be duplicated. If the Sprite Objects are not assigned to an AssetBundle, then the sprite atlas will also not be assigned to an AssetBundle.
但是,还是很难完全避免重复打包的问题,还是要小心处理,甚至使用TexturePacker来手动打包Atlas,放弃Unity提供的这一便利
Shader打包
在日常的开发中,我们通常会使用
Shader.Find("Transparent/Diffuse")
来直接查找到Shader来使用,但是,如果Shader被打包到AssetBundle中,这个函数会报错的
Unity提供了一个解决方案是AlwaysIncluded Shaders:
当Shader被添加在Always Included Shaders中时,依赖这个Shader的资源在打包时,并不会包含真正的Shader代码,而是包含了一个引用
在检查插件中,我们也要注意处理这个情况