仮想と物理とエトセトラ

xRや物理とかごった煮の備忘録的技術ブログ

HoloLens2でxboxのコントローラを使う(Input System)

今回は、HoloLens2でxboxコントローラを使用する方法をメモします。
UnityのInput Systemで簡単に使用できるようなので試します。
Input SystemはこれまでのUnityの入力系と比べ新しく、拡張、カスタマイズが可能なものであると説明されています。

docs.unity3d.com

せっかくなので、コントローラを用いて下記で使用したVRMを歩かせることを目標とします。

xr-physics-work-etc.hatenablog.com

前提

今回の環境は以下です。

Unity 2019.4.31
MRTK 2.7.3

MRTKは既に導入済みとします。

準備

Input Systemを導入する

まずはInput Systemを導入します。
Input SystemはPackage Managerからインポートできます。
上部メニューのWindow → Pacakge managerを選択します。
f:id:napo909:20220213141934p:plain

Input Systemを見つけ、右下のInstallをクリックします。
f:id:napo909:20220213142006p:plain

Installを行うと再起動を求められるため、Yesをクリックします。
f:id:napo909:20220213142146p:plain

再起動が終わるとUnityの入力が新しいInput Systemに置き換わります。
しかし、MRTKのInput Simulatorでは古い入力方式を使用しているため、このままではPlayモードで動作確認が十分できません。
そのため、新旧両方使えるようにする必要があります。

上部メニューからFile → Build Settings...を選択し、Build Settingsウィンドウを表示します。
f:id:napo909:20220213142616p:plain

Build Settingsウィンドウ左下のPlayer Settings ...ボタンを押して、Project Settingsウィンドウを開きます。
f:id:napo909:20220213142643p:plain

Project SettingウィンドウのPlayer Setting、Other SettingsのActive Input Hnadlingを確認します。
Input Systemを導入したことでInput System Package (New)がアクティブになっていると思います。
MRTKではInput Manager(Old)を使用しているので、一番下のBothを選択します。
f:id:napo909:20220213142918p:plain

再度ウィンドウが表示され再起動を促されるので、Applyを押して再起動します。
f:id:napo909:20220213144012p:plain

これでInput Systemの導入ができました。

VRMモデルを歩かせる

今回はStarter Assets - Third Person Character Controllerを使用します。

assetstore.unity.com

Add to My Assetsを実施した後、Unity Projectに導入します。
f:id:napo909:20220213145059p:plain

導入したら、VRMモデルのAnimatorコンポーネントにAnimation Controllerとして、Assets -> StarterAssets -> ThirdPersonController -> Character -> Animations -> StarterAssetsThirdPersonをアタッチします。
f:id:napo909:20220213145543p:plain

次にThirdPerosonContollerコンポーネントをアタッチします。
すると、Character Controller, Player Inputコンポーネントが一緒にアタッチされます。
次にStarter Assets Inputsもアタッチします。
f:id:napo909:20220213150914p:plain

Player InputコンポーネントのActionsにStarterAssets、Defauilt SchemeXbox Controllerを設定します。
f:id:napo909:20220213150056p:plain

キャラクターのColliderを調整するために、Character ControllerのCenter, Radius, Heightを調整します。
f:id:napo909:20220213151522p:plain f:id:napo909:20220213151530p:plain

次にProject SettingsウィンドウのInput System PackageからSupported Devicesを選択します。
今回は使用するXbox Contorllerを選択します。
f:id:napo909:20220213150540p:plain

このままではキャラクターが無限に落ちていくので、Ground LayersにSpatial Awarenessを設定した上で、Spatial Awarenessを有効にします。
f:id:napo909:20220213151104p:plain f:id:napo909:20220213155700p:plain

また、初期位置として、Spatial Awarenessタグを付与したPlaneを配置し、アプリ起動時に落ちないようにします。
f:id:napo909:20220213152014p:plain

最後にそれでも落ちてしまった場合に復帰できるようにリセットボタンを用意します。
MRTK標準ボタンに下記スクリプトをアタッチし、初期位置に戻せるようにします。

  • ResetPos.cs
クリックで展開
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ResetPos : MonoBehaviour
{
    Vector3 pos = new Vector3(0, 0, 0);
    Quaternion rot = new Quaternion(0, 0, 0, 1);
    Vector3 scale = new Vector3(1, 1, 1);

    [SerializeField]
    Transform targetTransform;
    // Start is called before the first frame update
    void Start()
    {
        pos = targetTransform.position;
        rot = targetTransform.rotation;
        scale = targetTransform.localScale;
    }

    // Update is called once per frame
    public void ResetPosFunc()
    {
        targetTransform.position = pos;
        targetTransform.rotation = rot;
        targetTransform.localScale = scale;
    }
}

