ARKitができる事、できない事

iOS 11から利用できるようになるARKitについて概要をまとめます。この記事では概念や機能として何ができて何が難しいのかを書いているので、エンジニアのみならずサービスや企画を考える方にも参考になるかもしれません。具体的なUnityでの実装方法は別途記事を書く予定です。

注意点：

- Unity ARKit Pluginに基づいた情報のため、iOSのネイティブコードでARKitを直接利用する場合とは異なる部分があるかもしれません。
- 情報は2017/06/17時点のものです。

# サマリー
## ARKitができる事
- ポジショントラッキング
- 平面検出
- ポイントクラウド（3次元の点座標情報）取得
- 周囲の明るさ推定
- 現実空間への当たり判定（HitTest）
- 現実空間とのスケール一致
- カメラ画像の取得

## ARKitができない事
- 取得した情報の保存/読み込み
- 現実空間の位置との関連付け
- 精度の高いリアルタイムなポイントクラウド取得
- ポイントクラウドからのジオメトリ生成
- マーカートラッキング

# ARKitとは
ARKitは、iOS11以降かつ__iPhone 6s以降__（A9チップ以降）で利用できるようになるARフレームワークです。
追加のハードウェアが不要なので、__iOS 11が公開されると同時に全世界で数千万台の実行環境が生まれる__事になります。
カメラ画像に加えて端末のセンサーを駆使している点、OSレベルで処理される点から、__従来のARライブラリよりも低負荷、高精度__であるとされています。またiOSに標準で含まれるため無料で利用できます。

