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<UnityEngine.Object> assets = new List<UnityEngine.Object>();
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<string> shaderSet = new HashSet<string>();
string[] files = Directory.GetFiles("Assets/", "*.mat", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; ++i) {
Material material = AssetDatabase.LoadAssetAtPath<Material>(files[i]);
if (material != null && material.shader != null &&
!shaderSet.Contains(material.shader.name)) {
shaderSet.Add(material.shader.name);
}
}
List<UnityEngine.Object> shaderObjects = new List<UnityEngine.Object>();
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<string> commonTexture, List<string> 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來做,不夠靈活