f:id:napo909:20220213153506p:plain

HoloLensにxboxコントローラをつなぐ

今回はBluetoothで接続しました。
xboxコントローラをペアリングモードにしたのち、HoloLensの設定からBluetoothを選択します。
バイスの追加からBluetoothまたはその他のデバイスを追加するを選択します。 f:id:napo909:20220213162504j:plain

「デバイスを追加する」画面からBluetoothを選択します。
f:id:napo909:20220213162614j:plain

今回接続したいXbox Wireless Controllerを選択すると、HoloLensに接続することができます。 f:id:napo909:20220213162822j:plain f:id:napo909:20220213162835j:plain

動作確認

無事コントローラでVRMモデルを操作することができました。
Spatialをつかっているので、現実空間の物体がColliderになり、そこにいるような感覚を得ます。
Starter AssetsのAnimatorを使っているためか肩の位置がややおかしいため、微調整するとなお見た目が良くなりそうです。

Input Systemを用いると、HoloLensでxboxコントローラの利用が簡単にできることがわかったので、次回以降バーチャルなラジコンなど実装してみようと思います。

PCにHoloLens2の映像を投影する(Miracast)

今回は小技的な手法をメモっておきます。
HoloLens2では、Device PortalのMixed Reality Captureでの映像共有のほかにMiracastでの映像共有が可能です。
最近のWi-Fi搭載のWindows PCでは、外部からの映像をPCで受信する「このPCへのプロジェクション」機能が有効です。
この機能ではWi-Fi機能を使用していますが、Wi-Fiルータへの接続は必要ないため外出先でのデモやほかの人との情報共有等に最適です。
また、後述しますが遅延も少ないので、オンラインミーティング等での画面共有でも使用できます。

docs.microsoft.com

「このPCへのプロジェクション」機能を用いることで、HoloLens2からの映像をPC側で表示することが簡単に実施できます。

準備

PC側の準備

まずは、PC側で「このPCへのプロジェクション」機能を有効にします。
f:id:napo909:20220206145020p:plain
Windowsの「設定」から「システム」を選択します。

f:id:napo909:20220206145911p:plain 「システム」メニューから「このPCへのプロジェクション」を選択します。
最初は各項目がグレーアウトしていると思います。
PCにオプション機能を追加する必要があるので、「オプション機能」をクリックします。

f:id:napo909:20220206150033p:plain
「オプション機能」ウィンドウが表示されたら「機能の追加」ボタンを押します。

f:id:napo909:20220206150150p:plain 「オプションを追加する」の検索窓に「ワイヤレス ディスプレイ」を入力するとプロジェクション機能に必要な機能が見つかります。
「ワイヤレス ディスプレイ」にチェックを入れ「インストール」ボタンを押します。

f:id:napo909:20220206150354p:plain しばらく待つとインストールが完了します。

f:id:napo909:20220206150903p:plain 「このPCへのプロジェクション」の設定に戻るとグレーアウトしていた項目が設定できるようになります。
一番上の項目を「セキュリティで保護されたネットワーク上のどこでも利用可能」か、「どこでも使える」に設定すればHoloLens2からの接続を受け入れることができるようになります。
f:id:napo909:20220206151034p:plain 最後に、「このPCへのプロジェクション」の設定画面上部の「このPCへのプロジェクション用の接続アプリを起動します」を選択します。
すると、「接続」ウィンドウが開き、接続待ち状態にできます。

HoloLens2側の準備

HoloLens2側で接続準備をします。

f:id:napo909:20220206152152j:plain 手首に表示されるボタンを押します。
表示されるホーム画面の右下のボタンを押下します。

f:id:napo909:20220206152808j:plain ワイヤレスディスプレイとして、接続先のPC名が表示されるのでタップして選択します。
これでPCへ画面送信が開始されます。

動作確認

PC側、HoloLens2側での準備を終えるとPCの画面にHoloLens2で閲覧している内容を表示できます。
f:id:napo909:20220206152934p:plain Device PortalのMixed Reality Captureと比べると少ない遅延で映像を共有することができます。
それぞれの端末同士のWi-Fi接続状況にもよりますが、あまり途切れることもなく快適に共有できます。

f:id:napo909:20220206153214j:plain HoloLens2側で接続中はホーム画面右下のボタンの表示が変わります。
映像共有をやめる場合は再度ボタンを押します。

これで手軽にHoloLens2中で閲覧している内容を、外から確認できました。

Vroid Studioから出力したVRMをHoloLens2で閲覧する

