【ARKit】今日からはじめる AR プログラミング Part.1「現実空間をトラッキングする」

#この記事について
AR（拡張現実: Augmented Reality） は未来の社会に大きな変化をもたらすテクノロジーだから、今のうちから始めておこう！
まずは、ARKit を使った限りなくシンプルなアプリケーションを作成してみる。

#どんな人のための記事？
- Xcode の基本的な使い方を理解している。
- Swift プログラミングの基本を理解している。
- AR に興味があるけど、何から始めるべきかがわからない。

#要件
- Xcode10 がインストールされた Mac
- A9 プロセッサが搭載されている iOS11以降がインストール済みの iPhone 実機が必須（この記事では iPhoneX を使用）

# ARKit とは
Apple が WWDC2017 で発表した拡張現実アプリケーションを開発するためのフレームワーク。
WWDC2018 では、ARKit2 が発表された。
A9 プロセッサが搭載されている iPhone と iPad で動作する。
デバイスカメラとモーションセンサーのデータから現実空間を認識し、その画像に 2D や 3D のコンテンツを重ねて表示することで、それらの仮想オブジェクトがあたかも現実に存在するかのような体験をユーザにさせる。

# 開発するアプリケーションの概要
- Single View App テンプレートからARKitを使うことで、基本的な仕組みを理解する。
- アプリケーションに実装した ARKit が、カメラ画像を解析して平面を検出するための特徴を検出している様子を確認する。
- 平面を検出したり、仮想オブジェクトを配置したりはしない。

#手順
##1. Xcodeプロジェクトを作成
本来なら、Augmented Reality App テンプレートを使用すると、よりシンプルな手続きで AR アプリを開発できるが、ここでは ARKit が動作する仕組みを理解するために Single View App テンプレートを使用する。
###プロジェクトの設定
以下の項目以外は、自由に設定しても基本的には大丈夫。
テンプレート: Single View App
使用する言語: Swift

###ユーザーからカメラの使用許可を得る。
Info.plist に以下のキーを追加する。

|Key               |       Type        |    Value          |
|:-----------------|:------------------|:------------------|
|Privacy - Camera Usage Description|String |ARを体験するために、カメラを使用します。|

###アプリの動作対象をARKit対応デバイスに制限する
Info.plist にある「Required device capabilities」セクションに、以下のキーを追加する。

|Key               |       Type        |    Value          |
|:-----------------|:------------------|:------------------|
|item1|String |arkit|

##2. ユーザーインターフェース
###iPhoneX に対応させる
エディタエリアに表示されているデバイスを iPhoneX に変更する。
###AR 体験のためのビュー
シーンに ARSCNView 型オブジェクトのビューを配置する。
正式な名称は「ARKit SceneKit View」と表示されている。
このビューは、カメラが撮影している映像に仮想オブジェクトを重ねて表示することができる AR 機能が満載のビュー。
###オートレイアウト
セーフエリアを超えて、画面いっぱいに表示させる。
###IBOutlet 接続
アシスタントエディタに切り替えて、ARSCNView をソースコードに接続する。
ここでは「myArSceneView」とした。

```ruby:ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var myArSceneView: ARSCNView!
    
}
```

##3. ソースコード
ARKit のデバッグ機能を使って、カメラ画像から特徴点を検出している様子を視覚化する。

###ARKit フレームワークをインポートする
ARKit は UIKit を含んでいるので、`import UIKit`を削除しても実際には問題ない。

```ruby:ViewController.swift
import UIKit
import ARKit
```

###セッションを生成する
空間トラッキングは、セッションが実行中のみ行われる。
AR 体験を実現するための様々な機能を提供してくれるセッションは、`ARSession` 型のオブジェクト。
生成したセッションは、AR専用ビューのプロパティにしておく。

```ruby:ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let mySession = ARSession()
        myArSceneView.session = mySession
        
    }
```


###デバッグ情報を表示する

```ruby:ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let mySession = ARSession()
        myArSceneView.session = mySession
        
        myArSceneView.showsStatistics = true
        myArSceneView.debugOptions = ARSCNDebugOptions.showFeaturePoints        
    }
```

###コンフィグレーションを指定して、セッションを実行する
アプリケーションが画面に表示されたら、空間トラッキングを開始する。
`configuration` オブジェクトに、このセッション中に現実空間のどんな情報をトラッキングするかを指定することができる。
今回は、特別な機能は指定しない。

```ruby:ViewController.swift
    override func viewDidAppear(_ animated: Bool) {
        let configuration = ARWorldTrackingConfiguration()
        myArSceneView.session.run(configuration)
    }
```

###セッションを停止する
空間トラッキングはバッテリー消費が激しいので、アプリケーションがバックグラウンドに移行したタイミングでセッションを停止させる。

```ruby:ViewController.swift
    override func viewWillDisappear(_ animated: Bool) {
        myArSceneView.session.pause()
    }
```


###ステータスバーを非表示にする
AR アプリケーションは没入感を高めることが重要だそう。特に、iPhoneX のベゼルレスデザインはそのためのものだと思われる。余計な情報を表示したくないので、ステータスバーは非表示にする。
ソースコードに、以下の記述をすると画面からステータスバーを消せる。

```ruby:ViewController.swift
import ARKit

class ViewController: UIViewController {
    override var prefersStatusBarHidden: Bool { return true }
    override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { return .slide }

}
```

###完成したソースコード

```ruby:ViewController.swift
import UIKit
import ARKit

class ViewController: UIViewController {

    @IBOutlet weak var myArSceneView: ARSCNView!
    
    override var prefersStatusBarHidden: Bool { return true }
    override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { return .slide }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let mySession = ARSession()
        myArSceneView.session = mySession
        
        myArSceneView.showsStatistics = true
        myArSceneView.debugOptions = ARSCNDebugOptions.showFeaturePoints        
    }

    override func viewDidAppear(_ animated: Bool) {
        let configuration = ARWorldTrackingConfiguration()
        myArSceneView.session.run(configuration)
    }

    override func viewWillDisappear(_ animated: Bool) {
        myArSceneView.session.pause()
    }

}
```

##4.ビルド
実機を接続してプロジェクトを実行する。
iPhoneX をゆっくり動かして、画面に無数の黄色い点が表示されれば、アプリケーションは正しく動作している。

<img width="375" alt="IMG_4460.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/70476/87c30a31-44fe-6e75-715f-c6875f5a77f9.jpeg">


###上手な空間トラッキング
デバイスの向きだけでなく位置も変化させてあげると、ARKit は上手に特徴点を見つけてくれる。
また、模様がない面（MacBook のパームレスト部分みたいな...）や反射が強かったり透明な面（ペットボトルとか）は、特徴を見つけてくれない。
反対に、木目調のパネルや石畳なんかは特徴点をたくさん見つけてくれることがわかる。

#次のステップへ
[今日からはじめる AR プログラミング Part.2](https://qiita.com/chino_tweet/items/a8a3f68cdadaf2e307ba) では、SceneKit を使って 3D コンテンツでリアル空間を拡張してみる。