iPad Pro の LiDARスキャナ を試してみた[追記あり]


※実行中のスクリーンキャプチャ動画をGIF化しました(更新:2020/06/01)

# はじめに
コロナ禍最中の2020年3月に新型iPad Proが発売されました。個人的に最も惹かれたのは、LiDARスキャナ搭載というところでした。

LiDAR(Light Detection and Ranging：光検出と測距)とは、対象物にレーザーをパルス状に照射し、反射して戻ってくるまでの時間を計測することで距離を測る技術です。この技術の搭載により、AR技術がさらに進化することが期待されています。

それにしても、1秒に地球を7回半回るほど超高速な光を使ってミリ単位(?)の距離の測定ができるなんて驚きです。しかもそんなすごい技術を身近に、手軽に使うことができるようになるなんて。

そんな思いから、さっそく12.9インチiPad Pro を入手し、簡単なコードを書いてその機能を試してみました。

本稿ではLiDARを活用した、実空間の物体の形状認識と、オクルージョン、仮想オブジェクトと現実の物体との物理的な作用を実装したサンプルコードを紹介します。


## 開発環境等
-MacBook (Retina, 12inch, Early 2015)
-macOS Catalina Version 10.15.4
-Xcode Version 11.4.1 (11E503a)
-iPad Pro (12.9インチ) (第4世代)
-iPadOS 13.4.1 (17E262)

# プロジェクトの作成
Xcodeで、テンプレートとして “Augmented Realit App” を選択し、Content Technology には “Reality Kit” を選択してプロジェクトを作成します。

これで生成されるテンプレートに何も加えないままでビルドするだけで、一辺の長さ10cmの仮想の立方体が実空間を背景に重ね合わされて表示されるARアプリが出来上がります。

~~なお、Xcodeのターゲットは、LiDARスキャナ搭載の実機(現状では最新型のiPad Proのみ)か、 Generic iOS Device に設定してください。それ以外だと、 “Use of unresolved identifier ‘xxxxxx’” エラーが出まくります。LiDARスキャナ搭載機のシミュレーターでもダメです。
(無駄に悩んだので念のため)~~
※Xcodeのバージョンが上がったせいなのか(Version 11.5)、現在は、LiDARスキャナ非搭載の実機やシミュレータをターゲットにしてもエラーが出なくなりました。(2020/06/02 追記)

# オクルージョン
従来のARKitでもオクルージョンを実現できていましたが、画像認識をベースにしているので、速度と精度に限界がありました。

LiDARスキャナにより、直接的に実空間の立体形状を把握することができるようになったので、速度と精度が向上しました(定量的な比較はしていませんが)。

具体的には、ViewController.swift の viewDidLoad() に以下のように書き加えるだけでオクルージョンが有効になります。

また、デバッグ用に用意された機能を用いて、LiDARスキャナによって認識された実空間の物体の形状をメッシュ表示することができるので、これも有効にしておきます。

```swift
// SceneUnderstanding設定をいったんリセット
arView.environment.sceneUnderstanding.options = []

// オクルージョンを有効化
arView.environment.sceneUnderstanding.options.insert(.occlusion)

// メッシュ表示の有効化
arView.debugOptions.insert(.showSceneUnderstanding)
```

この程度の簡単なコードでも、十分LiDARの威力を実感できますね。

# タップ位置の検出

画面(ARView)をタップした位置に対応する実空間上の位置を取得することができます。

まず、画面タップした時に呼ばれるハンドラを設定します。
viewDidLoad()に下記の2行を加えておきます。

```swift
let tapRecognizer = UITapGestureRecognizer(target: self, action:　#selector(handleTap(_:)))
arView.addGestureRecognizer(tapRecognizer)
```

以下のように、ハンドラでARView上のタップ位置を受け取り、一番手前にある物体表面の位置を resultAnchor として取得します。
ここでは、その位置に半径1cmの球を配置しています。