今回は、VRoid Studioで作成したアバターVRM出力し、HoloLens2で閲覧します。

vroid.com

VRoid Studioでは気軽にアバターが作成できるため、VRChatなどで用いられることが多いです。
私もアバターを作成してみたので、試しにHoloLens上で投影し、現実世界に召還してみます。

前提

今回の環境は以下です。

Unity 2019.4.31
MRTK 2.7.3

シーン中でMRTK用のConigureは設定済みとします。
また、VRoid Studioですでにモデルは作成済みとします。

準備

VRoid StudioからVRMファイルを出力する

まずは、VRoid StudioからVRMファイルを取得します。
モデルを開いた後の画面右上真ん中のボタンから、VRMエクスポートを選択します。
f:id:napo909:20220123164915p:plain

VRMエクスポート画面ではエクスポート時の設定を行えます。
ポリゴン数は4万ポリゴン数程度なので問題ないと思いますが、念のため「透明メッシュを削除する」にチェックを入れ、マテリアル数と解像度を削減しておきます。
設定が終わったら「エクスポート」ボタンを押します。
f:id:napo909:20220123165713p:plain

ボタンを押すとVRMの設定画面になります。
必須事項である「タイトル」、「作成者」を入力します。
配布する予定がある場合は、ほかの項目も入力します。
すべて設定が終わったら、一番下の「エクスポート」ボタンを押します。
f:id:napo909:20220123170005p:plain
f:id:napo909:20220123170040p:plain

次に表示されるウィンドウで保存場所を指定したら、VRMファイルの出力は完了です。

VRMファイルをUnityに取り込む

ここで、作成したVRMファイルをUnityに取り込みます。
VRMファイルは通常ではUnityに取り込むことができません。
そこで、UnityにVRMファイルを取り込むことを可能にする、UniVRMを使用します。
このアセットを使用すると、VRMを取り込み、Unityで使用できるPrefab化することができます。
下記リンクからUniVRM-[バージョン名].unitypackageをダウンロードします。
github.com

f:id:napo909:20220123170442p:plain

ダウンロードしたUnityPackageをUnityのProject Windowドラッグ&ドロップします。
ドラッグ&ドロップすると、Import Unity Package Windowが表示されるので、下端のImportボタンを押します。

Importが終わると、おすすめの設定をするように指示されるため、Accept Allで実行します。
f:id:napo909:20220123171259p:plain

Console Windowにエラーが出ていますが、Editor上で使用するGlb Importerが複数あるため発生しているものです。
アプリ実行には特に問題ないため、無視して問題ありません。
f:id:napo909:20220123171537p:plain

設定が終わると、上部メニューにVRM0が追加されます。
Import from VRM 0.xを選択することでVRMファイルを読み込むことができます。
最初にVRMファイルを読み込み、次にAsstsのどこに出力するか指定します。
Assetsフォルダ配下でフォルダを作成し、その中を出力先にすると散らからずに済みます。
f:id:napo909:20220123171739p:plain

f:id:napo909:20220123171843p:plain

正常に処理が終わると、出力先に指定したフォルダにVRMモデルから生成したPrefabが生成されます。
これで、Unity上でVRMモデルを取り扱えます。
試しにHierarchyにドラッグ&ドロップすると、Scene上に表示されます。
f:id:napo909:20220123172347p:plain

アニメーションを設定する

出力したモデルはそのままではTポーズをしているだけで味気ないので、アニメーションをさせます。
今回は、下記URLのUnity Animationを使用させていただきました。

booth.pm

ダウンロードしたファイルを解凍するとEmoteSet_Free_v130.unitypackageが入っているため、先ほどと同様にProject Windowドラッグ&ドロップします。
ドラッグ&ドロップするとImport Unity Pakcage Windowが表示されるので、Importボタンを押します。
f:id:napo909:20220123173257p:plain

正常にImportされると、Assets/Necocoyaフォルダが作成され、その中にAnimation用のファイルが配置されます。
f:id:napo909:20220123173611p:plain

今回は、Emote02/OneLoopDivisionのAnimation Contollerを使用します。
Animation Controllerをダブルクリックすると、Animation Windowが表示されるので、Parametersタブから使用したいアニメーションを選択します。今回は01_Tefuri3_OneLoopを選択します。
f:id:napo909:20220123174117p:plain

アニメーションがどのような動きをするかは、animファイルを選択した状態でInspector Windowの下端の再生ボタンから確認できます。
f:id:napo909:20220123174102p:plain

