はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】今更ながらAssetBundleの基礎的な使い方を学んでみる

はじめに

以前Addressable Asset Systemについての基本操作の記事を書いたのですが、Asset Bundleの知識もマトモに得ずにけしからんと怒られてしまうかもしれないのでAsset Bundleの基礎を学んでいこうかなと思います。(Addressableは内部的にAssetBundleを利用している)
www.hanachiru-blog.com

また公式ドキュメントはこちら。
docs.unity3d.com

概要

Asset Bundleについての説明を公式ドキュメントより引っ張ってきます。

AssetBundle (アセットバンドル) はランタイムに読み込むプラットフォーム特有のコード以外のアセット (モデル、テクスチャ、プレハブ、オーディオクリップ、シーン全体) を含むアーカイブファイルです。アセットバンドルは互いの依存関係を示すことができます。例えば、あるアセットバンドル のマテリアルは他のアセットバンドルのテクスチャを参照できます。ネットワークを使った効果的な配布のために、アセットバンドルはその使用要件に応じてビルトインのアルゴリズムの中の 1 つで圧縮されます (LZMA と LZ4)。

アセットバンドルはダウンロードコンテンツ (DLC) に有用で、初期インストールサイズを削減し、エンドユーザーのプラットフォームのために最適化されたアセットを読み込み、ランタイムのメモリにかかる負担を軽減します。

アセットバンドル - Unity マニュアル

AssetBundleに格納するアセットとしてモデル、テクスチャ、プレハブ、オーディオクリップ、シーン全体が紹介されていますが、ScriptableObjectを格納することもできます。ただScriptableObjectを定義している.csファイル自体はプロジェクトのアセンブリに含まれていなければならないことに注意してください。

利用の流れ

Asset Bundleを利用するにあたって以下のフローを行います。

  • アセットバンドルにアセットを割り当てる
  • アセットバンドルをビルドする
  • アセットバンドルとアセットをロードする

またAsset Bundleは必ずリモートからダウンロードしなければならないわけではなく、ローカルに配置することもできます。

  • サーバーに配置したAsset Bundleをダウンロードして利用する
  • StreamingAssets内に配置したAsset Bundleを読み込んで利用する

後気をつけてほしい点としてBuildTargetというどのプラットフォーム向けにビルドするか設定しなければならず、指定したプラットフォーム以外だと利用できないことも注意してください。

  • StandaloneOSX
  • StandaloneWindows
  • iOS
  • Android
  • StandaloneWindows64
  • WebGL
  • WSAPlayer
  • StandaloneLinux64
  • PS4
  • XboxOne
  • tvOS
  • Switch
  • Stadia
  • CloudRendering
  • PS5

BuildTarget - Unity スクリプトリファレンス

加えて圧縮の仕方を指定することができ、以下の3つから選びます。(LZ4を利用する方が多いよう)

  • 非圧縮
  • LZMA
  • LZ4

アセットバンドルのビルド - Unity マニュアル

アセットバンドルにアセットを割り当てる

Projectビューより対象のアセットを選択し、Inspectorビューの下部にAsset Bundleと書かれた左にあるセクションをクリック、Newよりアセットバンドル名を指定します。

アセットの割り当て
アセットバンドル名を記述した様子

このときSampleFolder/Sampleのように/をつけることでフォルダー構造にすることができます。

アセットバンドルをビルドする

アセットバンドルをビルドするにはコードを書かなければいけません。正直めんどくさいですが、サンプルを公式ドキュメントより引用させていただきます。

using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        string assetBundleDirectory = "Assets/AssetBundles";
        if(!Directory.Exists(assetBundleDirectory))
        {
            Directory.CreateDirectory(assetBundleDirectory);
        }
        BuildPipeline.BuildAssetBundles(assetBundleDirectory, 
                                        BuildAssetBundleOptions.None, 
                                        BuildTarget.StandaloneWindows);
    }
}

https://docs.unity3d.com/jp/current/Manual/AssetBundles-Workflow.html

コードの説明をざっくりするとこんな感じ。

  • MenuItemでUnityの上にあるメニューバーにあるAssets/Build AssetBundlesを選択することで、メソッドを実行する
  • Assets/AssetBundlesフォルダ内にビルド後のファイルを出力する
  • BuildPipeline.BuildAssetBundlesでビルドを行う

