ARKit 2.0の何が凄いのか

![ARkit2_Lifestyle-room_06042018.jpg](https://qiita-image-store.s3.amazonaws.com/0/111366/79568870-214a-26d4-a80c-894228cb0f1c.jpeg)

WWDC2018で発表されたARKit2.0

WWDCでのビデオからの情報やAppleの公式Documentsに載っている情報を元に書いていきます。

**追記**
iOS12がリリースされたので、サンプルコードを作りました！ 👇👇👇
サンプルコードを作ってわかったことを元に本記事も加筆訂正を加えています。

**[kboy-silvergym/ARKit-Emperor](https://github.com/kboy-silvergym/ARKit-Emperor)**

# 新しいARAnchor

AREnvironmentProbeAnchor, ARObjectAnchorはARkit2.0で追加された新しいAnchor。ARAnchorクラスを継承している。

今まで**ARPlaneAnchor**(ARKit1.0から), **ARFaceAnchor**(ARKit1.0からiPhoneXのみ), **ARImageAnchor**(ARKit1.5から)などがあったが、ARKit2.0で新たな２つが追加された。

Anchorと言えば、最近のARCore1.2におけるCloud Anchorが思い出される。

[ARCoreのCloud AnchorsをSwift, iOSで試してみた](https://qiita.com/k-boy/items/69e345fc69d681a9bff3)

CloudAnchorを利用する際は、以下のようにGARAnchorのtransformから`ARAnchor`を生成していた。

```swift
    func session(_ session: GARSession, didResolve anchor: GARAnchor) {
        let arAnchor = ARAnchor(transform: anchor.transform)
        sceneView.session.add(anchor: arAnchor)
    }
```

**空間をより一意に認識するために**、このAnchorが欠かせない。

今回追加された２つに対する僕の理解は以下。

## AREnvironmentProbeAnchor
https://developer.apple.com/documentation/arkit/arenvironmentprobeanchor

`An object that provides environmental lighting information for a specific area of space in a world-tracking AR session.` は直訳すると、**特定環境におけるライティング情報**。

こちらも今回から追加された、`var environmentTexture: MTLTexture?` というpropertyがあって、Anchorに対するテキスチャ情報が取れる。

<img width="408" alt="スクリーンショット 2018-06-10 12.35.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/52619197-48dd-4efc-34a2-7b1c82e53ac0.png">

WWDC2018の[What’s New in ARKit 2](https://developer.apple.com/videos/play/wwdc2018/602)では、テーブルの上に現実のバナナを置いたときに、銀のバケットにバナナの様子を反射することができ、AR物体のりんごのバケットの環境をよりリアルに表現できるようになったと説明している。

銀のバケットにバナナの反射が写り込んでいるのがわかるであろうか？これがARKit1.xではできなかったこと。

[engaget](https://japanese.engadget.com/2018/06/08/arkit2/)の記事の解説が分かりやすかったので以下に引用。

>鏡や銀食器はもちろん、車のボディやスマホの画面、磁器に至るまで、およそ光沢のあるものには、すべて「周囲の風景や色」が反射している。この反射を物体に映し込む技術を「環境マッピング」という。ゲームでいえば、メタルマリオのテカり感や、グランツーリスモの車のボディのなまめかしさだが、ARKit 1までは環境マッピングに対応していなかったので、「現実にあるものをCGの物体に反射させる」ことができなかった。これだとどうしても「合成っぽさ」が残る。

>しかしARKit 2ではカメラが捉えた現実の世界の状況から、反射のための「環境マップ」がリアルタイムに生成され、物体に反映される。この写真の場合、リンゴの入った金属の食器はCGであり、バナナは実際に机の上にあるものだ。ARKit 1ではバナナの黄色は反映されないが、ARKit 2では、ぼんやりとバナナが映り込んでいる。 
https://japanese.engadget.com/2018/06/08/arkit2/


## ARObjectAnchor
https://developer.apple.com/documentation/arkit/arobjectanchor

物体を勝手に認識してくれて、今までのPlaneAnchorなどと同じようにAnchorを付与してくれる。これはかなりデカイ。

ARKitとVisionを使って物体認識してそこに何かを貼り付けるというサンプルを作ったことがあるが、Visionで得られる物体情報は2DのboundingBoxだったので、そこの側面を座標まで得ることはできなかった。ARObjectAnchorのおかげでかなりそれがやりやすいはず。

ARObjectAnchorには、`var referenceObject: ARReferenceObject` というプロパティがある(これもARKit2.0から)。次に続く。

# スゴイ物体認識
|物体をスキャン|それを認識|
| --- | --- |
|![GIF image-8C238A00CA21-1.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/6891959b-ae0f-094b-d49e-ebbaae0c709b.gif)| ![GIF image-A27D4DEE9665-1.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/ed91bdae-c9ec-9f97-6c4b-c1fc25ba785c.gif) |
## ARReferenceObject
https://developer.apple.com/documentation/arkit/arreferenceobject

これがスゴイ。

center, extent, scaleというpropertyがあるので、物体を検出し、その位置や大きさなどを検出することができる。（現状事前にその物体のcenter, extent, scaleは作成時に手動で定義しておく必要がある）

これで、実際にある物体を加工したりすることができると思う。SnowやSnapChat, FacebookMessangerでFaceFilterができると思うが、これが物体に対してできるイメージ。

また、

```swift
init(archiveURL: URL)
```

というイニシャライザに注目したい。

ARReferenceObjectは `.arobject` という拡張子のファイルとしてアウトプットすることができ、そしてそれはアプリで使うことができる。さらに、一度アウトプットすれば、そのファイルは他のアプリでもimportして使えて物体認識に利用することができる。

<img width="627" alt="スクリーンショット 2018-06-10 13.15.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/f68b639c-2013-df8a-c643-65b2f435004f.png">

WWDC2018の[What’s New in ARKit 2](https://developer.apple.com/videos/play/wwdc2018/602)では、ネフェルティティの物体を認識して情報を保存し、後から再びみたときもネフェルティティが認識できた様子がデモされていた。

自分もデモアプリを使ってみたが、複数ある別の見た目のタンブラーの中から、正しいタンブラーをboundingBoxごと認識できた。

# 世界ごと保存！？

## ARWorldMap
https://developer.apple.com/documentation/arkit/arworldmap

一度作った拡張現実情報を保存して、次にカメラを開いた時に、同じAnchorを探して、前回と同じような位置に仮想物体が出てくるように再現することができる。

ARSessionに用意された [`getCurrentWorldMap(completionHandler:)`](https://developer.apple.com/documentation/arkit/arsession/2968206-getcurrentworldmap) メソッドを使って、その時の`ARWorldMap` が得られる。

これを以下のような感じでアーカイブできて、

```swift
func writeWorldMap(_ worldMap: ARWorldMap, to url: URL) throws {
    let data = try NSKeyedArchiver.archivedData(withRootObject: worldMap, requiringSecureCoding: true)
    try data.write(to: url)
}
```

以下のように、再現できる。

```swift
func loadWorldMap(from url: URL) {
    let mapData = try Data(contentsOf: mapURL)
    guard let worldMap = try? NSKeyedUnarchiver.unarchivedObject(of: ARWorldMap.classForKeyedUnarchiver(), from: mapData) as? ARWorldMap
        else { throw ARError.invalidWorldMap }

    let configuration = ARWorldTrackingConfiguration()
    configuration.planeDetection = .horizontal
    configuration.initialWorldMap = worldMap
    sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
}
```

ARWorldTrackingConfigurationのinitialWorldMapにセットしてsessionを起動すると、共有元の座標系と同じになるので、複数のデバイスで繋いでゲームするようなときに実装しやすそう。

例えばARCoreのCloud AnchorでもAnchorを共有することができて同じ場所に物を置く実装を容易に実現できるが、それだけでは座標系は一致していないので何らかの方法で座標系を合わせる必要がある。その証拠にGoogleが出している[Just A Line](https://itunes.apple.com/app/id1367242427?mt=8)のアプリでは、「**２つのデバイスの位置を合わせてください**」というメッセージが出てきている。同じ座標系にするのを簡単にするためだ。

<img width="150" alt="just a line" src="https://qiita-image-store.s3.amazonaws.com/0/111366/76b832a6-ac07-995d-e572-f39e20b89cbb.png">

ちなみに[Just a lineのiOSのコード](https://github.com/googlecreativelab/justaline-ios)はgithubに公開されているのだが、ここでは[setWorldOrigin(relativeTransform:)](https://developer.apple.com/documentation/arkit/arsession/2942278-setworldorigin)というメソッドを使って２つのデバイスの座標系を一致させている。

AppleのドキュメントではこのARWorldMapについて、

- Multiuser AR experiences. (複数人でのAR体験)
- Persistent AR experiences (永続的なAR体験)

という２点のAR体験の拡張に貢献すると紹介されていて、
前者は**リアルタイムに同じ場所でAR体験をするようなゲーム**を想起させるし、
後者は例えば**公園の特定の場所に何かを保存して、後から来た人が同じ場所に来た時にそれを発見できる**といった体験を想起させる。

筆者の印象としては、iOS12のデバイスどうしで空間共有体験を実現するためにはARWorldMapを使うのがベストだ。もちろん世界の点群情報が集まった[ARCloud](https://tech.graffity.jp/entry/arcloud)が提供される未来がくればそちらの方が良いかもしれない。

# パフォーマンス向上

## ImageTracking
https://developer.apple.com/documentation/arkit/arimagetrackingconfiguration
https://developer.apple.com/documentation/arkit/arimageanchor

<img width="797" alt="スクリーンショット 2018-06-10 12.49.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/216fcac0-7e85-287f-0bf1-1fe16544c54e.png">

今までは１枚ずつしか画像を検出できなかったが、今回から複数が可能になる。
そして、その認識の精度が向上し、画像が動いていても正確に追跡することができる。

<img width="840" alt="スクリーンショット 2018-06-10 12.50.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/a8ccdfa4-9a80-ebdc-1de4-1e0115fe168c.png">

configurationに画像を登録してから、ARSessionをRunすることで、該当の画像を認識することができるようになる。ARImageAnchorは自動的にSceneKitが発見してくれて、ARSessionDelegateやARSCNViewDelegateでanchorの発見をトラックできる。

ARKit1.5からARImageAnchorは使うことができるが、**ARImageTrackingConfiguration** がARKit2.0から。今までは**ARWorldTrackingConfiguration**を使って同様なことができていたが、新しいconfigulationは画像が動いていても追跡できるという点でパフォーマンスが向上している。その代わりこのconfigulationだと平面認識などができない。

堤さんのブログの[ARKit 2.0の画像トラッキングとARKit 1.5の画像検出の違い](http://shu223.hatenablog.com/entry/2018/08/25/223003)がこの点について詳しい。

WWDC2018の[What’s New in ARKit 2](https://developer.apple.com/videos/play/wwdc2018/602)では、猫の静止画を認識し、その画像の上で動画を再生するというデモを行なっていた。

## Face Detection

|視線|舌|
|:--:|:--:|
|<img width="689" alt="スクリーンショット 2018-06-10 13.27.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/17acbce3-d74d-ab29-3c13-475bd14cf037.png">|<img width="722" alt="スクリーンショット 2018-06-10 13.28.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/2fe2371a-a31f-8a5d-2707-ae7c7e008b52.png">|

Gaze DetectionとTongue Detectrionが追加された。
視線と舌の認識である。

より顔の動きを正確に認識することができるようになった。

こちらは現状iPhoneXだけで使える機能。今後とも対応デバイスが増えて行くであろう。

## Faster Plane Detection

平面認識なども早くなったと言われている。

いつも２、３秒はARSessionの起動にかかるので、これが短くなるのは嬉しい。

<img width="794" alt="スクリーンショット 2018-06-10 13.42.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/099970ac-1f36-d51a-6764-b48b6b2c2c4c.png">

# まとめ

- 実世界にある物体の検出とその保存
- 実世界のマップ情報の保存、再現

これらは使いようによって、かなり面白いことができそうです。

仕事上、ARKit2.0は調べていくので、コードベースでも最新情報はどんどん追記していきます。

何か認識が間違っているものがあればお気軽に教えてください :bow: 

# 公開されているサンプルコード
- [Scanning and Detecting 3D Objects](https://developer.apple.com/documentation/arkit/scanning_and_detecting_3d_objects)
- [Creating a Multiuser AR Experience](https://developer.apple.com/documentation/arkit/creating_a_multiuser_ar_experience)
- [Creating a Game for Augmented Reality](https://developer.apple.com/documentation/arkit/swiftshot_creating_a_game_for_augmented_reality)
- [Adding Realistic Reflections to an AR Experience
](https://developer.apple.com/documentation/arkit/adding_realistic_reflections_to_an_ar_experience)
- [Creating a Persistent AR Experience](https://developer.apple.com/documentation/arkit/creating_a_persistent_ar_experience)

# ARKit 2.0 参考資料
https://developer.apple.com/videos/play/wwdc2018/602
https://developer.apple.com/documentation/arkit

# こちらもチェック

- [今日からは、こう名乗るがよい。ARKit-Emperorと。](https://qiita.com/k-boy/items/760f8b3add6ea283f41c)
- [ARKitのための3D数学
](https://qiita.com/k-boy/items/775633fe3fd6da9c5fb6)
- [ARKitの可能性を知るためにオススメの教材2選
](https://qiita.com/k-boy/items/7e47c818557f6876cf45)
- [ARCoreのCloud AnchorsをSwift, iOSで試してみた](https://qiita.com/k-boy/items/69e345fc69d681a9bff3)
- [ARKitで空間上に写真を置く
](https://qiita.com/k-boy/items/e18e74e8b341f5d5675d)