はじめに

ついに先日、全哺乳類待望のHoloLens 2が発表されました!


いやー3年ぶりの新作ですよ、3年。長かったですが、長かっただけあって予想を超える製品が出てきそうで今からワクワクが止まらないですね!!
さて、ハードウェアの方が大きくアップデートしようとしてる一方、開発環境も大きな進化の途上にあります。
初期には HoloToolKit と呼ばれた Hololens の SDK ですが、いつしか WinMR の SDK とくっついて MixidRealityToolKit と呼ばれるようになりました。
そして昨年の夏ごろより MixidRealityToolKit vNEXT として一新されて SDK が提供されました。(当時でα版、現在でもβ版ですが)
本記事では、今 Hololens で開発するにはどのように環境構築をすればいいのかについて解説していきます。
以降、 HoloToolKit を HTK 、 MixidRealityToolKit vNEXT を MRTK を表記します。
重要事項として本記事は2019年3月に書いた物です。特に MRTK に関しての記述は賞味期限が長くないと思いますのでご留意ください。

MRTK は何が新しくなったか

一新された MRTK は何が変わったのか

対応ハードウェアが大幅に増えた(予定)

これまでの HTK は WinMR と HoloLens を対象とした SDK でしたが、 MRTK は OpenVR などの他社製 VR などに対応できるようになっています。
MRTK は抽象化が進み、インターフェースを継承したコードを書くだけで多種多様なデバイスに対応させることができます。
これは HMD 以外にもコントローラーデバイスも同様で、 Xbox コントローラーや WInMR コントローラーはもちろんのこと、 Oculus コントローラーや Vive コントローラーなども対応しています。

clipboard.png

これによって Steam VR と同じように一つの SDK で開発すれば多数の HMD で動作させられる環境が整ったといえます。(まだ開発途上ですが)
これまで VR 開発といえば、とりあえず SteamVR SDK でやれば Vive も Oculus も WinMR も動いて展開楽だよね、という感じでしたがそこに MRTK を使うという選択も加わってきました。(まだ開発途上ですが)
鼻息荒く MRTK の説明をしましたが、今回のメインは HoloLens なので、一旦 VR の話はこの辺で置いておきます。

各種設定がインスペクタで簡単に行えるように!

これまで、 HTK で細かい設定を行うには、 C#でコードを書く必要がありました。これが、インスペクタで大体の設定を終わらせることができるようにりました!

clipboard.png

しかも、変更したい項目のみ設定プロファイルを作成し変更するという便利な方法です。
HoloLens の設定やる人なんてエンジニアなんだからインスペクタで設定できなくても困らないだろ!という声もあるでしょうが、そもそも HoloLens ってどんな設定があるのか、どんな API があるのかというのを知らなければ C#で設定できないわけですよ。
それがインスペクタ上に見えてるというだけで慣れるまでの時間短縮効果があると思います。

そんな感じで個人的にインスペクタ中心に設定できるようになったのはいいことだと思います。

AssemblyDefinition 対応

最近の Asset や SDK よろしく、ちゃんと AssemblyDefinition に対応しています。これにより、長いビルド時間が短縮されるようになりました。

HoloToolKit vs MixidRealityToolKit ビルド時間対決

現状、 HoloLens を開発する場合、下記2通りの組み合わせがあると思います。
  • MRTK_v2.0.0 Beta 2 + Unity2018.3~
  • HTK_2017.4.3.0 – Refresh + Unity2017.4~
どちらの組み合わせでも、実装方法に多少の違いがあるとはいえ同じアプリを作ることが(たぶん)できます。
HoloLens の開発で重要なのはビルド速度です。スマホアプリであれば Editor プレビューでそれなりに確認ができますし、エミュレーターもあります。 VR アプリは開発機に HMD を繋いであれば Editor でプレビューができます。
しかし、 HoloLens の場合はエミュレーターでは正直 UX の面で確認がし辛いですし、 Holographic Remoting Player を快適に使えるほど東京という街に電波帯域が空いていません。
(例として弊社の2.4Ghz 帯ご覧のありさまで、常在戦場な環境であり、社内で動けばビッグサイトなどの展示会場の電波状況でも動くだろうという最高のデバッグ環境を実現できています。5Ghz 帯も似たような惨状になっています。)

clipboard.png

