Tutti Lab

元シリコンバレー在住のおっさん技術者、モバイルVRアプリ開発に挑戦中

Vuforia for Unityを使って(擬似)ハンドトラッキング

前回、Viforia for Unityの機能を活用し、Google Cardboardでポジショントラッキングを実現する方法について記載しました。同様に、Vuforia for Unityを使うことで(擬似)ハンドトラッキングも可能です。
Vuforiaでは直接「手」を認識することはできません。しかし、手にマーカーを貼り付ける、マーカーを貼り付けたふだを持つなど、マーカ認識を通じて手の位置を認識する、ということは比較的容易に実現できます。
先日とあるVRイベント向けに開発した「Santa Claus Job Simulator」というサンタのお仕事を体験するアプリにて、この擬似ハンドトラッキングを実装してみましたので、本実装技術についてご紹介したいと思います。
www.youtube.com

ARCameraの設定

Google CardboardにてVuforia for Unityを利用した(マーカ認識による)ハンドトラッキングをする際のポイントは「VRのヘッドトラッキングを考慮した上で、Vuforiaで認識した「手」を「手の位置」に表示すること」です。
Vuforia for Unityはデフォルトでは「はじめに発見した認識対象の座標を固定し、認識対象との位置関係に応じてCameraの位置を変える」という設定になっています。VuforiaがImage Targetに指定された認識対象を発見した際、Image Targetの座標・回転が変化するのではなく、ARCamera(Main Cameraを子として含む)の座標・回転を変化させることで、相対的にImage Targetが動いているように見せます。
VRでなければ、特段問題は生じませんが、VR(Player SettingsにてVirtual Reality SupportedがON)の場合、ヘッドトラッキングによりデバイスの回転によりMain Cameraを回転させます。このため、上記のデフォルト設定では、ヘッドトラッキングの回転設定とVuforiaの回転設定が競合してしまい、ちょっと都合が悪いです。

そこで、

  • ARCameraのVuforia BehaviorコンポーネントのWorld Center Modeをデフォルトの「FIRST TARGET」から「CAMERA」に変更します。これで、認識対象物が発見された際の固定される座標はMain Cameraとなり、代わりにImage Targetの座標が変わります。
  • また、もう一点、Image TargetはMain Cameraの子とします。これは上記の通り、認識対象の位置はMain Cameraが固定であることを前提としていますから、ヘッドトラッキングによるMain Cameraの回転変化に関わらず、Image TargetからはMain Cemeraが固定に見えるようにするためです。

f:id:tuti107:20161221234833p:plain

また、Image Targetと「手」の位置関係にも工夫が必要です。Santa Claus Job Simulatorでは、マーカ付きの看板を手に持ってもらい、そのマーカを認識することで手を表示するようにしています。
f:id:tuti107:20161221233051p:plain

このためImage Target認識時に表示される手の位置・回転は、看板に貼り付けられたマーカからの相対位置・回転を設定する必要があります。
f:id:tuti107:20161221233148p:plain

高速化が不可欠

Vuforiaをハンドトラッキングに活用する上でもう一つ重要な点は、可能な限り処理の高速化を図ることです。
VR表示しながら、同時にマーカ認識するという処理は、モバイル端末にとって非常にヘビーなものとなります。
このため、Edit->Project Settings->Qualityにて処理をFastestとして描画・表示負荷を下げる等、できるだけ処理を軽くし、Vuforiaの認識処理にリソースを回してあげる必要があります。
描画負荷が高い場合等、Vuforiaの認識処理のための余裕がない場合、認識の品質は明らかに低下し、すぐに認識対象を見失ってしまいます。こうなると心地よりハンドトラッキングとは程遠くなってしまいます。

最後に

今回は、Google Cardboard向けに(擬似)ハンドトラッキング処理を実装した当方が開発したゲームを例に、Vuforiaによる(擬似)ハンドトラッキングを実装する方法について説明をしました。
モバイル向けにはVuforiaを活用したハンドトラッキング・ポジショントラッキングをどんどん活用したい、と思っていますが、最新のモバイルVRヘッドセットであるDaydream ViewではVuforiaが使えません。Google Cardboardのようにスマホカメラの位置に穴を開けるわけにはいきませんので。。
何らか他の方法を検討する必要があるな、と考えております。

