たるこすの日記

たるこすの日記

リアルからバーチャルへ、バーチャルからリアルへ

Tango を HoloLens 用ガンコントローラとして使ってみる

はじめに

こんにちは、たるこすです。

今回の記事は Oculus Rift Advent Calendar 2017 の19日目の記事です。

qiita.com

やってみたこと

HoloLens と Tango を連携させ、Tango を HoloLens 用ガンコントローラとして使ってみました。

まずはデモ動画をご覧ください。

Tango について

Tango とは Google が開発した AR フレームワークで、対応端末は 2機種(Zenfone AR, Phab 2 Pro) 発売されています。

外部センサなしで高精度の SLAM を行うことができ非常に優秀なのですが、残念なことに Tango ブランドは終了することが発表されています。さらに、12/15 には、Tangoのサポートは 2018年3月1日 に終了するということが発表されました。 jp.techcrunch.com

HoloLens と Tango の連携

ガンコントローラのトリガーは Tango アプリで取得し、HoloLens に送信しています。 また、Tango の位置を HoloLens に送ることで、HoloLens でガンコントローラの位置を取得できます。

しかし、Tango アプリと HoloLens アプリでは座標系が異なってしまうので、Tango から受け取った値そのままでは HoloLens 上では正しい位置になりません。

そこで、Tango アプリの画面にマーカー画像を表示し、それを HoloLens で認識した際に HoloLens 座標系での Tango の原点を計算します。 Tango アプリから受け取った座標は Tango 原点から見た座標なので、それを先ほど計算した Tango の原点を使って HoloLens 座標系に変換します。

こうすることで、HoloLens アプリで Tango の位置を使って操作ができるようになります。

ガンコントローラのボタンを取得する

カワダから発売されている、AR マジックガンというおもちゃのコントローラを使いました。

本来の使い方は、ガンに普通のスマートフォンを取り付け、壁に貼ったポスターをマーカーとしてスマホの画面で AR ゲームをするというものです。公式のスマホアプリを入れるとガンコントローラと Bluetooth 接続し、トリガーのボタンを取得できます。

今回は自作のアプリでガンコントローラと接続して値を読み取りたかったのですが、調べても情報が見つからなかったため方法がわかりませんでした。そこで、ガンコントローラを分解し、中のスイッチにジャンパーワイヤーをはんだ付けして外に取り出し、Teensy というマイコンで ON/OFF を読み取りました。Teensy は Zenfone AR に USB で接続し、Zenfone AR からはキーボードとして認識させています。

このあたりの話は、また別記事に詳しくまとめようと思います。

環境、ライブラリ

Tango アプリ

  • Unity 5.6.3p1
  • Tango SDK for Unity, Ikariotikos (Version 1.54)

HoloLens アプリ

  • Unity 2017.1.2f1
  • HoloToolkit-Unity-v1.2017.1.2
  • vuforia-unity-6-2-10.unitypackage

Tango アプリ

作成した Tango アプリの機能は以下の2つです。

  • 画面にマーカー画像を表示する
  • 現在位置、ガンコントローラの入力を HoloLens アプリに送る

実装内容については、大きく分けて以下の3つになりました。

  • Tango の位置トラッキングを使う
  • 画面、UI の構成
  • 現在位置、ガンコントローラの入力を HoloLens アプリに送る

Tango の位置トラッキングを使う

Tango SDK に含まれている、Tango Manager と Tango Camera のプレハブをシーンに配置しました。

これで、Tango 端末の位置に合わせて Main Camera が移動するようになります。

画面、UI の構成

以下のような画面を作成しました。


シーンには以下のように、Canvas に RawImage, InputField, Button を配置しています。

RawImage は HoloLens で認識するためのマーカー画像を表示する用です。

InputField と Button は、HoloLens と通信する際に必要となる HoloLens の IP アドレスを入力するために使います。 アドレスを入力してボタンをタップすると、IP アドレスが設定され、入力欄は非表示にしています。

現在位置、ガンコントローラの入力を HoloLens アプリに送る

Tango アプリから HoloLens へのデータの送信には、UNET の LLAPI (Low-Level API) を利用しました。

以前利用した際もブログに書いていたので、こちらも併せてご覧ください。

データ送受信のマネージャとして、以下のスクリプトを作成します。このスクリプトは、受信側の HoloLens アプリでも使用します。

これを空のゲームオブジェクトにアタッチし、以下のように設定します。

Tango の位置やコントローラ入力は、以下のスクリプトで送信します。