そんなこんなで UX 部分の作り込み時はどうしても試行錯誤のビルド祭りが発生します。 では一体どの開発環境を組み合わせれば最速なビルド速度を得られるのかを調査していきます。

計測の環境

開発 PC

今回の開発機のスペック及び環境です。
CPU i7-4770
RAM DDR3-1600 16GB
GPU GeForce GTX980
(Unity プロジェクトのある)HDD TOSHIBA DT01ACA
OS Windows10Pro 1803
Visual Studio 2017 15.6.7

Unity のバージョン

使用した Unity バージョンは2017.4.20と2018.3.6です。

Unity プロジェクト

メインカメラ(HoloLens)でキューブを見るだけのシンプルなプロジェクトを用意しました。 (弊社は MVP パターンでシーン制御の基盤を実装をしています。そのため UniRX 、 Zenject も使用しています。)

計測の仕方

IL2CPPでビルドしています。 Build Window を使ってビルドしています。 APPX のビルドに入る前を Unity 工程のビルド、 APPX のビルドは VisualStudio 側のビルドという計測をしています。
2~3回程度のビルド時間を計測して、平均値を算出しました。

計測結果

HoloToolKit x Unity 2017.4.20

キャッシュ削除状態で計測します。

工程 時間(分:秒)
Unity 3:07
VisualStudio 8:07
合計 11:14
続いてキャッシュは削除しないで、 Debug.Log を一行追加してビルドします。

工程 時間(分:秒)
Unity 2:56
VisualStudio 8:16
合計 11:12
大きな変化はありません。特にキャッシュが使われるわけでは無さそうです。

HoloToolKit x Unity 2018.3.6

キャッシュ削除状態で計測します。

工程 時間(分:秒)
Unity 2:34
VisualStudio 8:52
合計 11:24
続いてキャッシュは削除しないで、 Debug.Log を一行追加してビルドします。

工程 時間(分:秒)
Unity 4:19
VisualStudio 7:22
合計 11:41
やはり、大きな変化はありません。

MixidRealityToolKit x Unity 2018.3.6

(MRTK は Unity2018でしか動作できないので、 Unity2017での計測はしていません) キャッシュ削除状態で計測します。
工程 時間(分:秒)
Unity 3:02
VisualStudio 7:24
合計 10:26
HoloToolKit x Unity 2018.3.6と比較して、若干短くなってる気がしますが誤差の範囲内だと思います。
HTK から大きな変化はないと判断しました。
続いてキャッシュは削除しないで、 Debug.Log を一行追加してビルドします。

工程 時間(分:秒)
Unity 2:03
VisualStudio 3:39
合計 5:42
圧倒的な最速記録の達成です。恐らく Assembly Definition が的確に動作しているのだと思います。 IL2CPP 作業が入ってトータル5分なら待ち時間というほどの時間でも無いので良いですね!

今、開発する組み合わせ

ビルド時間の調査をいろいろとやってきましたが、組み合わせは Unity2018.3系と MRTK の組み合わせが一番良さそうです。
MRTK はまだまだβ版なので安定性に疑問符が多少ありますが、(どうせ HTK 使ってても安定するわけではないので)ちゃんと動作確認をすればこの組み合わせで良いと思います。
また、 Unity2018を使う事で UniRx.Async が使えるので非同期処理もやり易くなるのが、個人的には推しポイントです!

MRTK を使ってみる

では MRTK をどう使うんだ?という話です。
MRTK は HTK よりも要件が厳しいので下記要件を満たしてから作業をします。
Unity 2018.3.x or later
Microsoft Visual Studio 2017
Windows SDK 10.0.17134 or later
Windows 10 1803 or later
Windows SDK の新しいバージョンを入れるには Visual Studio の新バーションが必要という依存関係などもあるので、数年前に HoloLens のビルド環境を構築してそのままの人はいろいろとアップデートが必要になります。
結構時間がかかると思うので時間があるときに作業したほうが良いと思います。

SDK のインポート

まず MRTK をインポートします。 インポートする前の注意点として、 HTK ではインポート後に「 Apply Mixed Reality Project Settings 」を実行することで Project の設定を行っていましたが、 MRTK ではインポート時に設定が行われるようになりました。
そのため、インポート前に UWP へのスイッチと HoloLens の有効化処理をしておいたほうが良いと思います。

clipboard.png