UNIBOOK7で、ThetaSによる360度立体視映像配信について書かせていただきました

知人に紹介いただいたことがきっかけで、UNIBOOK7の「第8章 ThetaSを使った360度立体視映像配信」を書かせていただきました。
f:id:tuti107:20161221221355j:plain
半年ほど前、ThetaSを2台使った360度立体視の撮影・配信についてブログにかきましたが、その当時は、私の知識不足&当時作成していたアプリの要求仕様に合わない、ということから中途半端となっていた、撮影と配信、そして配信映像を視聴するためのモバイルアプリの作り方について記載しております。
本書には、その他多数の著名クリエイターが執筆した読み応えのある内容満載です。購入いただけると幸いです!

www.unity-bu.com

Vuforiaの認識精度を上げるには

はじめに

前回、Vuforia for UnityのExtended Tracking機能を利用してGoogle Cardboardでポジショントラッキングということで記事を書いたところ、ブログ始めて以来の反響、非常に驚きました。モバイルVRでもポジショントラッキングをやりたい、というニーズは高いのかもしれません。
前回の記事では、結局十分な精度を実現できず、自分が動かなくても、プルプルとポジションが動いてしまう状態のままで公開をしましたが、その後、精度を上げる方法について調べましたので、これをご紹介しようと思います。

理想的なイメージとは?

Vuforiaは、イメージの特徴点を比較することで、イメージを認識します。特徴点の詳細については割愛しますが、Vuforiaの場合、この特徴点は「イメージを白黒化した上で、尖った部分
(三角形や長方形の角のような箇所)」に多く現れるようです(詳細はこちら)。
理想的なイメージは、
- コントラストがはっきりしている。コントラストが低いと「尖り」が分かりづらくなるため
- ごちゃごちゃしている。シンプルだと特徴点が少なくなってしまう
- 規則性がない。詳細は分かりませんが、特徴点を比較する上で、規則的な配列の特徴点は、認識率を悪化させるのだと思われます
もの、となります。

f:id:tuti107:20161201161146j:plain f:id:tuti107:20161201161155j:plain

前回は、Vuforiaがサンプルとして提供している「stones」というイメージを利用しており、上記の条件は満たしております。

印刷品質・サイズ

次に疑われるのは、印刷したイメージの印刷品質・サイズです(詳細はこちら)。
印刷したイメージのサイズがあまりにも小さすぎると、カメラより入力した画像から十分な特徴点を抽出できず、認識を失敗したり・精度が不安定となります。サイズについては、端末ー印刷物間の距離(m)<印刷物のイメージの幅✖️10以下、とするのが良いようです。前回私は幅30cmでイメージを印刷したので、距離は3m以内、ということになります。私はせいぜい2m程度の距離で試したため、印刷サイズの問題ではないようです。
印刷品質については、「コントラストはっきり」「テカらない」、かつ「印刷物に折り目などがない」ものである必要があります。
私は前回、ペラッペラの再生紙に、印刷品質「普通」で印刷したため、コントラストが低く、紙がよれてしまい一部部屋の光をかなり反射している、という最悪の状況になっていました。
そこで、ためしにイメージをディスプレイに表示し、試してみたところ、品質はかなり安定しました。早速こちらの紙を注文しました!

終わりに

前回品質が低かった理由は、単に印刷物が粗末だったためでした。ディスプレイ表示によるポジショントラッキングは、ゲーム等の開発に十分耐えうる品質(Oculus RiftやHTC Viveと比べればかなり低いですが)です。
ちなみに、名刺サイズの用紙に認識用イメージをプリントし、手の甲に貼り付ければ、簡易ハンドトラッキング(ハンドポジショントラッキングというのが正確)も可能な旨、確認しました。これらを駆使すれば、モバイルVRでも、Oculus RiftやHTC Viveの様な没入感のあるアプリを開発することもできそうですね。

Vuforia for UnityのExtended Tracking機能を利用してGoogle Cardboardでポジショントラッキング

はじめに

