AssetBundleを明らかにする（その壱）

AssetBundleはパッケージング化に依存しているとよく言われますが、その役割はアセットが更新されたときに部分的な更新を実現することです。これは、プロジェクトのメモリ管理にとって非常に重要であることがわかるので、今日はこのスキルを適切に使用する方法について説明します。

---
#AssetBundleパッケージ（4.x）基礎
##基本紹介
###(1)よく使っているパッケージAPI
>public static bool BuildAssetBundle(Object mainAsset, Object[] assets,
string pathName, out uint crc, BuildAssetBundleOptions assetBundleOptions,
BuildTarget targetPlatform);
public static string BuildStreamedSceneAssetBundle(string[] levels,
string locationPath, BuildTarget target, out uint crc, BuildOptions options);

●*BuildPipeline.BuildAssetBundle*
Scene以外のアセットをパックします。単一および複数をサポートします。

●*BuildPipeline.BuildStreamedSceneAssetBundle*
Sceneファイルをパックします。単一および複数もサポートします。

###(2) よく使っているパッケージオプション（BuildAssetBundleOptions）
●*CompleteAssets*
アセットの完全性を確保するために使用されます。たとえば、一つのMeshアセットのみをパッケージしてこのオプションをオンにすると、エンジンはMeshアセットと関するGameObjectをAssetBundleファイルに入力します。

●*CollectDependencies*
アセットの依存項を収集するために使されます。たとえば、一つのPrefabをパッケージしてこのオプションをオンにすると、エンジンはこのPrefabが使った全てのアセットとComponentをAssetBundleファイルに入力します。

●*DeterministicAssetBundle*
アセットの固定IDを維持するために使用されます。それでアセットのホットアップデートはしやすくなります。


上記のオプションは、5.xの新しいメカニズムにデフォルトでオンになっています。ですから、4.xバージョンでは、開発者が各オプションの意味を深く理解していない場合は、それもオンにすることをお勧めします。

3つのオプションをオンにしてパッケージすると、依存するすべてのアセットがパッケージ内にあるため、プレハブのロードおよびインスタンス化時にアセット引用が失われることはありません。これは、Prefab-AとPrefab-Bが同じAsset-Aを引用し、別々にパッケージする場合、両方のパッケージにAsset-Aが含まれることも意味します。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/aba6ddec-9deb-3b16-6f6c-58bdb8ecf19e.png)
メモリにロードした後、Profilerを介してAsset-Aの冗長アセットが発見できます。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/7392f750-e06b-4196-52ef-a8626d53aa0e.png)
ただし、多くの場合には、2つのPrefabを1つのBundleに入れることは望ましくありません。この時、依存関係パッケージ化によって解決する必要があります。

##依存関係パッケージ化
依存関係パッケージ化の役割は、アセットの冗長性を回避し、アセットのロードとアンロードの柔軟性を向上させることです。その重要性は自明です。4.xバージョンのAssetBundleパッケージ化システムは、BuildPipeline.PushAssetDependenciesとBuildPipeline.PopAssetDependencies二つのインターフェイスに関連します。公式ドキュメントからその使用法を大まかに理解できます。

http://docs.unity3d.com/ScriptReference/BuildPipeline.PushAssetDependencies.html

PushAssetDependenciesがアセットをスタックにプッシュし、PopAssetDependenciesがアセットをスタックから取ると考えられます。毎回パッケージすると、エンジンは現在のスタック内のすべての依存項をチェックして、同じアセットがすでにスタック内にあるかどうかを確認します。存在する場合には、関するAssetBundleとの依存関係を確立します。メカニズムを理解するのは難しいことではありませんが、使用中に見落としがちな注意点がいくつかあります。下記の「進級編」に移動して読んでください。

---
#AssetBundleパッケージ（4.x）進級
##注意点
●1回のPush操作と複数のBuild操作を行います。たとえば、アセットPrefab-AとPrefab-Bを順番にBuildする場合、Prefab-AとPrefab-Bが順番にスタックにプッシュされると認められます。2つの間に共有アセットがあれば、後者は前者に依存します。具体的な表現は、実行時にPrefab-Bを先にロードしますと、共有アセットが失う可能性があります。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/fa972272-888c-00ac-3f23-cfd29e59bb72.png)
●4.xでは、スクリプトは「共有アセット」として依存関係パッケージにも参加します。つまり、Prefab-AとPrefab-Bに同時にスクリプトMがアタッチされている場合、前のポイントの状況が発生したら、後者も前者に依存します。具体的な表現は、実行時にPrefab-Bを先にロードしますと、スクリプトMが失う可能性があります。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/a8b27e8b-8b84-9d9b-3236-f3d6419d2607.png)
●ShaderをGraphicsSettings-> Always Included Shadersに配置した後、対応するShaderはパッケージ化時に削除され、実行時またはロードする時には、対応するShaderを自動的にロードします。同時に、Always Included Shaderを変更したり、新しいプロジェクトでこのBundleを使用したりすると、Shaderが失われるという問題が発生することも意味します。

●bundle内容を更新する必要があるが、依存関係が変更しない場合でも、依存するBundleパッケージを再生する必要があります。つまり、Bundle-BがBundle-Aに依存している場合、Bundle-Aを更新するときにBundle-Bを再生する必要はありません（DeterministicAssetBundleがオンになっている場合）。ただし、Bundle-Bを更新する場合は、Bundle-Aを再生する必要があります。

---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

UWA公式サイト：https://jp.uwa4d.com
UWA公式ブログ：https://blog.jp.uwa4d.com