これを、空のゲームオブジェクトにアタッチし、NetworkManger として先ほど作成したオブジェクトを設定します。

これで、Tango アプリは完成です。

HoloLens アプリ

初期設定

プロジェクトに HoloToolkit-Unity をインポートします。

シーンに、HoloLensCamera, Directional Light, SpatialMapping を配置します。Directional Light は 1つだと風船が暗く見えてしまったので、2つ設置しました。

また、はまりやすいのが Capability の設定です。今回のアプリでは以下の設定が必要なので、気を付けてください。

  • Webcam
  • Spatial Perception
  • Private Network Client Server

Tango からデータの受信

UNET でデータを受信するため、先ほど Tango アプリでも利用した LLAPINetworkManager.cs を使います。

LLAPINetworkManager.cs を空のオブジェクトにアタッチし、以下のように設定します。

HoloLens アプリの LLAPINetworkManager で設定する Local Port の番号と、Tango アプリで設定する Server Port を一致させるようにしてください。

さらに、受信したデータを処理するスクリプトとして、以下の UnetTangoController.cs を作成します。 ボタンの値を受信した場合は SelectButton の値が変更され、位置を受信した場合は UnetTangoController.cs がアタッチされたオブジェクトの位置が変更されます。

ITangoController.cs は以下のようなスクリプトです。

初めは、通信に Photon を使っていたので、切り替えを簡単にできるようにインタフェースを作りました。

Tango の位置の反映と光線の発射

光線銃オブジェクトは、ヒエラルキーでは以下のような構成となっています。

TangoOrigin が Tango 座標系の原点、Gun が Tango(ガンコントローラ)の位置、Muzzle が銃口、Aim が照準となっています。

Gun オブジェクトにアタッチする GunScript.cs では、先ほどの UnetTangoController.cs で取得した値を使って光線銃の処理を行います。GunScript.cs から関係する部分だけを抜き出すと以下のようになります。

このスクリプトでは、Gun オブジェクトの Position, Rotation を Tango から受け取った値に更新しています。正確に言うと、Tango から値を受け取るフレームレートが低くそのままだとカクカクして見えてしまうため、滑らかに見えるように前の値と補間して設定しています。

Tango と HoloLens の位置合わせ

マーカー画像の認識には Vuforia を使っています。

シーンに ARCamera と ImageTarget のプレハブを配置し、認識のための設定を行います。

詳しくは以下のブログをご覧ください。 tarukosu.hatenablog.com

さらに、ImageTarget に以下の CustomTrackingHandler.cs をアタッチします。

これは、Vuforia のトラッキング状態を Action で通知するためのスクリプトです。

次に、GunScript.cs で Tango の原点の計算を行います。先ほどは一部を省略した状態でしたが、以下が GunScript.cs の全体です。

重要なのは、OnTracking 内で Tango 原点を求めている部分です。originToMarker が HoloLens 原点からマーカーへの変換行列、tangoOriginToMarker が Tango 原点からマーカーへの変換行列、originToTangoOrigin が HoloLens 原点から Tango 原点への変換行列となっています。

Inspector では以下のように設定します。

これによって、TangoOrigin の位置が Tango アプリでの原点の位置に移動され、Gun の位置が Tango の位置と一致するようになります。

ブログでは省略したところ

アプリの実装内容をすべて書くのは大変だったので、以下の部分は省略しました。ごめんなさい。

Tango アプリでの IP の設定

Set ボタンが押されたら、Input Field に入力された IP を LLAPINetworkManager.cs の Server Address に設定するようにしました。

光線銃の照準

Muzzle から Ray を飛ばし、ぶつかったところに黄色いオブジェクトを表示させて照準としています。

発射される光線

Volumetric Lines というアセットを使って光線を作成しました。

風船

風船は MRDesingLabs_UnityDesignLabs_Unity_Examples に入っているモデルを使いました。

光線と風船の衝突を判定し、風船が割れる処理を行っています。

紙吹雪

風船が割れたときに出る紙吹雪は、以下のブログを参考にして作成しました。

tsubakit1.hateblo.jp

感想

出来上がったデモは出現する風船を撃つというだけのものですが、しばらくやっていたくなるような楽しいデモになりました。制限時間や得点などを入れてゲーム性を上げるともっと楽しくなりそうです。

また、今後の発展としては、複数人で対戦したり、現実のものとのインタラクションを入れたりしたいと思っています。

明日は...

@OculusTan さんによる「VRすきまアワード作品紹介?」です。お楽しみに!