Google CardboardやGear VRなど、スマホを利用したいわゆる「モバイルVR」は、Oculus Rift/HTC Vive等と比較し、値段が安くお手軽にVR体験を楽しむことができます。一方で、Oculus Rift/HTC Viveには搭載されているハンドデバイス(Oculus RiftのOculus Touchはこの2016/12に出荷予定)や、ポジショントラッキング等、VRの没入感を生み出すための重要な機能が、モバイルVRには搭載されておりません。
モバイルVRでは、立体視+ヘッドトラッキング(顔=デバイスの向きをトラッキング)により、顔の向きとCG空間内の視線方向を一致させることで、あたかも自分が向いている方向のCGを立体視しているような錯覚を生み出し、これが没入感を生み出します。この「立体視+ヘッドトラッキング」だけでも、相当の没入感であり、私も最初にGoogle Cardboard(Oculus Rift DK1も)を見たときには相当な感動を覚えました。しかし、ポジショントラッキングやハンドデバイスが実装されているVR、特にHTC Viveのルームスケールなんかを体験してしまうと、「立体視+ヘッドトラッキング」だけでは物足りなさを感じるようになってしまいます。
ポジショントラッキングとは、その名の通り、ユーザの位置をトラッキングする機能です。ヘッドトラッキングでは顔の向きだけ任意の方向に向けることができましたが、例えば立ち上がったり・しゃがんだり・肩を左右に振っても、ユーザの視点位置は変化しません。しかし、ポジショントラッキング搭載のものであれば、例えば向こうから飛んでくるボールを避けるゲーム、なんてものも実現することができます。
Oculus Rift (DK2/CV1)では、ユーザの正面の専用のカメラを設置し、このカメラがOculus Rift本体の位置を捉えることでポジショントラッキングを実現しています。HTC Viveは、Oculus Riftと逆の方法、部屋の2角に赤外線を発光するベースステーションを設置し、ヘッドセットやハンドデバイスに内蔵のカメラで赤外線を受光することでトラッキングをしているようです。これにより、ルームスケールと呼ばれる「CG空間を歩き回る体験」や、まるで自分の手がCG空間に現れたかのような秀悦な操作感が実現されています。
f:id:tuti107:20161127153421p:plain
しかし、これらポジショントラッキングやハンドデバイスには高度が技術が必要となり、廉価版であるモバイルVRでの実現はコスト的に困難です。Vico VRのように、ポジショントラッキングや手足による入力に対応している(らしい、コンシュマー版は未出荷)ものもありますが、それなりのお値段のようです。
今回は、有名なARエンジンである「Vuforia」を利用して、簡易なポジショントラッキングを実現してみます。

Daydream Technical Preview

はじめに、前回説明した、Daydream technical previewのUnityを起動し、適当なプロジェクトを作成してください。
おそらく通常のUnity + Google VR SDK for Unityの組み合わせでの開発も可能かと思いますが、AndroidManifestがVuforia/Google VR SDKで競合するなど、いろいろと面倒な問題が発生するため、今回は割愛します。

Vuforiaのライセンスキー登録

Vuforiaを利用したアプリを開発する際、以下の手順でライセンスキーの登録が必要となります(下記の手順の場合は無料です)。

  1. Vuforiaにログインの後、こちらより、Add License Keyボタンを押下する。
  2. Project TypeよりDevelopmentを選択、Project Detailは、App Nameには適当な名前、DeviceはMobileを選択し、Nextボタンを押下する。
  3. "By clicking "Confirm" below, ..."をチェックし、Confirmボタンを押下する。
  4. License Managerに表示されるアプリ一覧より、2でApp Nameとして入力したものを選択する。
  5. License Keyが表示されるので、これをコピーする。
  6. Unityに戻り、ARCameraのインスペクタを開く。Vuforia BehaviorコンポーネントのApp License Keyにペーストする。

Targetの登録

次に、認識対象となるイメージの登録を、以下の手順で行います。

  1. Target Managerで、Add Databaseボタンを押下する。
  2. Create Databaseポップアップにて、Nameには適当なデータベース名を、TypeはDeviceを選択し、Createボタンを押下する。
  3. Target Managerのデータベース一覧に2で追加したデータベースが追加されるので、これを選択する。
  4. Add Targetボタンを押下する。
  5. Add Targetポップアップにて、TypeはSingle Image、Fileには適当なイメージファイル、widthには実世界(プリントアウトしたイメージ)のサイズ(単位はメートル)、Nameには適当な名前を入力し、Addボタンを押下する。
  6. Download Databaseボタンを押下し、Download Databaseポップアップにて、Unity Editorを選択し、Downloadボタンを押下して、データベース(unitypackage形式)をダウンロードする。
  7. ダウンロードしたパッケージをインポートする。すると、Assets/StreamingAssets/QCARに、データベースが読み込まれる。
  8. ARCAmeraオブジェクトのDatabaseLoadBehaviorコンポーネントに、Load データベース名 Databaseというチェックが現れるので、これをチェックする。また、これをチェックすると現れる「Activate」もチェックする。

