MRが楽しい

MRやVRについて学習したことを書き残す

TriLib2を使ってHoloLens2アプリでFBXファイルを動的読み込みする

本日は HoloLens2 の技術調査枠です。
TriLib2を使ってHoloLens2アプリでFBXファイルの動的(Runtime)読み込みを試したので記事にします。
f:id:bluebirdofoz:20210827003517j:plain

TriLib2

TriLib2 は、クロスプラットフォームのランタイム3Dモデルインポーターです。
ファイルシステム、Web またはカスタムソースからのモデルインポートが可能です。

読込可能なファイル形式 FBX、OBJ、GLTF2、STL、PLY、3MF、ZIP
対応プラットフォーム WindowsMacLinux、UWP、AndroidiOSWebGL

assetstore.unity.com
f:id:bluebirdofoz:20210827002743j:plain

TriLib2 は有料アセットです。
利用するにはアセットを購入する必要があります。
f:id:bluebirdofoz:20210827002803j:plain

サンプルアプリの作成

TriLib2 を使って FBX ファイルを動的読み込みする HoloLens2 アプリを作成します。

MRTKのインポートと基本設定

MRTK を利用して HoloLens2 用のサンプルプロジェクトを作成しました。
こちらの手順の詳細は以下の記事を参照して実施してください。
bluebirdofoz.hatenablog.com
f:id:bluebirdofoz:20210827002825j:plain

TriLib2のインポート

UnityPackageManager から TriLib2 のインポートを行います。
メニューから[Window -> PackageManager]で PackageManager ウィンドウを開きます。
f:id:bluebirdofoz:20210827002835j:plain

[Package]のプルダウンを開き、[MyAssets]を選択します。
右下の数字をクリックして全ての MyAssets を表示します。
f:id:bluebirdofoz:20210827002846j:plain

一覧に表示された TriLib2 を選択し、[Import]ボタンをクリックします。
f:id:bluebirdofoz:20210827002857j:plain

ImportUnityPackage ウィンドウが開くので[Import]を実行します。
f:id:bluebirdofoz:20210827002913j:plain

インポート時、APIUpdateRequired のダイアログが表示された場合は[I Made a Backup. Go Ahead!]を選択します。
f:id:bluebirdofoz:20210827002938j:plain

これで TriLib2 のインポートは完了です。
f:id:bluebirdofoz:20210827002952j:plain

モデル読み込みのサンプルコード

指定のファイルパスの FBX ファイルを読み込むサンプルコードを作成しました。
ファイル名を指定して FileLoad() 関数を呼び出すと FBX ファイルの動的読み込みを行います。
・FBXLoader.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// TriLib の参照
using TriLibCore;

public class FBXLoader : MonoBehaviour
{
    /// <summary>
    /// FBXファイルの動的読み込み
    /// </summary>
    /// <param name="a_FileName">ファイル名</param>
    public void FileLoad(string a_FileName)
    {
        // FBX ファイルのみ処理する
        if (System.IO.Path.GetExtension(a_FileName) != ".fbx") return;

        // 実行環境に応じて参照するファイルパスを取得する
        string filepath = System.IO.Path.Combine(FileDirectoryPath(), a_FileName);

        // ロードの設定情報を作成する(今回はデフォルト設定)
        AssetLoaderOptions assetLoaderOptions = AssetLoader.CreateDefaultLoaderOptions();

        // ファイルシステムからのロードを実行する
        AssetLoader.LoadModelFromFile(filepath, OnLoad, OnMaterialsLoad, OnProgress, OnError, null, assetLoaderOptions);
    }

    /// <summary>
    /// <summary>
    /// モデルの読み込みの進行状況が変化したときに呼び出されるイベント
    /// </summary>
    /// <param name="assetLoaderContext"></param>
    /// <param name="progress"></param>
    private void OnProgress(AssetLoaderContext assetLoaderContext, float progress)
    {
    }

    /// <summary>
    /// エラー発生時に呼び出されるイベント
    /// </summary>
    /// <param name="contextualizedError"></param>
    private void OnError(IContextualizedError contextualizedError)
    {
    }

