Tangoアプリ開発の基礎知識をまとめる

jyukoです。Tangoの勉強でソースコードを眺めつつ、A-Frameをさわったり、ミニドローン飛ばしたりしてます。

Tangoアプリ開発の取っ掛かりとして、Tangoを理解する上で必要な要素技術をまとめておきます。
Tangoの概要については、[前の記事](http://qiita.com/jyuko/items/2f8f74325b2fc2749f6f)を参照ください。


## デプス・カメラ（depth camera）
深度を測るセンサを用い、奥行きを持った3次元距離画像を撮影するカメラを指すようです。

[PHAB2 Proのスペック](http://www.lenovo.com/jp/catalog/smartphone/2016/phab2_pro_web_0927.html)を改めて見直すと、**深度カメラ （TOF方式）**と記載されていました。
TOF方式は、"Time Of Flight"の略で、赤外線を照射して反射して返ってくるまでの時間で距離を測る仕組みです。

デプス・カメラで3Dスキャンやモーションキャプチャを行うデバイスとしては、[Kinect](http://www.xbox.com/ja-JP/xbox-one/accessories/kinect-for-xbox-one)が有名かと思います。
また、詳しい仕組みは非公開ですが、[LeapMotion](https://www.leapmotion.com/?lang=jp)も赤外線を飛ばして3Dキャプチャを行う点は共通です。

近い将来、スマートフォンを始めとするモバイルデバイスに、デプス・カメラが標準搭載されてくるかもしれません。


## 点群データ（point cloud）
デプス・カメラによって得られるデータの形式です。
メッシュではなく、ポイントの集合体で形状を表しています。

![Point_cloud_torus.gif](https://qiita-image-store.s3.amazonaws.com/0/153460/044fe4ef-2e2b-a86d-5e82-ed5d3c977f4a.gif)

光の反射で測定しているので、一つ一つの点は物体表面の座標になります。
これらの点群データから、メッシュ形式に変換する手法もいくつかあるそうです。

ポイントには、位置(XYZ座標)だけではなく、色(RGB値)を持たせることもできます。
RGBカメラ（普通のカメラ）で得た画像から、デプス・カメラで得た座標に対応する位置のRGB値を取れば、おおよその色情報も含めてキャプチャができます。

Tangoアプリ開発には不要と思われますが、点群データを扱うオープンソースライブラリも紹介しておきます。
[Point Cloud Library (PCL)](http://pointclouds.org/)


## 改めて、Tangoをさわってみる
プリインストールされているGoogleのアプリでは、点群が線でつながり、仮想空間が作られるようなデモが流れます。
![Screenshot_20161216-221122.png](https://qiita-image-store.s3.amazonaws.com/0/153460/561240cd-8c98-318f-6481-f2b49ee835e7.png)


前回の記事でも紹介しましたが、[Tango Unity SDK](https://developers.google.com/tango/apis/unity/)のExampleにある"ExperimentalMeshBuilderWithColor"です。
カメラを向けると室内をキャプチャして、メッシュができていきます。
![Screenshot_20161218-003355.png](https://qiita-image-store.s3.amazonaws.com/0/153460/4a3f8109-740e-2c4e-2faa-a5f13a873509.png)

色情報を持てるpoint cloudをメッシュ形式に変換できるということは、つまりそういうことです。


## Tango Unity SDKのコードを読む
[Project Tango UnitySDK Examples](https://github.com/googlesamples/tango-examples-unity)で、いつでも読み放題です。
点群データ(point cloud)がインターフェースに渡るまでの処理は、以下の3ファイルを眺めているとなんとなく理解できます。


#### TangoSDK/Core/Scripts/TangoWrappers/DepthProvider.cs  

ファイル名やコメントからして、デプス・カメラからの情報を得る[C API](https://developers.google.com/tango/apis/c/)のラッパー。
`UpdateTangoEmulation()`でXYZ座標と色情報を`m_emulatedPointCloud`に詰め詰めしておいて、`GetTangoEmulation()`が呼ばれたらreturnしている。


####  TangoSDK/Core/Scripts/Listener/DepthListener.cs
`SendIfAvailable()`が上記の`_FillEmulatedPointCloud()`で点群データを取ってきて、イベントハンドラに渡している。
`_FillEmulatedPointCloud()`は`DepthProvider.GetTangoEmulation()`でラッパーからデータを取ってきている。


#### TangoSDK/Core/Scripts/TangoWrappers/TangoApplication.cs
`Update()`で`DepthProvider.UpdateTangoEmulation()`実行からの`DepthListener.SendIfAvailable()`しているので、イベントハンドラにpointCloudが渡る。

**見えるぞ！私にもTangoが見える！**


## まとめ
というわけで、最終的には[ITangoPointCloud](https://developers.google.com/tango/apis/unity/reference/interface/i-tango-point-cloud)インターフェースの`OnTangoPointCloudAvailable()`で[Tango.TangoPointCloudData](https://developers.google.com/tango/apis/unity/reference/class/tango/tango-point-cloud-data)が取れます。
XYZとCの配列になっている`m_points`が点群データ(point cloud)です。
使い方は[こちら](https://github.com/googlesamples/tango-examples-unity/blob/b25317a9394657d78716b23ab35d34918cba33a9/TangoWithMultiplayer/Assets/TangoPrefabs/Scripts/TangoPointCloud.cs)。


やはり理論から入ると、API仕様やソースコードの見え方が違いますね。
期せずして、イベント駆動をちゃんと理解するきっかけにもなりました。