f:id:tuti107:20161127200849p:plain

VuforiaがTargetを認識した時の処理

  1. Assets/Vuforia/Prefabs/ImageTargetをシーンに追加する
  2. ImageTargetオブジェクトのImageTargetBehaviorコンポーネントについて、インスペクタにて、TypeはPredefined、Databaseはデータベース名、Image Targetはターゲットの名前を選択する。また、Enable Extended Trackingにチェックを入れる。
  3. f:id:tuti107:20161127201605p:plain
  4. ImageTargetオブジェクト配下に適当なオブジェクト(以下の図の場合はCube)を適当なサイズで配置する。なお、Extended Trackingの効果をわかりやすくするために、縦方向に長くしています。
  5. f:id:tuti107:20161127202058p:plain
  6. 認識用のイメージを印刷する。サイズはAdd Targetにて設定した横幅とする。

フロントカメラ搭載のノートPCやMacをご利用の方は、エディタ上にて実行し、印刷したターゲットのイメージにカメラを向けると、上記のCubeが撮影イメージ上に表示されます。また、Extended Trackingをチェックすると、カメラからターゲットのイメージが外れてしまってもCubeが適切な位置に表示され続けます。つまり、一度でもターゲットのイメージを認識すると、その後はターゲットのイメージの周囲の情報をリアルタイムに認識することで、ターゲットのイメージがカメラ内に無くてもまるでターゲットのイメージがカメラ内に捉えられているかのごとく振舞います(当然、周囲に動くものがある場合はダメなようです)。
www.youtube.com

Google Cardboardとのインテグレーション

  1. ARCamera配下のCameraをDisableする。また、ARCameraオブジェクトのVideoBackgroundManagerコンポーネントのEnable video backgroundチェックを外す。これらは、スマホで撮影したカメラプレビューを背景映像として表示するためのものですが、ポジショントラッキングの用途には不要なためです。
  2. ImageTarget配下のCube(もしくは上記で追加した何らかの3Dオブジェクト)をDisableする。こちらもポジショントラッキングには不要なためです。
  3. シーンのルートにEmptyObject(名前をPlayerとする)を配置、そこにCameraをぶら下げる。このCameraのTagはMainCameraとする。
  4. 以下のPositionTracker.csを作成し、Playerにコンポーネントとして設定する。
  5. using UnityEngine;
    using System.Collections;
    
    public class PositionTracker : MonoBehaviour {
      public GameObject arCamera;
    	
      void Update () {
        var p = arCamera.transform.position;
        gameObject.transform.position = new Vector3 (p.x, p.z, -p.y);
      }
    }
    

  6. Cameraの前に適当な3Dオブジェクト(Cubeなど)をシーンに配置する。

  7. Assets/Plugins/Android/AndroidManifest.xmlのandroid:minSdkVersionを"16"に変更する。
  8. 前回説明した手順にて、Virtual Reality Supportedをチェック、SDKをCardboardとして、Android向けにビルドする

品質は微妙

アプリ起動前に、ターゲットイメージを印刷した紙を(多少ごちゃごちゃした)壁・棚などに貼り付け、この紙の方を向いて端末を起動してください。
f:id:tuti107:20161127220737p:plain

紙に近づけばCubeが大きく、左右に動いたりしゃがんだりすればCubeはそれぞれの方向に動きます。ちゃんとシーンを構成すれば一応ポジショントラッキングのあるVR、な感じになります。以下は、Editorで実行し、前後上下左右にMacを動かした際のものです。
f:id:tuti107:20161128211500g:plain

