この項では、AssetBundle (アセットバンドル) を使用したプロジェクトでよくある問題をいくつか解説しています。
Unity のアセットバンドル システムは、オブジェクトがアセットバンドルにビルドされる際に、そのオブジェクトの全ての依存を特定します。これは アセットデータベースによって行われます。この依存情報は、そのアセットバンドルに含まれる一揃いのオブジェクトを特定するために使用されます。
アセットバンドルへの割り当てはアセットレベルで行われます。アセットバンドルに明示的に割り当てられたアセット内のオブジェクトは、その 1 つのアセットバンドルにのみビルドされます。BuildPipeline.BuildAssetBundles のどのシグネチャを呼び出すかによって、アセットの AssetImporter.assetBundleName プロパティに空でない文字列を設定するか、AssetBundleBuild.assetNames に列挙することでアセットが “明示的に割り当て” られます。
アセットバンドルで明示的に割り当てられないアセットの一部であるオブジェクトは、それを参照するオブジェクトを含む各アセットバンドルに含まれます。
つまり、 2 つのことなるオブジェクトが 2 tsの異なるアセットバンドルに割り当てられていて、その両方が共通の依存関係オブジェクトへの参照を持つ場合、その依存関係オブジェクトは両方のアセットバンドルにコピーされます。重複した依存関係は、インスタンス化も行なわれます。つまり、依存関係オブジェクトの 2 つのコピーが異なる識別子を持つ異なるオブジェクトと認識されます。その結果、アプリケーションの アセットバンドルの合計サイズが大きくなります。また、アプリケーションがその オブジェクトの両方の親をロードする場合は、オブジェクトの 2 つの異なるコピーがメモリーにロードされることになります。
この問題の解決方法はいくつかあります。
異なるアセットバンドル内にビルドされた複数のオブジェクトが依存を共有しないようにする。依存を共有するオブジェクトは、その依存を重複させることなく同じアセットバンドル内に配置することができます。
同じ依存を共有する複数のアセットバンドルが同時に読み込まれないようにアセットバンドルを分類する。
全ての依存アセットが、その所属するアセットバンドル内に確実にビルドされるようにする。これによりアセットの重複が起きる可能性は無くなりますが、複雑な状況が発生します。アプリケーションは、異なるアセットバンドル間における依存をトラッキングし、 AssetBundle.LoadAsset APIs の呼び出しが行われる前に正しいアセットバンドルが確実に読み込まれようにしなければなりません。
オブジェクトの依存関係は、UnityEditor 名前空間にある AssetDatabase API を介して追跡されます。名前空間が示唆するように、この API は Unity エディターでのみ利用可能で、ランタイムでは利用できません。AssetDatabase.GetDependencies を使用すると、特定のオブジェクトまたはアセットの直下の依存関係をすべて見つけることができます。これらの依存関係は、それ自体の依存関係を持つ可能性があるため、再帰的な計算になる可能性があることに注意してください。 アセットバンドルへのアセットの割り当ては、BuildPipeline.BuildAssetBundles を呼び出す際に AssetBundleBuild 構造体の配列を渡して明示的に定義するか、AssetImporter API を使用して問い合わせることができます。アセットバンドルの直接的または間接的な依存関係がすべてアセットバンドルに割り当てられていることを確認したり、アセットバンドルに割り当てられていない依存関係を 2 つのアセットバンドルが共有しないことを確認したりするエディタースクリプトを記述できます。
ノート: Addressables パッケージを使用してアセットバンドルをビルドする場合、Addressables Analyze
ウィンドウを使用して、重複するアセットを見つけることができます。
以下のセクションでは、 アセット依存の計算コードを自動生成のスプライトアトラスと併用した場合に起こる特異な現象について解説します。
自動生成されたスプライトアトラスは全て、その生成元のスプライトオブジェクトが含まれるアセットバンドルに割り当てられます。スプライトオブジェクトが複数のアセットバンドルに割り当てられる場合、そのスプライトアトラスは単一のアセットバンドルに割り当てられるのではなく、複製されます。スプライトオブジェクトがアセットバンドルに割り当てられていない場合、そのスプライトアトラスも、アセットバンドルに割り当てられません。
スプライトアトラスの複製を確実に防ぐためには、同じスプライトアトラスにタグ付けされた全てのスプライトが、確実に同じアセットバンドルに割り当てられるようにしてください。
Android のエコシステムではデバイスが極度に断片化されるため、テクスチャをいくつかの異なる形式に圧縮する必要が頻繁に生じます。全ての Android デバイスは ETC1 に対応していますが、 ETC1 はアルファチャンネルを持ったテクスチャには対応していません。 OpenGL ES 2 に対応する必要のないアプリケーションの場合、問題を解決する最もシンプルな方法は、ETC2 を使用することです。 ETC2 には全ての Android OpenGL ES 3 が対応しています。
ほとんどのアプリケーションでは、ETC2 非対応の古いデバイスへの配信が必要になります。この問題の解決策のひとつは、AssetBundle Variants を使用することです(そのほかの方法については、Unity の Android 向け最適化ガイドをご参照ください)。
AssetBundle Variant を使用するには、 ETC1 を使用してクリーンに圧縮できないテクスチャは全て、テクスチャ専用のアセットバンドル内に分離する必要があります。次に、 DXT5 や PVRTC、ATITC などの、vendor-specificのテクスチャ圧縮形式を使用して、Android エコシステムにおける ETC2 非対応のスライスに対応するために、これらのアセットバンドルのバリアントを十分量作成します。それぞれの AssetBundle Variant に関して、それに含まれるテクスチャの TextureImporter 設定を、そのバリアントに適した圧縮形式に変更してください。
ランタイムでは、各種テクスチャ圧縮形式への対応は SystemInfo.SupportsTextureFormat API で判定できます。この情報は、対応された形式で圧縮されたテクスチャを含む AssetBundle Variant の選択と読み込みに使用されます。
Android のテクスチャ圧縮形式についての詳しい情報は こちらを参照してください。。
アセットバンドルをビルドすると、Unity はそのバンドル内の情報を使用して、コンパイルするシェーダーバリアントを選択します。これには、アセットバンドル内のシーン、マテリアル、Graphics Settings、ShaderVariantCollections に関する情報が含まれます。
別々のビルドパイプラインは、他のパイプラインから独立して独自のシェーダーをコンパイルします。プレイヤービルドと Addressable ビルドの両方がシェーダーを参照する場合、Unity はシェーダーの 2 つの別個のコピーを各パイプラインに 1 つずつコンパイルします。
この処理では、キーワード、テクスチャ、コード実行による変更などのランタイム情報は考慮されません。特定のシェーダーをビルドに加えたい場合は、必要なシェーダーを含む ShaderVariantCollection を加えるか、グラフィックス設定の Always Included Shaders リストに加えて手動でシェーダーをビルドに入れます。