また、このときに IL2CPP が強制されます。時代は IL2CPP なようです。
PlayerSettings の XR 設定ですが、私が実行したときは正しく設定されなかったので PlayerSettings から手動で有効化しています。

Scene の設定

Scene に必要なものを設定していきます。「 Mixed Reality Toolkit 」の「 Configure 」を選択すると必要な Prefab が配置されます。
また、 Inspector 上に設定情報が表示されます。特に弄らなければデフォルト設定になりますが、これは Immersive Headset 向けの設定になってるので「 Copy & Customize 」を押すと設定ファイルがコピーされて設定変更が可能になります。

clipboard.png clipboard.png

複製後、「 Target Scale 」を World に設定します。さらに Input や Camera などの細かい設定を編集します。何もしない場合はデフォルトの設定データが使用されます。
「</>」ボタンを押すことでデフォルト設定がコピーされた編集可能な設定ファイルが作成されます。まずは「 Camera Settings 」の設定ファイルを変更します。

clipboard.png

カメラ設定は HTK で Camera についていた Script と同じ様な設定ができます。
「 Opaque Display Settings 」は Immersive Headset 用の設定です。今回は HoloLens なので「 Transparent Display Settings 」の方を変更します。
HTK と違ってここで Quality Setting も弄れますが、 Very Low 以外にすることはないでしょう。

clipboard.png

続いてオブジェクトをタップできるようにします。タップしたいオブジェクトに「 Pointer Click Handler 」コンポーネントを追加して uGUI の Button などよろしく UnityEvent で追加するだけで簡単にタップが受信できます。
「 Is Focus Required 」が有効では無い場合、オブジェクトへのフォーカスに関係なくタップイベントが受信されます。

clipboard.png

ビルド

ビルドは HTK 時代ととくに変わりはありません。 Build Window からビルドを実行すれば HoloLens のインストールまで一気通貫に実行されます。
注意点として、 Build Window の設定が IL2CPP になっているかどうかは確認する必要があります。

MRTK まとめ

以上が MRTK を利用した最低限の HoloLens 開発 HalloWorld になります。 HTK とはかなり異なった設定方法になりました。
恐らく HoloLens2が出た場合の開発は MRTK 一択になると思いますので今のうちに HoloLens1のプロジェクトを MRTK 化するなどして準備をしておいた方がいいと思います。(まぁ MRTK 版にするだけで1から作り直すくらい大変な気がしますが……)

HoloLens で Xbox コントローラーを使いたかった話

ここからは2月に起きた、とある HoloLens エンジニアのお話です。

このお話はきっとフィクションであり、実在する人物、団体、 SDK 、ハードウェア等は関係あったりなかったりします。

はじまりはじまり

HoloLens 上で表示されたオブジェクトの Transform 、 Material 設定を細かく微調整したい、という事がありました。

HoloLens の操作といえば基本的には AirTap 等のジェスチャーになります。それで Scale を0.1倍とか、 Rotation を2度調整といった事をやるに難儀です。
さてどうしよう、そうだ Xbox コントローラーを使おう。 Xbox のコントローラーは唯一 HoloLens で動作するので十字キーやボタンで細かい操作が行える筈だ。

Xbox コントローラー

初期の Oculus Rift を購入してる方は Xbox コントローラーを持っていると思います。やったこれで無料でいけるな!
と思っていたのですが、 Oculus Rift 付属の Xbox コントローラーは Bluetooth 非対応なので HoloLens にペアリングすることができません。
というわけで下記製品を購入しました。

あとは Windows10の PC と同じように Bluetooth ペアリングで Xbox コントローラーとペアリングすれば OK です。 Windows10のスタートメニューも Xbox コントローラーで操作可能なのでそこで動作確認ができます。

MRTK で Xbox コントローラーを使う

「 MixedRealityControllerMappingProfile 」でコントローラーの入力関連を設定します。

Controller Definition

MRTK には「 Controller Definition 」というコントローラーデバイスを使用するための定義ファイルを作成できます。 デフォルトで次のデバイスの Controller Definition が用意されています。
  • HoloLens のジェスチャー入力
  • Windows Mixed Reality コントローラー
  • Oculus Touch
  • Oculus Remote
  • Knuckles コントローラー
  • Vive コントローラー
  • マウス
  • タッチスクリーン
  • Xbox コントローラー