BuildPipeline.BuildAssetBundlesの引数は結構色々と設定することができます。
Unity - スクリプティング API: BuildPipeline.BuildAssetBundle

一番気をつけてほしいのは前述もしましたがBuildTargetで、適切なものを選択してください。

またBuildAssetBundleOptions.Noneに関しては以下の記事が参考になるかと。
アセットバンドルのビルド - Unity マニュアル

メソッドを実行する

ビルドされたファイル群

AssetBundles
|--- AssetBundles
|--- AssetBundles.manifest
|--- samplefolder
            |--- sample
            |--- sample.manifest

Manifestファイル

上記のAssetBundles.manifestsample.manifestの中身を覗いてみましょう。

// sample.manifest
ManifestFileVersion: 0
CRC: 307180686
Hashes:
  AssetFileHash:
    serializedVersion: 2
    Hash: 46b1de024bbcb1a0d43b0604c3474f58
  TypeTreeHash:
    serializedVersion: 2
    Hash: 4df8c69f2c8a6ad9e3cbf82bb83e4dc3
HashAppended: 0
ClassTypes:
- Class: 28
  Script: {instanceID: 0}
- Class: 213
  Script: {instanceID: 0}
SerializeReferenceClassIdentifiers: []
Assets:
- Assets/Sprites/AssetBundle/assetbundle.png
Dependencies: []

sample.manifestには含まれるアセット、依存関係等の情報が書き込まれています。

// AssetBundles.manifest
ManifestFileVersion: 0
CRC: 1670162852
AssetBundleManifest:
  AssetBundleInfos:
    Info_0:
      Name: samplefolder/sample
      Dependencies: {}

対してAssetBundles.manifestにはアセットバンドルの関連情報と依存関係を表しています。

またドキュメントにmanifestファイルの読み込み方・利用の仕方の紹介がされていますね。
アセットバンドルを使いこなす - Unity マニュアル

AssetBundle ファイル

AssetBundlessampleAssetBundleファイルに該当します。

アセットバンドルファイルは複数のファイルを内部に持つアーカイブであり、バイナリデータです。

またAsset Bundleファイルに何が含まれるかについては以下のような説明がありました。

  • シリアル化したファイル。個々のオブジェクトに分割され、この 1 つのファイルに書き出されたアセットが含まれています
  • リソースファイル。特定のアセット (テクスチャとオーディオ ) 用に別々に格納されたバイナリデータのチャンクで、Unity が別のスレッドのディスクから効率的にロードできるようにします。

アセットバンドル - Unity マニュアル

AssetBundleファイル

アセットバンドルのビルド - Unity マニュアル

アセットバンドルとアセットをロードする

今回は分かりやすくローカルのStreamingAssetsからロードを行なってみます。

StreamingAssetsフォルダを作成し、先ほどビルドしたファイル群を移動させます。

StreamingAssets内に入れる

サンプルを参考にしながらコードを作成しました。

using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class LoadFromFileExample : MonoBehaviour
{
    [SerializeField] private Image image;
    private void Start() {
        // AssetBundleのメタ情報のロード
        var assetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "samplefolder/sample"));
        if (assetBundle == null) {
            Debug.Log("Failed to load AssetBundle!");
            return;
        }
        
        // テクスチャをメモリにロード
        var sprite = assetBundle.LoadAsset<Sprite>("assetbundle");

        image.sprite = sprite;
        
        // AssetBundleのメタ情報をアンロード
        assetBundle.Unload(false);
    }
}
実行した様子

また今回はAssetBundle.LoadFromFileを利用しましたが、以下の4種類が存在します。

  • AssetBundle.LoadFromMemoryAsync
  • AssetBundle.LoadFromFile
  • WWW.LoadfromCacheOrDownload
  • UnityWebRequestAssetBundle の DownloadHandlerAssetBundle (Unity 5.3 以降のもの)

アセットバンドルを使いこなす - Unity マニュアル

詳しくは上記記事を参照してみてください。

ひとこと

AssetBundleの基本しか触れませんでしたが、Unloadであったり依存解決であったりと難しい箇所がまだまだ潜んでいます。
qiita.com

今から利用するのであればUnity公式がAddressable Asset Systemを用意してくれているので、特に理由がなければそちらを使っていけば良いとは思います。