ARKit2でライドウォッチの使用シーンを再現してみた


[グレンジ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/grenge) 8日目担当の raitome です
グレンジでクライアントエンジニアをやっています
最近[ARKit2](https://developer.apple.com/jp/arkit/)を色々触って、面白そうな機能の使い方を簡単にまとめてみました
そして現在放送中の「仮面ライダージオウ」の変身アイテムである「ライドウォッチ」を使って劇中の使用シーンを再現してみました

##今回ご紹介する機能
・画像認識（ARReferenceImage）
・物体認識（ARReferenceObject）

##技術・環境
・Swift4
・iOS12
・Xcode10
・iPhoneX

##コード書く前の準備
###1.カメラの使用許可を設定する
カメラの使用許可を設定しないと、起動時にクラッシュしますので、info.plistで設定します
<img width="867" alt="スクリーンショット 2018-12-04 8.02.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/218003/d804ebed-dc47-4a5a-e75c-9d1a5c6c44f4.png">

###2.storyboardにARSCNViewを追加する
カメラの映像はこのViewに表示される
<img width="1061" alt="スクリーンショット 2018-12-04 8.01.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/218003/5641e98c-310e-ff68-9115-3f4e3098ad7a.png">
##画像認識（ARReferenceImage）

###1. Assets.xcassetsにAR Resource Groupを追加して認識させたい画像を追加する
複雑すぎる画像だと、場合によって認識しにくいかも
<img width="1134" alt="スクリーンショット 2018-12-04 8.15.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/218003/4b13d5c2-9f74-20eb-80c0-58c431f18b92.png">

###2. override func viewWillAppear内で画像認識用のconfigurationを設定して実行する

```ViewController.swift
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        guard let images = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: Bundle.main) else {
			return
		}
        // Create a session configuration
        let configuration = ARImageTrackingConfiguration()
		configuration.trackingImages = images

        // Run the view's session
        sceneView.session.run(configuration)
    }
```

###3. 認識できた時の動作

func rendererに必要な処理を書く
基本的にSpriteKitの処理を書いて何かを表示させるのがわかりやすい

```ViewController.swift
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        let node = SCNNode()
        let imageAnchor = anchor as? ARImageAnchor
        let referenceImage = imageAnchor?.referenceImage
        let imageName = referenceImage?.name
        // imageNameがAR Resource Groupに追加した画像名と一致する時に、何か処理をする
        return node
    }
```

##物体認識（ARReferenceImage）
###1. 認識させたい物体のデータ（AR Object）を作成する

Apple公式のサンプルアプリを使って、物体のスキャンとデータ作成ができる
[Scanning and Detecting 3D Objects](https://developer.apple.com/documentation/arkit/scanning_and_detecting_3d_objects) 

<img width="252" alt="スクリーンショット 2018-12-04 8.35.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/218003/7a9119ca-8af2-0a32-4111-f2cbab4ee8f3.png">
↑スクショ通りに、物体を各角度からスキャンして、「.arobject」ファイルとして出力する

###2. 画像認識と同じくAssets.xcassetsにAR Resource Groupを追加する
AR ResourceGroupにドラッグ＆ドロップで「.arobject」ファイルを追加する
<img width="636" alt="スクリーンショット 2018-12-04 8.44.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/218003/2c960cef-8d0f-7fb7-3430-906fd9748133.png">


###3. override func viewWillAppear内で物体認識用のconfigurationを設定して実行する

```ViewController.swift
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
		
        // Create a session configuration
        let configuration = ARWorldTrackingConfiguration()
        
        // Object Detection
        configuration.detectionObjects = ARReferenceObject.referenceObjects(inGroupNamed: "KivaObject", bundle: Bundle.main)!

        // Run the view's session
        sceneView.session.run(configuration)
    }
```

###4. 認識できた時の動作

func rendererに必要な処理を書く
基本的にSpriteKitの処理を書いて何かを表示させるのがわかりやすい

```ViewController.swift
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        let node = SCNNode()
        if let objectAnchor = anchor as? ARObjectAnchor {
            // 何か処理を書く
        }
        return node
}
```

##ライドウォッチの使用シーン再現
ご紹介した技術を使って、仮面ライダージオウのライドウォッチで劇中の使用シーンを再現もしてみましたが、周りの環境や光の関係で、認識が鈍い時が結構あるのは少しの難点でした
興味ある方は[動画](https://youtu.be/nqCdRkbYGNo)を見てください

##最後に
ARKit2は他にも機能がたくさんあるみたいで、顔の認識やARWorldMapというのも面白そうので、また今度触ってみたいです