Unity AssetBundlesでモデルをダウンロードできるようにしてみた
Unityではモデルやテクスチャなどコード以外のデータをAssetBundlesという仕組みで管理できます。ユーザーが最新のデータをダウンロードすることでアプリのアップデートなしでモデルや素材の変更ができます。
概要
今回の記事でやること
前回作成した平面検出UnityアプリをAssetBundleに対応します。ボールのプレハブをサーバーからダウンロードするように変更して、アプリの更新なしでデータが変更されるか確認します。サーバーはPythonでローカル環境に構築します。
開発環境
- OS: macOS Monterey
- Unity Version:2020.3.20f1
- C#エディター: Visual Studio 2019 for Mac
- Python: 3.9.7
AssetBundle対応
AssetBundleを有効にする
AssetBundleを有効にするためにはコードを記述する必要があります。
- ProjectからAssetsを選択 > [Create] > [Folder] > Editorフォルダを作成
- Editorフォルダ内から [Create] > [C# Script] > ファイル名をCreateAssetBundleに変更
- 作成したCreateAssetBundleをダブルクリックして以下のように変更して保存
CreateAssetBundle.cs
using System.IO; using UnityEditor; using UnityEngine; public class CreateAssetBundles : MonoBehaviour { [MenuItem("Assets/Build AssetBundles")] static void BuildAllAssetBundles() { string assetBundleDirectory = "Assets/StreamingAssets"; if (!Directory.Exists(Application.streamingAssetsPath)) { Directory.CreateDirectory(assetBundleDirectory); } BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget); } }
ボールのプレハブをAssetBundleで管理するように変更する
- Shpereを選択 > Inspector最下部のAssetBundleドロップダウンを選択 > [New]を選択 > [testbundle]を入力
これでこのプレハブはAssetBundleでの管理対象になります。AssetBundleをビルドするとAssets/StreamingAssetsフォルダが生成されます。
- メニューから [Assets] > [Build AssetBundles]
データをサーバーからダウンロードするプログラムを作成する
今回はローカル環境にサーバーを立てるのでPCのIPを調べておきます。
データをダウンロードしてきてGameObjectをロードするプログラムを作成して保存します。
BundleWebLoader.cs
using System; using System.Collections; using UnityEngine; using UnityEngine.Networking; public class BundleWebLoader : MonoBehaviour { private string bundleUrl = "http://192.168.50.68:8000/assetbundles/testbundle"; private string assetName = "Sphere"; public IEnumerator GetBundle(Action<GameObject> callback) { UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(bundleUrl); yield return www.SendWebRequest(); if (www.result != UnityWebRequest.Result.Success) { Debug.LogError("Failed to download AssetBundle"); yield break; } else { AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www); callback(bundle.LoadAsset(assetName) as GameObject); bundle.Unload(false); } } }
アプリ起動時にオブジェクトをダウンロードするようにプログラム変更
アプリ起動時にAssetBundleをサーバーからダウンロードするようにプログラムを変更します。
PlaneDetection.cs
using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.ARFoundation; using UnityEngine.XR.ARSubsystems; public class PlaneDetection : MonoBehaviour { ARRaycastManager raycastManager; BundleWebLoader loader; // ダウンロードしてきたSphere GameObject instantiate; public delegate void Callback(Action<GameObject> gameObject); private void Awake() { raycastManager = GetComponent<ARRaycastManager>(); } void Start() { loader = new BundleWebLoader(); // ダウンロード開始 StartCoroutine(loader.GetBundle((GameObject obj) => { // ダウンロードしたGameObject instantiate = obj; })); } void Update() { if (Input.touchCount == 0 || Input.GetTouch(0).phase != TouchPhase.Ended) { return; } var hits = new List<ARRaycastHit>(); if (raycastManager.Raycast(Input.GetTouch(0).position, hits, TrackableType.PlaneWithinPolygon)) { var hitPose = hits[0].pose; // ダウンロードに成功していればインスタンス化 if(instantiate != null) { Instantiate(instantiate, hitPose.position, hitPose.rotation); } } } }
ローカルサーバーを準備する
AssetBundle内のファイルを配置する
サーバーを起動したいフォルダ内にStreamingAssetsフォルダをコピーして、フォルダ名をassetbundlesに変更します。
今回はPythonでローカル環境にサーバーを立てます。Terminalで任意フォルダに移動してから以下コマンドでサーバーを立ち上げます。ポートを指定しない場合、設定は8000になります。
python3 -m http.server
※事前にウェブブラウザでプログラム内で設定したURLにアクセスしてファイルがダウンロードできることを確認してください。
アプリの実行
アプリをビルドし実行します。スクリーンショットは平面にボールを置いた結果です。
プレハブを変更して、再度アップロードする
ここからは、プレハブのマテリアル変更がアプリの再インストールなしで適用されるのかを確認します。
- メニューから [Assets] > [Create] > [Material] ファイル名をSphereMaterialに変更
- Sphereを選択から Main MapsのAlbedo横の色を選択し任意の色に変更
- SphereMaterialをSphereプレハブにドラッグ&ドロップするとマテリアルが適用されます
再度AssetBundleをビルドします。
- メニューから [Assets] > [Build AssetBundles]
ビルドが終わったらサーバーを起動しているフォルダ内のファイルを入れ替えます。
色が変わるのを確認
アプリを再起動して平面にボールを置くと色が変わっているのが確認できました。
まとめ
AssetBundleを使えばアプリを更新せずにデータ変更できることが確認できました。アプリ配信後にデータを変更したい場面はありそうなので何かと使えそうです。