AssetBundle是Unity支持的一种资源打包方式。区别于Resources目录的打包资源,AssetBundle可以更加方便灵活的定制自己的资源组织方式,也可以支持资源更新。
AssetBundle 打包
AssetBundle打包以Object为单位,我们可以通过Untiy接口加载资源引用到的所有资源去打包,也可以对这些资源做筛选。
public static bool BuildAssetBundle(
UnityEngine.Object[] objs, string outputPath, out uint crc) {
crc = 0;
return BuildPipeline.BuildAssetBundle(null, objs,outputPath, out crc,
BuildAssetBundleOptions.ChunkBasedCompression |
BuildAssetBundleOptions.DeterministicAssetBundle |
BuildAssetBundleOptions.CollectDependencies,
BuildTarget.Android);
}
public static bool BuildAssetBundle(
string[] assetsList, string outputPath,
out uint crc , BundleType bundleType) {
crc = 0;
// Load all of assets in this bundle
List assets = new List();
foreach (string assetPath in assetsList) {
UnityEngine.Object[] assetsAtPath = AssetDatabase.LoadAllAssetsAtPath(assetPath);
assets.AddRange(assetsAtPath);
}
// assets include some not use object, we can filter used objects to reduce bundle size
assets = FilterObjectByType(assets, bundleType);
if (assets.Count == 0) {
return false;
}
return BuildAssetBundle(assets.ToArray(), outputPath, out crc);
}
Shader资源打包
Unity内置的Shader,并不能找到一个路径去打包,这时候我们可以直接把Shader作为Object传进去打包。
public static void BuildShaderBundle(string outputPath) {
HashSet shaderSet = new HashSet();
string[] files = Directory.GetFiles("Assets/", "*.mat", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; ++i) {
Material material = AssetDatabase.LoadAssetAtPath(files[i]);
if (material != null && material.shader != null &&
!shaderSet.Contains(material.shader.name)) {
shaderSet.Add(material.shader.name);
}
}
List shaderObjects = new List();
foreach (string shaderName in shaderSet) {
shaderObjects.Add(Shader.Find(shaderName));
}
if (shaderObjects.Count == 0) return;
uint crc = 0;
BuildAssetBundle(shaderObjects.ToArray(), outputPath, out crc);
}
公用资源打包
考虑到不同的资源可能引用到相同的资源,比如两个模型引用了相同的贴图,如果这时候把两个模型打成二个AssetBundle,那这张贴图会被分别打到两个AssetBundle里。
Unity提供里PushAssetDependencies和PopAssetDependencies来管理打包,同层之间的资源也是依赖的(先打的包有的,后面包就不会再打了),这里要比较小心不然依赖关系容易乱。
之前提到的Shader资源打包,可以做为共享包放在最顶层打包,这样Shader就只有一份了。
public static void BuildAllBundles(List commonTexture, List modelList) {
BuildPipeline.PushAssetDependencies();
BuildShaderBundle("Bundle/Shader.assetbundle");
foreach (string path in commonTexture) {
BuildAssetBundle(path);
}
foreach (string path in modelList) {
BuildPipeline.PushAssetDependencies();
BuildAssetBundle(path);
BuildPipeline.PopAssetDependencies();
}
BuildPipeline.PopAssetDependencies();
}
Unity 5 AssetBundle打包
Unity 5简化了打包过程,只需要设置BundleName,然后Build即可。
Unity 5支持在Inspect界面给每个资源设定BundleName,比起代码设置多了一种管理途径。
public static void BuildAssetBuilds(string[] assetsPath) {
for (int i = 0; i < assetsPath.Length; ++i) {
AssetImporter asset = AssetImporter.GetAtPath(assetsPath[i]);
asset.assetBundleName = Path.GetFileNameWithoutExtension(assetsPath[i]);
asset.assetBundleVariant = "assetbundle";
AssetDatabase.ImportAsset(assetsPath[i]);
}
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
BuildPipeline.BuildAssetBundles("Bundles");
}
总结
Unity提供了丰富的接口便于我们去构建AssetBundle,不过构建大小合理依拉关系清晰的AssetBundle还需要下较大的功夫去分析资源之间的依赖关系。
对比Unity 5新的打包方式,可以发现老接口可以更加精确的控制资源打包的力度,而且对于类似Unity内置Shader这种无路径内置对象,5只能通过替换Shader为本地的有路径Shader来做,不够灵活
附
AssetBundle压缩格式介绍