clipboard.png

Controller Definition は各デバイスのボタンやレバーに対してどの Action(後述説明)を割り当てるのかを設定できます。
HoloLens Gestures の場合

clipboard.png

clipboard.png

Xbox Contoroller の場合
Xbox コントローラーはデフォルトでは設定が不十分のままです。 Action を定義しつつ、 Controller Definition を適切な内容にしましょう。

clipboard.png

clipboard.png

Action

デバイスの各パーツからどんな情報を取り出すかの定義を Action といいます。
「 MixidRealityInputActionsProfile 」を開くと先ほどの Select など Action が定義されています。 Action の項の項目で入力時に受け取るデータの種類を設定できます。

Axis Constraint 利用目的
Digital Bool スイッチの ONOFF
Single Axis Float トリガーの入力値
Dual Axis Vector2 ジョイスティックの入力値
Three Dof Position Vector3 位置情報
Three Dof Rotation Quaternion 回転情報
Six Dof MixedRealityPose Tracker など位置と回転を持つ情報
ここに定義されているものが Controller Definition で設定可能な enum の項目名になります。 デフォルトの設定だとこうなっています。
  • Select : ボタンで使用することを想定して Digital
  • Pointer Pose: アナログスティックで使用することを想定して SixDof
  • Mouse Delta : マウスで使用することを想定して Dual Axis

clipboard.png

入力イベントを受け取る

Action の Select という名前見覚えないでしょうか?
実はこれ、前述の「 Pointer Click Handler 」コンポーネントを追加したときにインスペクターの Input Action の Enum だったのです。
つまり次の手順でコントローラデバイスからの情報が流入されるのです。
  1. コントローラーデバイスで入力
  2. Controller Definition から入力が行われたパーツの Action を知る
  3. Action からどのデータを受け取るかを知る
  4. 「 Pointer Click Handler 」が受け取ったデータの渡し先を知る

clipboard.png

Xbox コントローラの各パーツの入力に対応するには「 Pointer Click Handler 」では不十分です。
「 Pointer Click Handler 」を参考に Xbox コントローラーの入力を受け取れるクラスを作成します。 Example の中にサンプルコードが入っているのでこれをベースに使います。
using Microsoft.MixedReality.Toolkit.Core.Definitions.InputSystem;
using Microsoft.MixedReality.Toolkit.Core.Definitions.Utilities;
using Microsoft.MixedReality.Toolkit.Core.EventDatum.Input;
using Microsoft.MixedReality.Toolkit.Core.Interfaces.InputSystem.Handlers;
using Microsoft.MixedReality.Toolkit.SDK.Input.Handlers;
using UnityEngine;
public class InputTest : BaseInputHandler, IMixedRealitySpatialInputHandler
{
 ///受け取る Action
    [SerializeField]
    private MixedRealityInputAction myAction = MixedRealityInputAction.None;
 ///Axis Constraint が Digital のボタン押下
    public void OnInputDown(InputEventData eventData)
    {
        if (eventData.MixedRealityInputAction == myAction)
        {
            Debug.Log($"OnInputDown {eventData.InputSource.SourceName} | {eventData.MixedRealityInputAction.Description}");
        }
    }
 
 ///Axis Constraint が Digital のボタン離し
    public void OnInputUp(InputEventData eventData)
    {
        if (eventData.MixedRealityInputAction == myAction)
        {
            Debug.Log($"OnInputUp {eventData.InputSource.SourceName} | {eventData.MixedRealityInputAction.Description}");
        }
    }
 ///Axis Constraint が Single Axis の入力
    public void OnInputPressed(InputEventData<float> eventData)
    {
        if (eventData.MixedRealityInputAction == myAction)
        {
            Debug.Log($"OnInputPressed {eventData.InputSource.SourceName} | {eventData.MixedRealityInputAction.Description} | {eventData.InputData}");
        }
    }
 ///Axis Constraint が Dual Axis の入力
    public void OnPositionInputChanged(InputEventData<Vector2> eventData)
    {
        if (eventData.MixedRealityInputAction == myAction)
        {
            Debug.Log($"OnPositionInputChanged {eventData.InputSource.SourceName} | {eventData.MixedRealityInputAction.Description} | {eventData.InputData}");
        }
    }
 
