読者です 読者をやめる 読者になる 読者になる

凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Oculus Rift + Senz3D + iisu で VR 空間内に手を入れて遊んでみた

Unity Oculus C#

デモ

「はじめに」が長くなったので、まずは今回取り扱う内容をご覧ください。

はじめに

Senz3D(Creative Interactive Gesture Camera) は、昨年の IFA2013 にて発表されたクリエイティブテクノロジー社製の NUI カメラです。

720pRGB カメラと共に QVGATOF 方式によるデプスカメを備え、15 cm ~ 1 m と比較的近距離のデプス情報を精度よく捉えることが出来ます。271g とやや重めですが、30 fps / 74°と広角、また左右にマイクを備えたハイスペックなカメラになっています。購入は、Intel のサイトからが安くて早いです。

これを利用した有名なライブラリには IntelPCSDK(Perceptual Computing SDKがあり、顔認識や手のジェスチャ認識音声認識といった NUI の機能を提供しています。

f:id:hecomi:20140512234531p:plain

余談ですが、PCSDK のカメラ機能や音声認識機能は Senz3D を持っていなくても扱えます。

Oculus Rift と組み合わせた先行事例としては、第6回ニコニコ学会βシンポジウムにて @mohammedari さんが点群からメッシュを3次元再構成した手を VR 空間の中にいれるデモをされていました(見に行きたかったです...)。

@mohammedari さんも使われていましたが、MakerBot Thingiverse にて、Oculus Rift 用 Senz3D マウンタSTL データが公開されています。

後者が新しい版です。これは、3D センシングのソフトウェア / ハードウェアを手がける SoftKinetic 社の方が作られたモデルです。

Intel の PCSDK に対して、SoftKinetic 社は iisu(The interface is you)という NUI のプラットフォームを持っています。Senz3D は SoftKinetic の DS325 と互換のカメラとのこと*1で、この iisu によるアプリケーションが動作します。

そして、Oculus Rift × Senz3D × iisu のデモが CES 2014 にて披露されていました。

驚くことに、この動画にあがっている Unity によるサンプルプロジェクト一式が Thingiverse にあげられています。

そこで、このサンプルプロジェクトを解読して改造し、VR 内のオブジェクトとインタラクション出来るプロトを作成してみました。導入から解説までを本エントリにまとめたいと思います。

DMM での 3D プリント依頼

まず、Thingiverse でマウンタの STL データをダウンロードします。

次に、これを DMM.make の 3D プリントサービスにアップロードします。

「部品・工具・パーツ」を選択して手順に従ってアップロードします。色々と素材が選べるのですが、私は一番安い石膏を選択しました。値段は 2,247円で送料無料です。5/4 に注文して 5/9 に届きました(早い)。

Senz3D にはカメラ固定具で止められるので Amazon で適当な固定具を仕入れ装着します。

これで Oculus Rift の装着できます。

f:id:hecomi:20140511191209j:plain

iisu 3.6 のインストール

次に iisu 3.6 Free をインストールします。

SoftKinetic のユーザ登録が必要です。ダウンロード時にどこからダウンロードすれば良いか分からなくてハマりましたが、小さいフロッピーディスク型(古い)のアイコンをクリックすればダウンロードできます。

f:id:hecomi:20140514012618p:plain

後は「here」となっているリンクからアクチベーションキーを取得、インストール時にそれを入力すれば完了です。

Senz3D を接続すると DS325(SoftKinetic の 3D カメラ)として認識され、準備完了です。

f:id:hecomi:20140514012823p:plain

これで手を出す準備が整いました。

追記:2014/05/16

iisu Free は3ヶ月試用版のようです

サンプルアプリのインストール

サンプルアプリを動かしてみます。Thingiverse より「UNITY3D-SimpleDemoWith_Sources」および「UNITY3D-CubeDemoWith_Sources」をダウンロードします。

それぞれの Build ディレクトリにサンプルの exe が入っているので実行してみると、冒頭の動画と同じアプリが動作します。キューブをつついたり、グラブアクションによりボールを動かしたりするサンプルと、キューブを3次元のグリッド上に並べられるサンプルになっています。

サンプルアプリの解説

素晴らしいことにこのサンプルは Unity で出来ており、そのプロジェクト一式が Source ディレクトリに入っています(ライセンスは未確認)。仕組みを調べて改造すれば色々と出来そうです。ここでは「UNITY3D-SimpleDemoWith_Sources」について見て行きたいと思います。

全体像

コード及び構造はとてもシンプルになっていて分かりやすいです。

f:id:hecomi:20140514233800p:plain

iisu ディレクトリ下にプラグインが入っており、OVR(Oculus の SDK)も同梱されています。後は標準的なディレクトリ構成になっています。

カメラ画の取得

iisu/Components 下に MonoBehaviour 達が含まれています。IisuFeedbackImage はデフォルトで無効になってますがチェックを入れてアクティブにすると、OnGUI でデプス画を描画してくれるようになります。IisuColorImage をアタッチすればカラー画が表示されます。

f:id:hecomi:20140514235307p:plain

手の描画

手の描画のエントリポイントは HandMesh1 および HandMesh2 にアタッチされている Hand スクリプトです。

private void drawMesh()
{
    HandMeshInfo hmi = iisu.Hands[HandIndex].GetHandMesh(_offset, transform);
    _mesh.Clear();
    
    if(hmi.Vertices.Length == hmi.Normals.Length)
    {
        _mesh.vertices = hmi.Vertices;
        _mesh.triangles = hmi.Triangles;
        _mesh.normals = hmi.Normals;
    }
    
    Graphics.DrawMesh(_mesh, v3Zero, Quaternion.identity, HandMaterial, 1);
}

iisu/DataProviders にある機能をまとめた iisu クラスから手のメッシュデータをもらってきて Graphics.DrawMesh で描画しています。手の表現を変えたかったらここを色々といじれば良さそうです。

物体に触れていることの認識

まず手を触れると色が変わる接触判定についてです。これは Unity のコライダの OnTriggerStay を使って判定しています。実は Hand スクリプト内で、先ほどのメッシュの描画と同じタイミングでメッシュの代表点(Centroids)をコライダ付きのオブジェクトで配置しています。

void Awake()
{
    // ...
    centroids = new Transform[centroidCount];
    for (int i = 0; i < centroidCount; ++i) {
        GameObject centroid = Instantiate(CentroidPrefab) as GameObject;
        centroids[i] = centroid.transform;
        centroids[i].tag = HandIndex.ToString();
    }
    // ...
}

private void drawCentroids()
{
    centroidPositions = iisu.Hands[HandIndex].Centroids;
    for (int i = 0; i < centroidPositions.Length; ++i) {
        centroids[i].position = transform.TransformPoint(centroidPositions[i]);
    }
}

この代表点に使用する GameObjectpublic になっているため、衝突判定を弄りたかったら CentroidPrefab をインスペクタより指定すれば OK です。イメージをつかみやすくするために、デフォルトで指定されている Prefabs/CentroidMesh Renderer コンポーネントにチェックを入れてアクティブにしてみます。

f:id:hecomi:20140515002208p:plain

GrabSphereTouchCube スクリプトではこの球のコライダとの衝突を OnTriggerStya で検知しているわけです。

グラブアクションの検知

GrabSphere を見てみます。

void Update()
{
    if (isTouched) {
        if (!iisu.Hands[touchingHandIndex].IsOpen) {
            transform.position = handReferences[touchingHandIndex].TransformPoint(iisu.Hands[touchingHandIndex].CentralGrabber);
        }
        // ...
    }
}

iisu から IisuHand.IsOpen をもらってきてそれで検知しています。色々なアクションを追加したければここを参考に改造すれば良さそうです。その材料としては、先ほどの IisuHand.GetHandMeshIisuHand.Centroids といった他に、様々な面白い public メンバが公開されています。

HandMeshInfo GetHandMesh(Vector3 offset, Transform reference);
int CentroidCount;
Vector3[] Centroids;
Vector3[] FingerPositions3D;
Vector3[] FingerPositions3DCompensated;
Vector3 PalmPosition3D;
Vector3 PalmNormal3DCompensated;
Vector3 HandTipCompensated;
Vector3 HandTip;
bool IsDetected;
int[] FingerStatus;
Vector3 UpperGrabber;
Vector3 CentralGrabber;
Vector3 LowerGrabber;
int GestureID;

当たり判定のある手にしてみる

少しだけ改造して手に衝突判定をつけるとこんなことが出来るようになります。色々想像膨らみます。

おわりに

今回は、基本のみの紹介になりましたが、色々なパラメタが取れるので、SAO のように手を振って UI を出して指で選択とか出来そうです。是非皆さんも楽しんでみてください。