本日はUnity技術の調査枠です。
前回、MMDモデルをプロジェクトに取り込む技術について調査を行い、目論見は成功しました。
bluebirdofoz.hatenablog.com
息抜きやモチベーションアップに操作キャラクタを差し替えると、アプリ作成はより捗りそうです。楽しい。
しかし、作業の効率化という点ではMMDモデルの扱い難しさがネックになります。
今後、アプリを公開する際、わざわざMMDモデルをプロジェクトから削除するのは面倒ですし。
息抜きのたびに新キャラクタを追加していたらアプリの容量がとんでもないことになります。
そこで役に立ちそうなのが「AssetBundle」という機能です。
docs.unity3d.com
「AssetBundle」とはUnityプロジェクトのリソース群である「Asset」を動的に読み込む機能となります。
つまり、アプリ本体と3Dモデルのデータを別々に管理することで、アプリ本体の不要な再ビルドやデータ容量の増加が防げます。
携帯などの商用アプリで、アプリそのもののアップデートをしなくても、キャラ追加のアップデートが自動で走ったりしますが、この機能を利用しているものもあるようです。
hololens上のUWPアプリでは本機能は利用可能でしょうか。検証開始です。
まずは本機能を使った、簡単な3Dオブジェクト表示アプリを作ってみます。
3Dモデルに以前使ったSpatialMappingで取得した部屋の3Dデータを使います。
bluebirdofoz.hatenablog.com
データを差し替えるだけで、様々な部屋の間取りを見れるアプリなんて、言葉にするとテストアプリの割りにはシャレオツです。
マップの頂点数やファイルサイズが大きい場合は、事前にSpatialMappingのデータはBlenderで頂点数を減らしておきましょう。
bluebirdofoz.hatenablog.com
ただ、前回利用したMMDモデルを調べてみたところ、キャラクタ1体で9万個の頂点数だったので、1マップずつの表示ならそれくらいは許容範囲っぽいです。
まずは以下を参考に「AssetBundle」の作成と読み込みを試してみます。
tsubakit1.hateblo.jp
ビルド時の関数が古くなっているので注意です。最新の記法は以下になります。
docs.unity3d.com
「AssetBundle」のビルド用に、下記のコードを用意しました。
・CreateAssetBundles.cs
using UnityEditor; public class CreateAssetBundles { [MenuItem ("Assets/Build AssetBundles")] static void BuildAllAssetBundles () { BuildPipeline.BuildAssetBundles ("Assets/AssetBundles", BuildAssetBundleOptions.None, BuildTarget.WSAPlayer); } }
hololensで「AssetBundle」を利用する場合、BuildTargetは"BuildTarget.WSAPlayer"となります。
「AssetBundle」はアプリ本体と別ビルドになるため、利用する媒体ごとにビルド設定の変更が必要です。
上記のコードを作ったら、「Assets/AssetBundles」ディレクトリを作成して、Unityのメニューから「Assets」→「Build AssetBundles」を実行します。
因みにここでは「MappingObject」フォルダを「AssetBundle」に設定し、"mappingobject"としてビルドするよう設定を行っています。
実行すると「Assets/AssetBundles」ディレクトリに「AssetBundles」ファイルと用意したAssetBundleファイルが生成されます。
マニュフェストファイルとバイナリファイルが存在し、マニュフェストファイルを見ると中の構成が確認できます。
今回は"mappingobject"Assetが作成されていることが分かります。
AssetBundleへのアクセス方法はその目的からWEB経由がよく使われますが、今回はローカルファイルへのアクセスを使います。
hololensにインストールされたアプリ本体が、hololens内のファイルを読み込んで、モデルを表示するイメージです。
docs.unity3d.com
そして「AssetBundle」の読み込みと表示用に、下記のコードを作成しました。
・LoadFromFileAsync.cs
using UnityEngine; using System.Collections; using System.IO; public class LoadFromFileAsync : MonoBehaviour { IEnumerator Start() { string bundlepath = Path.Combine(Application.streamingAssetsPath, "mappingobject"); AssetBundleCreateRequest bundleLoadRequest = AssetBundle.LoadFromFileAsync(bundlepath); yield return bundleLoadRequest; AssetBundle myLoadedAssetBundle = bundleLoadRequest.assetBundle; if (myLoadedAssetBundle == null) { Debug.Log("Failed to load AssetBundle!"); yield break; } AssetBundleRequest assetLoadRequest = myLoadedAssetBundle.LoadAssetAsync<GameObject>("ROOM"); yield return assetLoadRequest; GameObject prefab = assetLoadRequest.asset as GameObject; Instantiate(prefab); myLoadedAssetBundle.Unload(false); } }
記事が長くなりました。一旦ここで記事を分けます。実装を完了したので、次は実動作確認編です。