作成したモデルへのAnimation Controllerの適用は、モデルを選択した状態でInspector Window中のAnimatorコンポーネントControllerを設定することで実現できます。
f:id:napo909:20220123174356p:plain

そのままではモデル表示位置が初期状態の頭の位置と同じなので位置を微調整します。 また、つかんで移動できるように、Object ManipulatorCapsule Colliderをアタッチすれば準備完了です。 f:id:napo909:20220123175716p:plain

動作確認

無事、HoloLensで現実世界に投影することができました。
拡縮もできます。
VRM/MToonシェーダもSingle Pass Instancedに対応しているようで、両目でしっかり見えます。

Netcode for GameObjects (旧MLAPI)をHoloLensで使ってみる その2

今回は前回の続きです。

xr-physics-work-etc.hatenablog.com

前回、Hostとして使用したHoloLens2の頭位置は共有されましたが、Clientとして接続したUnityEditorでは共有できませんでした。
この問題を解消します。

下記記事によると、以前のMLAPIからの変更点として、NetworkTransformでは、Server側からのTransform共有ができないようです。
Client側から共有する方法として、ClientNetworkTransformを用いる方法があるようです。

xrdnk.hateblo.jp

今回は下記を元にClientNetworkTransformを用いてClient側からも頭の位置を共有できるようにします。

docs-multiplayer.unity3d.com

前提

今回の環境は以下です。

Unity 2020.3.16
MRTK 2.7.3
Netcode for GameObjects 1.0.0-pre.4

準備

まずは、ClientNetworkTransformを用意します。
ClientNetworkTransformはnet code for GameObjectsの標準APIとしては存在しません。
サンプルとして用意されているため、まずはそれを導入します。

Unity上部メニューの「Window」→「Package Manager」からPackage Managerウィンドウを開きます。
f:id:napo909:20220116155345p:plain

Package Managerウィンドウから、「Netcode for GameObjects」を選択すると左欄に「Samples」という項目があります。
「Samples」の文字列をクリックすると用意されているサンプルが展開されます。
そこに「ClientNetwork Transform」があるので、Importボタンを押して取得します。
f:id:napo909:20220116155625p:plain

正常に導入できると、Assets/Samples/Netcode for GameObjects/1.0.0-pre.4ClientNetworkTransformフォルダが作成されています。
f:id:napo909:20220116160337p:plain

ClientNetworkTransform/Scriptsフォルダ内にClientNetworkTransform.csがあります。
ClientNetworkTransform.csを見ると、以下の記載がありました。

クライアント側の変更に伴うtransformの同期に使用します。これにはホストも含まれます。所有者としての純粋なサーバーは、これではサポートされていません。常にサーバーが所有するようなトランスフォームには NetworkTransform を使用してください。 (Deepl翻訳)

github.com

これは、L34にあるように、サーバ側にクライアントが所有しているオブジェクトのTransformを送り、サーバ側で処理しているためです。
サーバ用アプリを用意する場合は、NetworkTransform、ホスト、クライアントで用いる場合はClientNetworkTransformを使うのがよさそうです。

ユーザ位置はサーバ側アプリで使用しないため、Playerプレハブにアタッチするコンポーネントを、ClientNetworkTrnasformに変更しました。

f:id:napo909:20220116171811p:plain

HoloLens→PC接続

PCではUnityEditorからInspectorを用いて接続先IPを設定できましたが、HoloLensではそうもいきません。
そのため、HoloLensをClientとしてHostであるPCに接続するために、InputFieldを用いて接続先IPを設定する口を用意しました。
f:id:napo909:20220116172013p:plain

前回使用したNetworkConnectButtonFunctions.csを改修し、Input Filedが更新された際にIPアドレスとして設定されるようにします。

  • NetworkConnectButtonFunctions.cs
クリックで展開
using UnityEngine;
using Unity.Netcode;
using Unity.Netcode.Transports.UNET;
public class NetworkConnectButtonFunctions : MonoBehaviour
{
    /// <summary>
    /// ネットワークマネージャ
    /// </summary>
    private NetworkManager networkManager;


    void Start()
    {
        // ネットワークマネージャインスタンス取得
        networkManager = NetworkManager.Singleton;
        if(networkManager == null)
        {
            this.gameObject.SetActive(false);
        }
    }

    /// <summary>
    /// ホストとして接続
    /// </summary>
    public void ConnectAsHost()
    {
        networkManager.StartHost();
    }

    /// <summary>
    /// サーバとして接続
    /// </summary>
    public void ConnectAsServer()
    {
        networkManager.StartServer();
    }

    /// <summary>
    /// クライアントとして接続
    /// </summary>
    public void ConnectAsClient()
    {
        networkManager.StartClient();
    }

