ARKitで作るAR名刺

ARKitで作る名刺といえば、なんと言っても彼のコンセプト動画です。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">📱AR Business Card Concept <br><br>I created this it using ARKit 2.0 with Image Tracking,<br>Could really be how we interact with business cards in the near future.<a href="https://twitter.com/hashtag/ARKit?src=hash&amp;ref_src=twsrc%5Etfw">#ARKit</a> <a href="https://twitter.com/hashtag/iOS12?src=hash&amp;ref_src=twsrc%5Etfw">#iOS12</a> <a href="https://twitter.com/hashtag/AugmentedReality?src=hash&amp;ref_src=twsrc%5Etfw">#AugmentedReality</a> <a href="https://t.co/6qB7zfLyqM">pic.twitter.com/6qB7zfLyqM</a></p>&mdash; Oscar Falmer (@OsFalmer) <a href="https://twitter.com/OsFalmer/status/1008736572185903105?ref_src=twsrc%5Etfw">2018年6月18日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これは感動しましたね。。！情報が無限大じゃんと思いました。そこで僕も簡単にですが、同じようなものをARKitで作ってみました。

名刺をカメラで読み取ると、Facebookボタン、Twitterボタン、サムネイルと名前が立体的に現れて、

![business_card1.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/a8c2b641-a515-238e-9a8d-7f91bb4e32fe.gif)

ボタンを押すと実際にWebViewで遷移するというものです。

![business_card2.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/e210fe57-933c-886b-4a26-8834685da7d5.gif)

今回はこのシンプルなAR名刺の作り方を紹介したいと思います。

サンプルは https://github.com/kboy-silvergym/ARKit-Emperor にありますので、コードだけみたい方はそちらをチェック。

# AR名刺の作り方
- ボタンの3DモデルをXcodeのScene Editorにて作成
- 名刺を画像マーカーとして登録
- 画像マーカーを読み取ったら、ボタンやサムネイルのSCNNodeを表示
- SCNNodeはできればアニメーションさせる
- タップしたらアクションする

# ボタンの3DモデルをXcodeのScene Editorにて作成

完成形は以下です。

<img width="748" alt="ar_business_card 2.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/993f16b8-b778-9ed1-2904-719bc015830f.png">