ただ、品質があまりよくありません。静止していてもプルプル動くし、時々変な方向に飛んでしまうし。。シンプルにARCameraの座標を使うのでは無く、ちょっと一工夫が必要のようです。
また、私のAndroid端末(Galaxy S6)でGoogle Cardboard使用中にデバイスのカメラを利用するためには、Google Cardboardに切れ込みを入れる必要がありました。。
f:id:tuti107:20161127220810j:plain

Daydream technical previewを使ってみる

はじめに

先月注文したPixelとDaydream View、ようやく発送されました。ただ諸事情により手元に届くのは、あともう二週間後になりそうです。
今回は、実機入手後すぐに開発にとりかかるべく、Unity Daydream technical previewの導入を試してみたいと思います。

Daydream technical previewのインストール

f:id:tuti107:20161126122619p:plain
Daydream technical previewは、こちらよりダウンロードできます。本ページをずっと下にスクロールしていくと、インストーラのダウンロードボタンが見つかります。

インストールが完了しましたら、デスクトップに生成されたショートカットより、Daydream technical previewを起動します。
f:id:tuti107:20161126122959p:plain
すると、「普通」にUnityが起動します。ただしタイトルバーを見ると「Unity 5.4.2f2-GVR12」となっており、これがGoogle VR向けのものであることが確認できます。
f:id:tuti107:20161126123258p:plain

NativeサポートされたGoogle Cardboard

まずは(手元に実機もありませんので)Google Cardboard向けのアプリを作ってみます。
前回Google VR SDK for Unityを利用したアプリの作成について詳細をした際は、「GoogleVRForUnity.unitypackage」をインポートしましたが、Daydream technical previewではGoogle CardboardがNativeサポートされているため、立体視表示やヘッドトラッキング等のVRの最低限の機能については、本SDKを利用する必要はありません。その代わりに以下の通りの設定を行います。

  1. File→Build Settingsより、PlatformをAndroidとする
  2. Player SettingsのOther Settingsにて、Virtual Reality Supportedにチェックを入れる
  3. +ボタンを押下し、Cardboardを選択する
  4. 同じくOther Settingsにて、Minimum API Levelを16以上とする
  5. Bundle Identifierに適当なものを設定する

f:id:tuti107:20161126125443p:plain

f:id:tuti107:20161126125524p:plain

以上を設定の後、Build and Runにて、Android端末上にCardboard向けVRアプリが起動します。
アプリといっても、Sceneに何も配置していないので、デフォルトのSkyboxが表示されるのみですが。。
f:id:tuti107:20161126130036p:plain

さいごに

今回は、Daydream technical previewのインストールし、とりあえず実機上で動くアプリをビルド・実行してみました。
次回は、Gaze入力等、もう少し詳細まで踏み込んでみたいと思います。

Google VR SDK for Unityをより詳細に見てみる

前回は、Google VR SDK for Unityをインストールし、付属のDemo SceneをとりあえずAndroid端末上で実行してみました。特段なにもはまることなく、スムーズに実行まですすめることができました。
一方で、Demo Scene内のオブジェクトを見てみると、Google Cardboard SDKのときにはなかった色々な名前のオブジェクトがあることに気づきました。実行画面のぱっと見、Demo SceneはGoogle Cardboard SDKのものとほぼ同じなのですが、SDK自体は大きく異なるのかも?
f:id:tuti107:20161021214817p:plain
ということで、今回はGoogle Cardboard SDKとの差異を中心に、Google VR SDK for Unityついて、詳細に見てみました。

ほぼ一緒でした

結論からいうと、Google VR SDK for UnityとGoogle Cardboard SDKは概ねよく似ております。名前や機能分割による違いがメインかと思います。
Google Cardboard SDKは、

  1. CardboardMainというprefabを設置→これだけで左右眼分割表・樽状のゆがみ表示・ヘッドトラッキングの「VRっぽい機能」が動きます
  2. EventSystemにGaze Input Moduleを追加し、CardboardMainにGazeポインタを設置→ユーザが見ている位置にポインタが表示されます
  3. EventTriggerを実装した適当なオブジェクトを用意→上記ポインタがオブジェクトに入る・出る・クリックする等のイベントを受けることができます