    /// <summary>
    /// 接続切断
    /// </summary>
    public void Disconnect()
    {
        networkManager.Shutdown();
    }

    /// <summary>
    /// 接続先設定 <-------追加箇所
    /// </summary>
    /// <param name="ipString"></param>
    public void SetIP(string ipString)
    {
        networkManager.gameObject.GetComponent<UNetTransport>().ConnectAddress = ipString;
    }
}

f:id:napo909:20220116172143p:plain

動作確認

今回は、PC側をHost (Server + Client), HoloLens側をClientで接続しました。
PCでHost接続後、HoloLensからClient接続しています。
f:id:napo909:20220116172430g:plain

ClientNetworkTransform.csを用いることで、Clientの動きもHost (Server)側から確認することができました。
これで、HostもClientもお互いの動きを確認できます。

次回は、共有で重要な同じ物体をHost、Clinetで動かし、位置を共有することを試します。

Netcode for GameObjects (旧MLAPI)をHoloLensで使ってみる その1

今回は、Unity公式の共有フレームワークのNetcode for GameObjectsを触ってみます。

docs-multiplayer.unity3d.com

元になったMLAPIについては以前触れていますが、v.0.1.0からv.1.0.0になって変更点があると思われるので、確認の意味も込めて触れてみます。

xr-physics-work-etc.hatenablog.com

前提

Netcode for GameObjectsではUnity 2020.3, 2021.1, and 2021.2を推奨しているので、以下を使用します。

Unity 2020.3.16
MRTK 2.7.3

MRTKの導入~ HoloLensアプリ向けの設定は下記を参考にできます。

bluebirdofoz.hatenablog.com

Netcode for GameObjectsを導入する

公式のチュートリアルを元に実施します。

docs-multiplayer.unity3d.com

上部メニューのWindow→Pacakge ManagerからPackage Managerウィンドウを表示します。
f:id:napo909:20220109145039p:plain

Pakcage Managerウィンドウ左上の+ボタンを押して、Add package from git URL...を選択します。

f:id:napo909:20220109145502p:plain

出てくるInputFieldに下記文字列を入力してAddボタンを押します。
com.unity.netcode.gameobjects

f:id:napo909:20220109150233p:plain

正常に読み込まれると、リストにNetcode for GameObjectsが追加されます。
f:id:napo909:20220109150418p:plain

Packageを見てNetcode for GameObjectsフォルダが存在すれば正しく取り込まれています。
f:id:napo909:20220109151522p:plain

お試し実装

チュートリアルHello Worldをベースに、お試しで実装してみます。

まずはユーザを示すPrefabを作成します。
Scene上にSphereを追加し、NetworkObjectコンポーネントをアタッチします。
方向がわかるようにz方向のScaleを変更しておきます。
f:id:napo909:20220109152739p:plain

次に、ユーザ頭位置を示すようにMLAPIの際に使用したスクリプトを一部修正して作成し、アタッチします。
合わせて、Tramsformを共有対象とする、NetworkTransform もアタッチします。

xr-physics-work-etc.hatenablog.com

  • PlayerTracking.cs
クリックで展開
using UnityEngine;
using Unity.Netcode;
public class PlayerTracking : NetworkBehaviour
{

    // Update is called once per frame
    void Update()
    {
        if(IsOwner)
        {
            // 自オブジェクトの場合
            SetPlayerTransform();
        }


    }

    /// <summary>
    /// プレイヤー位置設定関数
    /// </summary>
    void SetPlayerTransform()
    {
        // カメラ位置にオブジェクトを移動
        this.transform.position = Camera.main.transform.position;
        this.transform.rotation = Camera.main.transform.rotation;
    }
}

f:id:napo909:20220109153627p:plain

作成したGameObjectをPlayerに名称を変更し、Assets中にドラッグ&ドロップしてPrefab化します。
Scene上のPlayer GameObjectは削除します。
f:id:napo909:20220109154327p:plain

次に、Scene上に空のGameObjectを作成し、NetworkManagerに名前を変更します。
作成したGameObjectにNetworkManagerコンポーネントをアタッチします。
f:id:napo909:20220109154424p:plain f:id:napo909:20220109154451p:plain

NetworkManagerコンポーネントのNetwork TransportプルダウンメニューからUNetTransportを選択します。
f:id:napo909:20220109154624p:plain

Network Prefabsリストのプラスボタンを押して、先ほど作成したPlayer Prefabを設定します。
また、Player Prefabの箇所にも同様に設定します。
f:id:napo909:20220109154934p:plain f:id:napo909:20220109154821p:plain

