なにげにぷろぐらまーWiki - Unity3D - AssetBundle

目次

共有アセットバンドル


複数のアセットバンドルをビルドする時、それぞれに含まれるオブジェクトが共通のマテリアルを参照していても、
個々のアセットバンドルに別物として含まれてしまいます。
実際にアプリ内でそれらのアセットバンドルをロードし、個々のオブジェクトをロードすると、
先ほどの共通のマテリアルが重複してメモリ上に乗ります。

●アセット
 ・material_A
 ・object_A … material_A を参照
 ・object_B … material_A を参照

●アセットバンドル
 ・AssetBundle_A … material_A
                    object_A
 ・AssetBundle_B … material_A
                    object_B

     ↓ アセットバンドルを読み込んで、object_A, object_B をロードする

●メモリ
 ・AssetBundle_A からロード
   ・object_A
   ・material_A
 
 ・AssetBundle_B からロード
   ・object_B
   ・material_A' … 共通のマテリアルだったはずが、メモリ上に別物としてロードされる

UnityProfilerで見ると、マテリアルが2個増えることが確認できます。
Resources.FindObjectsOfTypeAll(typeof(Material)) でも確認できます。

※この問題を解決するために、アセットバンドルの依存関係を指定してビルドします。

依存関係を指定したビルド


Object[] m_commonRes;	// 共通リソース。共有アセットバンドルとしてビルドする。
Object[] m_objects;		// 共通リソースに依存するオブジェクト。

private void BuildAssetBundle()
{
	BuildTarget platform;	//プラットフォームはどこかから取得

	BuildAssetBundleOptions option =
		BuildAssetBundleOptions.CollectDependencies |
		BuildAssetBundleOptions.CompleteAssets |
		BuildAssetBundleOptions.DeterministicAssetBundle;	//※必須オプション。後で一部のアセットバンドルを再ビルドする際、オブジェクトの識別に利用される。
									//  毎回全てのアセットバンドルをビルドし直すのであれば、このオプションは不要と思われる。

	// 共有アセットバンドルの依存関係開始
	BuildPipeline.PushAssetDependencies();

	// 共有アセットバンドルをビルド
	BuildPipeline.BuildAssetBundle(null, m_commonRes, "common.unity3d", option, platform);

	for(int i = 0; i < m_objects.Length; ++i)
	{
		// 個別のアセットバンドルもPush, Pop で囲む
		BuildPipeline.PushAssetDependencies();
		
		// 個別のアセットバンドルをビルド
		// ※ここで共有アセットバンドルに含まれるリソースは、このアセットバンドルには含まれない。
		BuildPipeline.BuildAssetBundle(m_objects[i], new Object[]{m_objects[i]}, m_objects[i].name + ".unity3d", option, platform);
		
		BuildPipeline.PopAssetDependencies();
	}

	// 共有アセットバンドルの依存関係終了
	BuildPipeline.PopAssetDependencies();
}

使用例


※注意点
共有アセットバンドルの参照を保持した状態でそれに依存するアセットバンドルをロードすると、リソースを正しく参照できる。

AssetBundle m_commonAB;
Object[] m_commonObj;
Object m_objA;
Object m_objB;

IEnumerator Download()
{
    // 共有アセットバンドルの読み込み.
    WWW loader = WWW.LoadFromCacheOrDownload("common.unity3d", 0);
    while(!loader.isDone) yield return new WaitForSeconds(0.1f);

    // 共有アセットバンドル取得後、LoadAll()で一旦全てロードすることで、リソースがメモリ上に乗る。
    // アセットバンドルはUnload()せずに保持し続ける。
    commonAB = loader.assetBundle;
    m_commonObj = commonAB.LoadAll();

    //---- 依存しているアセットバンドル
    // AssetBundleA
    loader = WWW.LoadFromCacheOrDownload("AssetBundleA.unity3d", 0);
    while(!loader.isDone) yield return new WaitForSeconds(0.1f);

    // 必要なオブジェクトをロードして、アセットバンドルは即解放.
    AssetBundle ab = loader.assetBundle;
    m_objA = ab.Load("objectA", typeof(GameObject));
    ab.Unload(false);
    
    // AssetBundleB
    loader = WWW.LoadFromCacheOrDownload("AssetBundleB.unity3d", 0);
    while(!loader.isDone) yield return new WaitForSeconds(0.1f);
    
    ab = loader.assetBundle;
    m_objB = ab.Load("objectB", typeof(GameObject));
    ab.Unload(false);
}

参考サイト


Unity公式:アセット依存関係の管理 / Managing asset dependencies
http://docs-jp.unity3d.com/Documentation/Manual/ma...

keijiroさん:アセットバンドルとシェーダー
https://github.com/keijiro/unity-shader-bundle