との手順で、VRアプリを簡単に作成することができましたが、Google VR SDK for Unityでは、

  1. GvrViewerMain prefabを設置→左右分割・樽状のゆがみ表示・ヘッドトラッキングを行う
  2. EventSystemにGaze Input Moduleを追加し、Main CameraにGazeポインタとなるGvrReticle(円形のポインタ)を置く
  3. EventTriggerを実装した適当なオブジェクトを用意

ということでほぼ一緒です。Google Cardboard SDKでごちゃごちゃしていて複雑だったところが、すっきりした、という感じです。

GvrViewerMain

本オブジェクトは、左右分割・樽状のゆがみ表示・ヘッドトラッキングといったVR的機能を提供します。
f:id:tuti107:20161021220843p:plain

  • VR Mode Enabledは、VR表示(左右眼分割表示)をするかどうかを設定
  • Distortion Correction Enabledは、樽状の歪み表示をするかどうかを設定
  • Stereo Screen Scaleは、1より低い値とすると画質悪いが高速、1より大きい値(最大2)とすると高精細だが低速となる
  • Neck Model Scaleは、首のオフセットを考慮したより正確なヘッドトラッキングを行う。0(未使用)~1の値を設定。Daydream端末だとわかる感じなのでしょうか?私には設定時の違いがあまりわからず。。

Main Camera

こちらは、Google Cardboard SDKとほぼ一緒です。
f:id:tuti107:20161022083056p:plain
留意点としては、AudioListenerがGvrの名称に変わっていること、くらいです。なお、Google Cardboard SDKと同様なのですが、Physics Raycasterを追加しておかないと、Gazeポインタが表示されません。
GvrAudioListenerによる音空間設定については、また別途の機会に触れたいと思います。

GvrReticle

円形上のGazeポインタです。MainCamera配下にこれを配置することで、向いている方向中央に
- ポイントが乗った・外れたこと(PointerEnter/PointerExit)通知を受けるオブジェクトがある場合は、大きな円に
- それ以外は点で
ポインターが表示されます。
f:id:tuti107:20161022084337g:plain
インスペクタで、表示される円について詳細設定ができます。
f:id:tuti107:20161022091236p:plain

  • Reticle Segmentsは、円描画の点の数を指定します。この値が少ないと円ではなく多角形な感じになります(以下は5を指定の場合)

f:id:tuti107:20161022090925p:plain

  • Reticle Growth Speedは、ポインタがオブジェクト上に乗った際に、点→円になる速度を指定します。すくないほどゆっくりとなります。

GvrReticleは、後述のGazeInputModuleを利用して、オブジェクトに乗った・外れた等の判定をします。なお、この(複雑な)GazeInputModuleを使用せず、シンプルにポインタ表示を行う手段としてGvrGazeがあります(こちらもいずれ紹介しようと思っています)。

GazeInputModule

EventSystemにGazeInputModuleを追加することで、Unityにおけるマウス・キーボード等の入力イベントの共通配信システムであるEventSystemを利用してGazeポインタ関連イベントを利用できるようになります。
例えば、DemoSceneの足元には、以下のようなボタンが配置されていますが、
f:id:tuti107:20161022093134p:plain
これらボタンが押下された場合の処理は、プログラムを記述する必要なく、簡単に設定することができます。
f:id:tuti107:20161022093422p:plain
この場合は、Cubeオブジェクト、Teleportコンポーネントの、ToggleVRMode()メソッドが、ボタンクリック時に呼び出されます。
EventSystemによるGaze関連イベントはボタン等のGUI部品のみならず、自作のGameObjectにも設定可能です。
DemoScene内のCubeオブジェクトには、以下のようにEventTriggerコンポーネントが追加されており、そこでPointerEnter/PointerExit/PointerClickがそれぞれ追加されております。このようにすることで、このCubeオブジェクトはGazeポインターが入ったとき・出たとき・クリックされたときにそれぞれ指定のメソッドが呼び出されるようになります。
f:id:tuti107:20161022094323p:plain

さいごに

以上、今回はGoogle Cardboard SDKとGoogle VR SDK for Unityの差異を中心に、Google VR SDK for Unityの詳細を見ました。これら2つは非常に似た感じですが、Google VR SDK for Unityのほうが、よりシンプルにまとめられていると感じました。
今回ご紹介の内容だけで、簡単なVRコンテンツは充分に開発可能かと思います。次回は、音響周りを中心に見ていこうかな、と思っています。