HoloLensからネットワーク接続するためのボタンを以前の記事を参考に作成します。
ボタンの配置など設定は下記と同じため参照して実施します。
xr-physics-work-etc.hatenablog.com HoloLens用の接続用ボタンを用意する

  • NetworkConnectButtonFunctions.cs
クリックで展開
using UnityEngine;
using Unity.Netcode;

public class NetworkConnectButtonFunctions : MonoBehaviour
{
    /// <summary>
    /// ネットワークマネージャ
    /// </summary>
    private NetworkManager networkManager;


    void Start()
    {
        // ネットワークマネージャインスタンス取得
        networkManager = NetworkManager.Singleton;
        if(networkManager == null)
        {
            this.gameObject.SetActive(false);
        }
    }

    /// <summary>
    /// ホストとして接続
    /// </summary>
    public void ConnectAsHost()
    {
        networkManager.StartHost();
    }

    /// <summary>
    /// サーバとして接続
    /// </summary>
    public void ConnectAsServer()
    {
        networkManager.StartServer();
    }

    /// <summary>
    /// クライアントとして接続
    /// </summary>
    public void ConnectAsClient()
    {
        networkManager.StartClient();
    }

    /// <summary>
    /// 接続切断
    /// </summary>
    public void Disconnect()
    {
        networkManager.Shutdown();
    }
}

f:id:napo909:20220109160933p:plain

プロジェクトをビルドする前に「Build Settings」→「Player Settings」→「Player」→「Publishing Settings」→「Capabilities」から下記にチェックを付けます。

  • InternetClientServer
  • PrivateNetworkClientServer

f:id:napo909:20210711120536p:plain

その後、ビルドを実施し、HoloLens2にアプリを入れます。

動作確認

PC-HoloLens間で動作確認します。
方法はMLAPIの時と同じです。

HoloLens2でアプリを起動したら、自分のIPアドレスを確認します。 (「自分のIP」のボイスコマンドやWi-Fiの詳細情報を確認)

確認したHoloLens2のIPアドレスをPC側のNetworkManagerオブジェクトのUNET TransportConnect Addressに設定します。

f:id:napo909:20220109163547p:plain

その後、HoloLens側でConnect As Host、PC側でConnect As Clientボタンを押して接続します。
正しく接続できると、各ユーザの頭の位置が球体で示されます。
HoloLens2をかぶっている頭を動かすと、PC側にも反映されます。

f:id:napo909:20220109163824g:plain

ただし、前回と異なりPC側(Client側)の頭位置が動いていませんでした。
※IsOwnerの扱いがMLAPIと異なってる?
この点は後日調査します。

MRTK(2.7.2)のExampleを試す その4 (Demos - Gltf)

今回は下記の続きです。

xr-physics-work-etc.hatenablog.com

前提

今回の前提は以下です。
Unity 2019.4.17f1
MRTK 2.7.2

準備

いつものようにPackage Managerからデモをインポートします。
f:id:napo909:20211219102128p:plain

Glb-Loading-Demo

このシーンは、インターネット上にあるglbモデルをUnityで取り扱えるオブジェクトとして表示するデモです。
f:id:napo909:20211219102800p:plain

glbまたはgltfは、JSONを用いて3Dモデルなどを表現する形式です。
標準のUnityでは動的読み込みなどできませんが、MRTKのGltf Importerを用いることで実現できます。

ja.wikipedia.org

GltfUtility.cs

このスクリプトで、gltfまたはglb形式のモデルデータを読み込み、Scene上に表示することができます。

github.com

staticなクラスのため、基本的にスクリプト中から使用することが前提です。
主な使い方の流れは以下です。

[1] 下記メソッドの中から適したものを使用してGltfObjectを取得する。

・ GetGltfObjectFromGlb(Byte[])
    glbファイルのバイト列からGltfObjectを取得する。  
・ GetGltfObjectFromJson(String)  
    Jsonファイルの内容(文字列)からGltfObjectを取得する。  
・ ImportGltfObjectFromPathAsync(String)
    ファイルパスからGltfObjectを取得する。(gltf, glbファイル両対応)  

[2] 取得したGltfObjectから下記メソッドをどちらか実施することで、Scene上にGltfオブジェクトを元にしたGameObjectを表示できる。

・ Construct()  
・ ConstructAsync()  

Rest.cs

このスクリプトは、直接Gltfのデモとして関係しているわけではないですが、初見のため取り扱っておきます。
このスクリプトに含まれるメソッドを使用することで、REST APIを用いてPOST, GETが実施できます。

github.com