- [AppleのARKitポータル](https://developer.apple.com/arkit/)
- WWDCでのARKitデモ動画（クリックで再生）  
[![ARKit DEMO](http://img.youtube.com/vi/VAvMTJ_LVNE/0.jpg)](http://www.youtube.com/watch?v=VAvMTJ_LVNE)

## Unity ARKit Plugin とは
Unity Technology社が公式に提供しているオープンソースのARKitのUnity用プラグインです。
ARKitの薄いラッパーとなっており、現時点のARKitの機能はほぼカバーされています。

- [Unity ARKit Pluginレポジトリ](https://bitbucket.org/Unity-Technologies/unity-arkit-plugin)
- [Unity ARKit PluginコミッタのTwitterアカウント](https://twitter.com/jimmy_jam_jam)  
TwitterやYouTubeで公開されている、Unity + ARKitの作品がひたすらRTされています

# ARKitができる事

## ポジショントラッキング
- 現実空間での自分（iOS端末）の位置と向きが取得できます。
- この位置と向きは、カメラとセンサ情報を元に構成した__3D空間内での相対位置__です。Unityの3D空間内に置いたカメラを端末で移動/回転できるようになると考えると分かりやすいかもしれません。したがって緯度経度的な意味での現実世界での絶対座標や高度は得られません。
- ポジショントラッキング（以下「ポジトラ」）は__VRアプリでも活用が可能__です。従来のスマホVRはジャイロセンサーによるヘッドトラッキング（頭の回転）のみで、ポジショントラッキング（頭の移動）はできませんでした。しかしARKitのポジトラを使えばそれが可能になります。ただし背面カメラで外を映す必要があるので、端末を完全に覆ってしまうタイプのVRゴーグルの場合は利用できないのが弱点と言えば弱点です。

## 平面検出
- 机や床などの平面を__3D空間上の平面__として取得できます。
- 取得できるのは水平面のみで、壁などの垂直面は取得できません（2017/06/17時点）。
- ARKit起動後すぐに検出される訳ではなく、検出するためには平面がカメラに映った状態で移動したり見る角度を少し変えたりする必要があります。経験的には__起動後検出まで早くて3〜4秒かかります__。
- 複数の平面を認識、維持する事ができます
- 同一平面と推定されるものは自動的に結合されます。例えば同じ床の少し離れた場所を別の平面として認識していても、歩いていると結合して1つの床となったりします。
- __平面情報は矩形__です。仮に床が三角だったり曲線的な壁で構成されていても、その形では取得できません。

## ポイントクラウド（3次元の点座標情報）取得
- 現実空間内に存在する物体について、__点単位で3D空間上の座標__を取得できます。イメージとしては、端末から光線をランダムな方向に撃ちまくって、何かにぶつかったらそのぶつかった位置を取得できる、という感じです。
- 多い時は秒間数百点以上取得できます。
- あくまでカメラ映像からの推定であるため、以下の欠点があります。
  - __見た目の特徴が少ない物（白い壁など）はほぼ点が取得できません__。Google Tango等の深度センサ計測に決定的に及ばない点がこれです。
  - 何もない空間上に点を検出するなど、ノイズが時々混じります。感覚的には数百点に1点くらいです。

## 周囲の明るさ推定
- 周囲の明るさを単一の数値として取得する事ができます
- 単一の数値なので、__「全体として明るか暗いか」という情報のみ__です。光源の場所や個数などは取得できないので、この情報から高度なIBLは実現できません。

## 現実空間への当たり判定（HitTest）
- UnityのRaycastのようにカメラ（端末位置）から指定した位置に見えない線を伸ばし、当たり判定を行う事ができます。
- ヒットさせる対象として、ARKit認識済みの平面だけでなく、__その場で線の先が平面かどうかを判定してヒットさせる事もできます__。
- 認識済みの平面については、「認識している矩形部分のみ」か「認識している矩形を延長した平面全体」かを指定できます。後者の場合、足元の床の狭い範囲のみ認識した段階で部屋全体の床（があると思われる位置）にヒットします。ただしあくまで仮想的に延長したものなので、実際にそこに平面があるかどうかや途中に遮蔽物があるかどうかは無関係です。

## その他
- 3D空間と現実空間のスケールが一致しているので、床との距離や机の長さを測るといった事も可能です。
- ARKitが使っているカメラの画像をテクスチャとして取得する事ができます。逆に、ARKitで処理はするけど画面に表示しない事もできます。

# ARKitができない事

## 取得した情報の保存/読み込み
- 認識した平面やポイントクラウドの情報全体を保持したり、それを後から読み込んでその続きとして動作させる事（Google Tangoで言うArea Learning）はできません。
- 取得した情報を自力保存する事はもちろんできますが、それをARKitに与える手段が無いのでARKitの動作としてはあくまで起動ごとに毎回初期状態からの認識開始となります。

## 現実空間の位置との関連付け
- ARKitが認識する空間はあくまで認識した空間上の点や平面から構成される相対的なもので、現実空間の何か位置と合わせる事はできません。
- 例えば同じ部屋にいるプレイヤー同士のマルチプレイARゲームを作る場合、全プレイヤーが同じUnity空間を共有してその中でそれぞれの位置を決定する必要がありますが、ARKit単体では位置合わせ用の情報が無いためできません。
- それをやりたい場合、ARKit外でマーカー認識をするなり、「まず全員の端末を同じ場所に集めてタップしてから開始」のように、何らかの別手段を併用する必要があります。

## 精度の高いリアルタイムなポイントクラウド取得
- ポイントクラド取得の項目でも書きましたが、ポイントクラウドはノイズが混じる、見た目の特徴によって認識精度に大きな差が生じるといった欠点があります
- 自分の手で3D空間の物体を隠すようなオクルージョンを行いたい場合、画面に映る手の範囲をリアルタイムに認識する必要がありますが、試した範囲では手を映して動かしてみても数個の点が発生するのみで、その情報からオクルージョンできるような精度ではありませんでした。それをやりたい場合はOpenCV等を使って別途処理をする必要があります。

## ポイントクラウドからのジオメトリ生成
- ポイントクラウドをつないで良い感じのジオメトリを作りたいところですが、そのような機能はありません。やりたい場合は自力もしくは別のライブラリでポイントクラウドを処理する必要があります。

## マーカートラッキング
- 予め登録した画像や物体を検知/追跡するマーカートラッキング機能はARKitに含まれていません（2017/06/17現在）
- マーカートラッキング機能を持つVuforia（ARライブラリ）を併用しようとしたけどカメラが競合して上手くいかなかったという報告があるので、別途行う場合は共存させる工夫が必要そうです。
- ARKitと同時に公表された[Visionフレームワーク](https://developer.apple.com/documentation/vision)がそのあたりで使えるかもしれません。

# 以前書いたUnityでARKitを使う記事
[UnityでiOSのARKitを動かす手順](http://qiita.com/arumani/items/aac7372a171e441e1f16)
[Unity ARKit Pluginのチュートリアル日本語訳](http://qiita.com/arumani/items/74dc65ceb9c90bd986ee)