本記事ではXcodeのScene Editorを使った3Dモデルの作り方は割愛します。先日私が書いた記事「[SceneKitでプリミティブなジオメトリから3Dモデルを作ろう](https://qiita.com/k-boy/items/14205dd569a57eb44d96)」のやり方と同じ要領で作ることができるので、気になる方はそちらをチェックしてみてください。

気をつけることは、あとから画像を貼ったり、タップアクションを加えたりする要素に対して名前をしっかりつけることです。

<img width="1014" alt="ar_business_card2 2.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/6a86122a-6e19-6c71-b3b2-1b71ed0c9bbf.png">

今回は、

- twitterボタン..twitter
- facebookボタン..facebook
- サムネイル貼る板..thumbnail

のように名前をつけました。

# 名刺を画像マーカーとして登録

Assets.scassetsのARResources(なければ+ボタンから作ります)に、名刺画像をドラッグアンドドロップしましょう。

以下の画像を見るとわかるように、⚠️（注意）マークが付いています。Graffityの名刺は模様が不十分ではないため、ARマーカーとしては適切では無いようです。一応これでも行けるので、今回はこのまま進みます。

<img width="1008" alt="ar_business_card3 2.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/aa81af69-c328-9a8d-aa76-12077c876033.png">

先日書いた[ARKit画像マーカーに適した画像適さない画像](https://qiita.com/k-boy/items/988af3a1663e84f2f328)という記事で、どのような画像が適しているか、書いたのでチェックしてみてください。

# 画像マーカーを読み取ったら、ボタンやサムネイルのSCNNodeを表示

まずは、Configuration。

ARWorldTrackingConfigurationもしくは、ARImageTrackingConfigurationを使います。平面認識などもしたい場合は前者、画像認識しかしない場合は後者を使いましょう。

この違いについては堤さんの記事、[ARKit 2.0の画像トラッキングとARKit 1.5の画像検出の違い](https://qiita.com/shu223/items/f01b4dc00ceb915b0e61)をチェック！

今回は、ARImageTrackingConfigurationを例に解説します。

以下のコードをviewWillAppear等で実行します。先ほどセットしたマーカー画像をARReferenceImageを呼び出してセットしています。

```swift:BusinessCardViewController.swift
let configuration = ARImageTrackingConfiguration()
        
let images = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil)
configuration.trackingImages = images! // ARReferenceImageがあれば落ちないはず
configuration.maximumNumberOfTrackedImages = 1
sceneView.session.run(configuration)
```

sceneViewには`sceneView.delegate = self`というかんじで、ARSCNViewDelegateに準拠させ、**imageAnchorが読み取られたら発火するように実装します。**

```swift:BusinessCardViewController.swift
extension BusinessCardViewController: ARSCNViewDelegate {
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        guard let imageAnchor = anchor as? ARImageAnchor else {
            return nil
        }
        // Do something
    }
}
```

# 画像マーカーを読み取ったら、ボタンやサムネイルのSCNNodeを表示

引き続き`renderer(:anchor)`メソッドの中で、名前を判別して、それに応じてbuttonNodeを表示するというコードを書いていきます。

以下は、aと登録した名刺画像だったら、buttonNodeを表示しています。

```swift:BusinessCardViewController.swift
extension BusinessCardViewController: ARSCNViewDelegate {
    
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        guard let imageAnchor = anchor as? ARImageAnchor else {
            return nil
        }
        
        switch imageAnchor.referenceImage.name {
        case "a" :
            DispatchQueue.main.async {
                self.feedback.impactOccurred()
            }
            buttonNode.scale = SCNVector3(0.1, 0.1, 0.1)
            let scale1 = SCNAction.scale(to: 1.5, duration: 0.2)
            let scale2 = SCNAction.scale(to: 1, duration: 0.1)
            scale2.timingMode = .easeOut
            let group = SCNAction.sequence([scale1, scale2])
            buttonNode.runAction(group)
            
            return buttonNode
        case "b" :
            return nil
        default:
            return nil
        }
    }
}
```

# SCNNodeはできればアニメーションさせる

buttonNodeを表示する部分のコードについて深掘りします。以下のコードにより、

- 一旦0.1倍に小さくする
- 1.5倍まででかくして
- 1倍まで戻す

というアニメーションを行なっています。

```swift:BusinessCardViewController.swift
buttonNode.scale = SCNVector3(0.1, 0.1, 0.1)
let scale1 = SCNAction.scale(to: 1.5, duration: 0.2)
let scale2 = SCNAction.scale(to: 1, duration: 0.1)
scale2.timingMode = .easeOut

let group = SCNAction.sequence([scale1, scale2])
buttonNode.runAction(group)
```

アニメーションの完成イメージは以下

![business_card1.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/a8c2b641-a515-238e-9a8d-7f91bb4e32fe.gif)

アニメーションについては[SceneKitのアニメーションサンプル集](https://qiita.com/k-boy/items/73a8ce28541966c7b20a)もチェックしてみてください！

# タップしたらアクションする

最後に、TwitterボタンやFacebookボタンをタップしたらWebViewに表示する部分を実装します。

画面をタッチしたら呼ばれるtouchesBeganを使って以下のように実装してみました。

- `let location = touches.first?.location(in: sceneView)` でタップしたロケーションを取得
- hitTestで、そこにNodeがあるかどうかを判別
- Nodeがあったら名前を確認し、facebookだったらwebViewでfacebookページを表示

といった順序になっています。

```swift:BusinessCardViewController.swift
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let location = touches.first?.location(in: sceneView),
        let result = sceneView.hitTest(location, options: nil).first else {
            return
    }
    let node = result.node
    
    if node.name == "facebook" {
        let safariVC = SFSafariViewController(url: URL(string: "https://www.facebook.com/kei.fujikawa1")!)
        self.present(safariVC, animated: true, completion: nil)
    } else if node.name == "twitter" {
        let safariVC = SFSafariViewController(url: URL(string: "https://twitter.com/kboy_silvergym")!)
        self.present(safariVC, animated: true, completion: nil)
    }
}
```

完成イメージは以下。

![business_card2.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/e210fe57-933c-886b-4a26-8834685da7d5.gif)

# まとめ

AR名刺を作る順序は以下。

- ボタンの3DモデルをXcodeのScene Editorにて作成
- 名刺を画像マーカーとして登録
- 画像マーカーを読み取ったら、ボタンやサムネイルのSCNNodeを表示
- SCNNodeはできればアニメーションさせる
- タップしたらアクションする

大変なのは、3Dモデルを用意する部分で、それ以外は簡単だと思います。未来の名刺が楽しみですね！

# サンプルコード

https://github.com/kboy-silvergym/ARKit-Emperor のBusinessCardにあります。