staticなクラスのため、基本的にスクリプト中から使用することが前提です。
下記がよく使用されると思われるメソッドです。

  • GetAsync
    Getリクエストを送る場合に使用するメソッド。
    引数:
    query : URLを入力  
    headers : リクエストに使用するオプションのヘッダ  (オプション)  
    timeout : タイムアウト時間  (オプション)  
    downloadHandler : ダウンロード時に使用するオプションのハンドラ  (オプション)  
    readResponseData : ダウンロードハンドラの使用有無  (オプション)  
    certificateHandler : 証明書検証に使用するハンドラ  (オプション)  
    disposeCertificateHandlerOnDispose : UnityRequest破棄時に証明書検証ハンドラを破棄するか否か  (オプション)   
  • PostAsync
    POSTリクエストを送る場合に使用するメソッド。
    引数:
    query : URLを入力  
    formData : POSTするWWForm型のForm Data(※)  
    jsonData : POSTするJsonデータ(※)
    bodyData : POSTするbyte列のデータ(※)  
    headers : リクエストに使用するオプションのヘッダ  (オプション)  
    timeout : タイムアウト時間  (オプション)  
    readResponseData : ダウンロードハンドラの使用有無  (オプション)  
    certificateHandler : 証明書検証に使用するハンドラ  (オプション)  
    disposeCertificateHandlerOnDispose : UnityRequest破棄時に証明書検証ハンドラを破棄するか否か  (オプション)   
    (※):オーバーロードされているため、どれか1つまたは使用しない  
  • PutAsync
    PUTリクエストを送る場合に使用するメソッド。
    引数:
    query : URLを入力  
    jsonData : PUTするJsonデータ(※)
    bodyData : PUTするbyte列のデータ(※)  
    headers : リクエストに使用するオプションのヘッダ  (オプション)  
    timeout : タイムアウト時間  (オプション)  
    readResponseData : ダウンロードハンドラの使用有無  (オプション)  
    certificateHandler : 証明書検証に使用するハンドラ  (オプション)  
    disposeCertificateHandlerOnDispose : UnityRequest破棄時に証明書検証ハンドラを破棄するか否か  (オプション)   
    (※):オーバーロードされているため、どれか1つ使用する  
  • DeleteAsync
    DELETEリクエストを送る場合に使用するメソッド。
    引数:
    query : URLを入力  
    headers : リクエストに使用するオプションのヘッダ  (オプション)  
    timeout : タイムアウト時間  (オプション)  
    readResponseData : ダウンロードハンドラの使用有無  (オプション)  
    certificateHandler : 証明書検証に使用するハンドラ  (オプション)  
    disposeCertificateHandlerOnDispose : UnityRequest破棄時に証明書検証ハンドラを破棄するか否か  (オプション)   

Gltf-Loading-Demo

このシーンでは、ローカルファイルからglbモデルを読み込んで表示するデモです。
f:id:napo909:20211219112934p:plain
デモを正しく実行するには、Assetディレクトリ中にStreamingAssetsディレクトリを作成し、デモ用ディレクトリ中のModelsをコピーする必要があります。
コピーをするには、サンプルシーン中のGltfExampleオブジェクトにアタッチされている、TestGltfLoadingコンポーネントに付与されているボタンを押下すると、コピーが実施できます。
正常にファイルが配置できると、表示されている警告が消えます。
f:id:napo909:20211219112836p:plain

そのあと、Unity上で実行するとglbモデルから構成されたアボカドがシーン上に表示されます。

使用しているスクリプトは、先ほど紹介したGltfUtility.csのImportGltfObjectFromPathAsyncで共通しているため省略します。

キリが良いので今回はここまで。
次回はHandCoachのデモを取り扱います。

HoloLens2でJoyConのIMUを使ってみたかった(失敗)

今回はNintendo SwitchのJoyConをHoloLensで使用できるか試します。
使用できれば、加速度、ジャイロセンサを用いて何かしらできそうです。
※今回の記事はHoloLens上で正しく動作できていません。後々解決策がわかったら記事にします。

JoyConをUnityで取り扱う方法については下記を参考に実施します。

baba-s.hatenablog.com

前提

今回は下記環境で検証しています。
MRTKのインポートなどの設定は今回は省略し、JoyconLibの導入から始めます。
Unity 2019.4.17
MRTK 2.7.2
JoyconLib 0.6

準備

まずはJoyconLibのUnityPackageを下記からダウンロードします。

github.com

f:id:napo909:20211212163646p:plain

ダウンロードしたUnityPackageをUnity上にドラッグ&ドロップすると、Unity Packageのインポートができます。
右下の「Import」ボタンを押下するとインポートできます。
※ Sceneフォルダに警告が出ていますが、特に問題ないので無視でよいです。
f:id:napo909:20211212163917p:plain

