Unity 5 より前のバージョンでは、アセットの依存関係の定義はエディタースクリプトのみでしか行うことができませんでした。(Unity 5 では、エディター上のツールを使ってアセットを特定のバンドルに割り当てることができ、依存関係の管理は自動で行われます。)以下の情報は、Unity 4 で旧プロジェクトを扱うユーザー向けに、Unity 4 を使用している前提で提供しています。
バンドルの任意のアセットは他のアセットに依存するかもしれません。例えば、モデルはマテリアルを利用するかもしれず、テクスチャやシェーダーを使用するかもしれません。アセットの依存関係をバンドルとともにすべて含めることは可能です。しかし、異なるバンドルからのいくつかのアセットは他のアセットの共通セットに依存するかもしれません(例えば、ビルの複数のモデルがあった場合に共通の煉瓦のテクスチャを使用するかもしれません)。もし共通の依存関係の別の複製がオブジェクトに使用されるそれぞれのバンドルに含まれると、バンドルが読み込まれたときにアセットの余剰なインスタンスが作成されます。これはメモリの浪費につながります。
そのような浪費をさけるため、共有の依存関係を別のバンドルに分けることができて、必要とするアセットとともに、どんなバンドルからでも参照することができます。最初に、BuildPipeline.PushAssetDependencies をコールして参照機能を有効化する必要があります。次に参照の依存関係を含むバンドルはビルドされる必要があります。次に、PushAssetDependencies への別のコールを、最初のバンドルからアセットを参照するバンドルをビルドを行う前に、行う必要があります。追加の依存関係のレベルは PushAssetDependencies に対する更なるコールにより実現することができます。参照のレベルはスタックに格納されるため、ひとつレベルを戻るのに対応する BuildPipeline.PopAssetDependencies 関数を使用することができます。push および pop コールは、ビルド前に起きる最初のプッシュを含め、バランスをとる必要があります。
ランタイムでは、他のバンドルが参照する前に、依存関係を含むバンドルをロードする必要があります。例えば、共有テクスチャのバンドルを、そのテクスチャを参照するマテリアルの別のバンドルをロードする前にロードする必要があります。
もし依存関係のつながりの一部分であるアセットバンドルの再ビルドが必要であると考えた場合、BuildAssetBundleOptions.DeterministicAssetBundle のオプションを有効化してビルドする必要があることに注意してください。これによりアセットを識別する内部 ID の値は、バンドルが再ビルドされるたびに同じであることを保証します。
この方法でアセットバンドルをビルドすると、そこに含まれるオブジェクトは、アセットバンドルファイル名、アセットの GUID 、アセット内のオブジェクトのローカル ID を利用して計算された 32 ビットのハッシュコードになります。そのため、リビルド時は同じファイル名を使うようにしてください。多数のオブジェクトを持つことは、アセットバンドルのビルド時に、ハッシュの衝突によって Unity が妨げられる可能性がある事も覚えておいてください。
BuildPipeline.BuildAssetBundle のパラメータとして直接シェーダーが参照されている、もしくは BuildAssetBundleOptions.CollectDependencies オプションから間接的に参照された場合、そのシェーダーのコードはアセットバンドルに含まれる事になります。これは、 BuildAssetBundle を単体で使用して作成したアセットバンドルでは、参照されたシェーダーが、生成されたバンドルすべてに内包されてしまう事に起因する問題です。例えば、異なるバージョンのシェーダーをミックスした場合、シェーダーを修正した後ですべてのバンドルをリビルドすることになるので、コンフリクトが起こります。BuildPipeline.PushAssetDependencies を使うと、バンドル単体にシェーダーを分け、この問題を避ける事ができます。また、これならシェーダーバンドルのアップデートだけで済みます。このやり方を実現するための例示のように、必要なシェーダーへの参照を含んだプレハブを作成することができます。
using UnityEngine;
public class ShadersList : MonoBehaviour {
public Shader[] list;
}
空のオブジェクトを作成してスクリプトを割り当て、シェーダーをリストに追加してプレハブを作成してください(“ShadersList”)。これで、すべてのバンドルを生成してシェーダーのバンドルを更新するエクスポーターを作成することができます。
using UnityEngine;
using UnityEditor;
public class Exporter : MonoBehaviour {
[MenuItem("Assets/Export all asset bundles")]
static void Export() {
BuildAssetBundleOptions options =
BuildAssetBundleOptions.CollectDependencies |
BuildAssetBundleOptions.CompleteAssets |
BuildAssetBundleOptions.DeterministicAssetBundle;
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/ShadersList.prefab"), null, "Data/ShadersList.unity3d", options);
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Scene1.prefab"), null, "Data/Scene1.unity3d", options);
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Scene2.prefab"), null, "Data/Scene2.unity3d", options);
BuildPipeline.PopAssetDependencies();
BuildPipeline.PopAssetDependencies();
}
[MenuItem("Assets/Update shader bundle")]
static void ExportShaders() {
BuildAssetBundleOptions options =
BuildAssetBundleOptions.CollectDependencies |
BuildAssetBundleOptions.CompleteAssets |
BuildAssetBundleOptions.DeterministicAssetBundle;
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/ShadersList.prefab"), null, "Data/ShadersList.unity3d", options);
BuildPipeline.PopAssetDependencies();
}
}
シェーダーバンドルは必ず最初に読み込んでください。この方法のひとつの難点は、オブジェクトが多すぎるときに、ハッシュの衝突が原因でオプション BuildAssetBundleOptions.DeterministicAssetBundle に問題が生じることがあります。その場合、ビルドは機能しなくなり、シェーダーバンドルだけで更新することができなくなります。このようなときは、そのオプションを除いて、すべてのアセットバンドルをビルドし直さなければなりません。