```swift
@objc func handleTap(_ sender: UITapGestureRecognizer) {
    let tapLocation = sender.location(in: arView)
    if let result = arView.raycast(from: tapLocation, allowing: .estimatedPlane, alignment: .any).first {
        let resultAnchor = AnchorEntity(world: result.worldTransform)
        resultAnchor.addChild(sphere(radius: 0.01, color: .lightGray))
        arView.scene.addAnchor(resultAnchor)
    }
}
```

# 実空間の物体との物理的作用
公式ドキュメントでは、実空間上のオブジェクトの分類を行っていますが、本稿ではそこは割愛し、代わりに物理計算について補足します。

せっかくLiDARスキャナによって実空間の物体の形状を把握できたので、それと仮想オブジェクトを物理的に作用(要するに衝突)させてみましょう。

まず、実空間の物体の形状に対して物理計算を有効化します。
例によって viewDidLoad() で以下の設定を行えばOKです。

```swift
arView.environment.sceneUnderstanding.options.insert(.physics)
```

前節では、タップ位置に球を出現させていましたが、その球に物理的な性質を与えた上、タップ位置よりちょっと上方に出現させてみます。球の落下と実空間オブジェクトとの衝突を起こすことが観察できます。
球を生成する sphere() をちょっと書き換えます。

```swift
func sphere(radius: Float, color: UIColor) -> ModelEntity {
    let sphere = ModelEntity(mesh: .generateSphere(radius: radius), materials: [SimpleMaterial(color: color, isMetallic: false)])
        
    // 現実の物体と"衝突"できるように設定
    sphere.generateCollisionShapes(recursive: true)
    sphere.physicsBody = .init()
        
    // 重力の影響を受けるように設定
    sphere.physicsBody?.mode = .dynamic

    sphere.position.y = radius+0.1 // 半径＋10cm上空に配置

    return sphere
}
```

# 実行結果

サンプルアプリ実行中のスクリーンキャプチャ(アニメーションGIF)です。

## オクルージョン
真ん中のゴールドの立方体が仮想オブジェクトで、iPad Proの箱の後ろに一部が隠れています。

![iPadProLiDARTestApp-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56444/f5b411c8-c7ec-73e0-2ae4-7e33f9c91596.gif)


## 物理的作用
画面をタップして、仮想オブジェクトの球を置きました。実空間の物体の影響を受けています。

![iPadProLiDARTestApp-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56444/bf8b175b-a3ac-21da-2c90-6aade0be2943.gif)


実行中の画面の通しの動画をYoutubeにアップしました。
https://youtu.be/I0ac0Fe5Ejg


仮想的な立方体と、実空間の物体によるオクルージョン、実空間の物体形状の再現、仮想オブジェクトと実空間の物体との物理的な相互作用などが確認できます。

右奥の Smart Keyboard Folio の箱は傾斜を付けて置いているので、仮想オブジェクトの球を落とすとその表面を転がるのが観察できます。ただ、LiDARスキャナを持ってしても、表面が滑らかに認識されていないようで、途中で引っかかります。

メッシュの細かさから推定するとLiDARの精度は、1cmぐらいでしょうか。ざっくりとした感覚値ですが。この辺はより詳しい方に定量的に検証していただければと思います。

# 最後に
シンプルなアプリを作成して、新型 iPad Pro に搭載されたLiDARスキャナを試してみました。複雑な設定やコードは不要で、想像以上に手軽に扱えることには驚きました。

iPhoneでも次のフラグシップ機にはLiDARスキャナが搭載されることでしょう。

これから様々な応用が考えられると思います。楽しみですね。


## 参考
-Visualizing and Interacting with a Reconstructed Scene
https://developer.apple.com/documentation/arkit/world_tracking/visualizing_and_interacting_with_a_reconstructed_scene
-【ARKit3.5】超簡易検証(手順付)！iPad Pro LiDARの威力を確認！(オブジェクトオクルージョン等)
https://gloria.cool/blog/20200331-lidar-object/

## 個人的な宣伝
GW最終日に、iOS(iPadOS)アプリ「簡単便利な階層型情報メモアプリ HiMemo」を個人開発でリリースしました。
近日中にこれについての記事もまとめたいと思っています。
ご興味のある方は、こちらをご覧ください → https://apps.apple.com/jp/app/himemo/id1506694081