    /// <summary>
    /// 全ての GameObject が読み込まれたときに呼び出されるイベント
    /// </summary>
    /// <param name="assetLoaderContext"></param>
    private void OnLoad(AssetLoaderContext assetLoaderContext)
    {
        // ロードされたGameObjectを取得する
        GameObject loadedGameObject = assetLoaderContext.RootGameObject;

        // この時点ではマテリアルとテクスチャの読み込みが完了していない可能性があるため
        // オブジェクトを非表示にしておく
        loadedGameObject.SetActive(false);
    }

    /// <summary>
    /// マテリアルとテクスチャを含む全ての読み込みが完了したときに呼び出されるイベント
    /// </summary>
    /// <param name="assetLoaderContext"></param>
    private void OnMaterialsLoad(AssetLoaderContext assetLoaderContext)
    {
        // ロードされたGameObjectを取得する
        GameObject loadedGameObject = assetLoaderContext.RootGameObject;

        // この時点で全てのリソースの読み込みが完了しているのでオブジェクトを表示する
        loadedGameObject.SetActive(true);

        // カメラの正面1mの位置にオブジェクトを配置する
        loadedGameObject.transform.position = Camera.main.transform.position + (Camera.main.transform.forward * 1.0f);
    }

    /// <summary>
    /// データ保存ディレクトリパス
    /// 実行環境によって参照ディレクトリを変更する
    /// </summary>
    private string FileDirectoryPath()
    {
        string directorypath = "";
#if WINDOWS_UWP
        // HoloLens上での動作の場合、LocalAppData/AppName/LocalStateフォルダを参照する
        directorypath = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
#else
        // Unity上での動作の場合、Assets/StreamingAssetsフォルダを参照する
        directorypath = UnityEngine.Application.streamingAssetsPath;
#endif
        return directorypath;
    }
}

適当なオブジェクトに作成したスクリプトを設定します。
f:id:bluebirdofoz:20210827003122j:plain

Assets からシーンに MRTK の[PressableButtonHoloLens2_64x64.prefab]のボタンオブジェクトを配置します。
[OnClick]にサンプルコードの FileLoad() 関数を指定し、ボタン押下時にファイル読み込みが行われるようにしました。
f:id:bluebirdofoz:20210827003135j:plain

エディター上での動作確認

FBX ファイルのテストデータを作成し、まずエディター上での動作確認を実施してみます。

テストデータの作成

今回は Blender で FBX のテストデータを作成しました。
Suzanne モデルを凡そ 40 cm サイズに調整しました。
f:id:bluebirdofoz:20210827003148j:plain

メニューから[ファイル -> エクスポート -> FBX(.fbx)]で出力ウィンドウを開きます。
[トランスフォームを適用]の設定にチェックを入れておくと、回転軸が Unity と同じ形式に修正されます。
ファイル名を指定して[FBXをエクスポート]で出力します。
f:id:bluebirdofoz:20210827003202j:plain

Unityエディターでの読み込みフォルダ

Unity エディターで動作させた場合は、Assets/StreamingAssets フォルダを参照します。
StreamingAssets フォルダを作成し、FBX ファイルを配置します。
f:id:bluebirdofoz:20210827003215j:plain

動作確認

シーンを再生して動作を確認します。
f:id:bluebirdofoz:20210827003228j:plain

ボタンを押下すると FBX ファイルが読み込まれ、目の前に3Dモデルが表示されます。
f:id:bluebirdofoz:20210827003241j:plain

HoloLens2上での動作確認

次にアプリケーションを HoloLens2 にデプロイして、HoloLens2 での動作確認を実施してみます。

アプリケーションの起動

アプリケーションをデプロイして起動します。
f:id:bluebirdofoz:20210827003256j:plain

HoloLens2での読み込みフォルダ

するとアプリケーションのローカルフォルダが作成されるので、そこに FBX ファイルをアップロードします。
バイスポータルの[FileExplorer]からアプリケーションの[LocalState]フォルダを開きます。
f:id:bluebirdofoz:20210827003307j:plain

FBX ファイルを指定して[Upload]を実行します。
f:id:bluebirdofoz:20210827003320j:plain

これで FBX ファイルの配置は完了です。
f:id:bluebirdofoz:20210827003330j:plain

FBXファイル読み込みの実行

HoloLens2 のアプリケーションに戻り、ボタンをタップします。
FBX ファイルが読み込まれ、目の前に3Dモデルが表示されました。
f:id:bluebirdofoz:20210827003341j:plain

参考ページ

qiita.com