正常にインポートができると、JoyconLib由来のファイルがAssetsフォルダ上に配置されます。
f:id:napo909:20211212164151p:plain

そのままだとエラーが発生するため、参考元の記事の通り、一部ソースコードを修正します。

  • Joycon.cs L370
    変更前:
DebugPrint(string.Format("Dequeue. Queue length: {0:d}. Packet ID: {1:X2}. Timestamp: {2:X2}. Lag to dequeue: {3:s}. Lag between packets (expect 15ms): {4:s}",

変更後:

DebugPrint(string.Format("Dequeue. Queue length: {0:d}. Packet ID: {1:X2}. Timestamp: {2:X2}. Lag to dequeue: {3:t}. Lag between packets (expect 15ms): {4:g}",

f:id:napo909:20211212165259p:plain

Scenes/Scene1を選択すると、JoyconLabのサンプルが確認できます。
これを左上メニューのFile/Save As...から複製して保存します。
f:id:napo909:20211212165814p:plain

複製したSceneをHoloLens用に構成します。
左上メニューのMixed Reality/Add to Scene and Configure...からMRTK用に構成します。
f:id:napo909:20211212165937p:plain

そのままだとJoyConの動きを示すCubeが頭の位置に来てしまうため、微調整します。
f:id:napo909:20211212170152p:plain

Scene上にTextを配置して、ジャイロと加速度の状態を確認できるようにします。
TextMeshProを適当な位置に配置して、JoyconManagerにShowJoyConState.cs (下記ソース参照)をアタッチし、TextMeshProを参照させます。

  • ShowJoyConState.cs
クリックで展開
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class ShowJoyConState : MonoBehaviour
{
    private List<Joycon> joycons;

    [SerializeField]
    private TextMeshPro text;

    // Start is called before the first frame update
    void Start()
    {
        this.joycons = JoyconManager.Instance.j;
    }

    // Update is called once per frame
    void Update()
    {
        ShowState();
    }

    private void ShowState()
    {
        string info = "";

        foreach(var joycon in this.joycons)
        {
            info += "#########\n";
            info += (joycon.isLeft) ? ("[Left]\n") : ("[Right]\n");
            info += $"Accel:\n";
            info += $"x:{joycon.GetAccel().x}\n y:{joycon.GetAccel().y}\n z:{joycon.GetAccel().z}\n";
            info += $"Gyro:\n";
            info += $"x:{joycon.GetGyro().x}\n y:{joycon.GetGyro().y}\n z:{joycon.GetGyro().z}\n";
            info += "#########\n";
        }

        this.text.SetText(info);
        
    }
}

f:id:napo909:20211212171722p:plain
f:id:napo909:20211212171859p:plain

ProjectSettins/PlayerのCapabilitiesからBlueToothにチェックを入れておきます。
f:id:napo909:20211212172520p:plain

BuildSettingsからビルド対象シーンに今のシーンを追加し、Buildボタンを押します。
f:id:napo909:20211212172219p:plain

次にHoloLens側でBluetoothを用いてJoyconを接続します。
設定/Bluetoothとその他のデバイスからBluetoothまたはその他のデバイスを追加するを選択します。
f:id:napo909:20211212175620p:plain

追加するデバイス種として、Bluetoothを選択します。
f:id:napo909:20211212175737p:plain

Joyconの丸いボタンを長押ししペアリングモードにすると、JoyConが一覧に表示されます。選択すると、HoloLensとJoyConをBluetooth接続できます。
f:id:napo909:20211212180044p:plain

動作確認

HoloLens側でアプリ起動しましたが、JoyConの加速度、ジャイロのデータを取得することはできませんでした。
Unity上では動作確認できているため、HoloLens特有の問題のようです。

f:id:napo909:20211212180936g:plain

アプリのログを見たところ、使用しているdllが読み込めていないようです。

  • UnityPlayer.log
DllNotFoundException: Unable to load DLL 'hidapi': The specified module could not be found.
  at JoyconManager.Awake () [0x00000] in <00000000000000000000000000000000>:0 
 
(Filename: currently not available on il2cpp Line: -1)

該当のプラグインの格納場所を見ると、win32, win64, mac用のプラグインしかなく、arm, arm64用のプラグインが入っていないようです。
hidapiのarm用プラグインがあれば、動作しそうです。
f:id:napo909:20211212180449p:plain

うまくいってはいないですが、今回はここまで。
hidapiのarm版が見つかったら再度チャレンジしてみます。