 ///Axis Constraint が Three Dof Position の入力
    public void OnPositionChanged(InputEventData<Vector3> eventData)
    {
        if (eventData.MixedRealityInputAction == myAction)
        {
            Debug.Log($"OnPositionChanged {eventData.InputSource.SourceName} | {eventData.MixedRealityInputAction.Description} | {eventData.InputData}");
        }
    }
 
 ///Axis Constraint が Three Dof Rotation の入力
    public void OnRotationChanged(InputEventData<Quaternion> eventData)
    {
        if (eventData.MixedRealityInputAction == myAction)
        {
            Debug.Log($"OnRotationChanged {eventData.InputSource.SourceName} | {eventData.MixedRealityInputAction.Description} | {eventData.InputData}");
        }
    }
 
 ///Axis Constraint が Six Dof の入力
    public void OnPoseInputChanged(InputEventData<MixedRealityPose> eventData)
    {
        if (eventData.MixedRealityInputAction == myAction)
        {
            Debug.Log($"OnPoseInputChanged {eventData.InputSource.SourceName} | {eventData.MixedRealityInputAction.Description} | {eventData.InputData}");
        }
    }
}

MRTK を使わない決定をした2つの理由と顛末

ここまで作っておいてアレですが MRTK を使うのはやめ、 HTK に変更をしました。
理由は2つありました。

理由1

ビルド時間が50分程度かかっていました。

原因として IL2CPP のビルド負荷のせいでした。
SSD にリポジトリを移すなどいろいろと試しましたが解決せずに諦めてしまい Mono ビルドができる Unity2017.4と HTK に逃げました。

ですが本記事前半の検証の通り、今では中規模のプロジェクトでも20分程度でビルドが終えています。
キャッシュが効いている場合ではその半分以下の時間で済みます。

50分もかかっていた理由は、 Visual Studio のバージョンアップが強く関係していると思います。
その根拠としては、開発機は2017年にとある HoloLens 案件以来、開発環境を更新していませんでした。
Visual Studio もです。
これを最新バージョンにアップデートしたところ、ビルド時間が劇的に短くなったのです。

Visual Studio は過去4バージョン前程度までしか過去バージョンが公開されていないので元々の環境に戻すことができず Visual Studio が速度アップの要因と断定はできないのですが、恐らく Visual Studio のバージョンは HoloLens 関連のビルド時間を大きく左右するのではないかと思います。

理由2

前述の Xbox コントローラーの実装をしても、アプリを起動して暫くすると全く動作しなくなる問題が起きました。
ブルームして一度 Home に抜けてから再度アプリをフォアグラウンドにすると治るのですが直ぐ再発します。

原因を探るにも、ビルド時間が大きな足かせになっていたので HTK に戻す事になりました。

原因は下記の issue に見解が載っています。
かいつまんで言いますと OS のバグのようです。
ただ当時はこの見解のコメントがなく、開発環境を変えれば解決できるのではないか?という一縷の望みもありました。


そして HTK でもコントローラーは動かない

そんなこんなで開発環境を HoloToolKit x Unity 2017.4にしましたが、 HTK で Xbox コントローラーを制御するには課題がいくつかありました。

HoloToolKit x Unity 2017.4は Unity の Input でコントローラーの入力を取得するのですが、 Unity2017系にはバグがあります。


このため入力を取得することができません……
仕方が無いので Windows.Gaming.Input を使ってネイティブ側で取得します。


以上ここまで頑張りましたが……
先ほどの issue の通り、 OS のバグのため HTK でも症状は解決することはありませんでした。

顛末、 Xbox コントローラーなんて無かった

長い時間を掛けて Xbox コントローラーを使おうと努力しましたが、万策尽きたので諦めました。

最終的にどうしたかというと、 iPad で同等のアプリを ARkit と組み合わせて作りました。
このアプリから Transform の更新情報を Hololens 側のアプリに送るという、ずいぶんリッチな遠回り……

まとめ

以上、ここまで MRTK と HTK と Xbox コントローラーの四方山話を書いてきました。

恐らく半年後にはこの記事は古文書みたいな状況になっているでしょう。 HoloLens 開発の最適解なんで渋谷駅の通路みたいにしょっちゅう変わってしまうのでまだまだ過去資産の組み合わせで楽々開発なんて状況は来そうにないです。

最後に

Visual Studio のバーションはちゃんとアップデートしよう!!
Facebook Comments