【ARKit入門】平面にアイテムを配置する

#平面にオブジェクトを配置する

こんな感じのです
![IMG_4898.TRIM.MOV.gif](https://qiita-image-store.s3.amazonaws.com/0/138735/b1da8945-f566-e54a-2e36-738874482a3c.gif)



この記事ではARKitを用いて、検出された平面にアイテムを配置する実装を紹介します。

ARKitでの初期設定や、アイテムとして追加する3Dモデルのプロジェクトへの取り込みなどは以下をご参照ください〜。;)
・[【ARKit入門】　まずやること](https://qiita.com/yyokii/items/9f4ad47087fdc6136de7)
・[【ARKit入門】Xcodeに3Dファイルを入れてみる](https://qiita.com/yyokii/items/667998a28d46b93fb1e3)


ではでは本題です！！

## タップの検出

ARSCNViewがタップされた時にその情報を受け取る必要があるので、まずその検出をします。```tapped```メソッドについては後述します。

```MainViewController.swift

///　メインのビューのタップを検知するように設定する
    func registerGestureRecognizers() {

        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped))
        self.mainSceneView.addGestureRecognizer(tapGestureRecognizer)
    }

```
## アイテムボタン
ボタンがタップされたら、対応するアイテムを選択状況とします。
```selectedItem```の値は.scnファイルのファイル名とします。

```MainViewController.swift

@IBAction func cupButtonTapped(_ sender: Any) {
        selectedItem = "cup"
    }

    @IBAction func wineButtonTapped(_ sender: Any) {
        selectedItem = "wine_glass"
    }

```
## 画面タップ時の処理

画面がタップされたら```sender```よりタップ位置を取得し、ARアンカーを検索します。そこでARアンカーの情報が所得されていればアイテム追加処理をします。


```MainViewController.swift

@objc func tapped(sender: UITapGestureRecognizer) {
        // タップされた位置を取得する
        let sceneView = sender.view as! ARSCNView
        let tapLocation = sender.location(in: sceneView)

　　　　 // タップされた位置のARアンカーを探す
        let hitTest = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)
        if !hitTest.isEmpty {
            // タップした箇所が取得できていればitemを追加
            self.addItem(hitTestResult: hitTest.first!)
        }
    }

```

## アイテム追加処理

選択したアイテムに対応する.scnファイルを使用してノードを作成し、現実世界の座標を検出しそこにアイテムを配置します。

```MainViewController.swift

    /// アイテム配置メソッド
    func addItem(hitTestResult: ARHitTestResult) {
        if let selectedItem = self.selectedItem {

            // アセットのより、シーンを作成
            let scene = SCNScene(named: "Models.scnassets/\(selectedItem).scn")

            // ノード作成
            let node = (scene?.rootNode.childNode(withName: selectedItem, recursively: false))!
            
            // 現実世界の座標を取得
            let transform = hitTestResult.worldTransform
            let thirdColumn = transform.columns.3

            // アイテムの配置
            node.position = SCNVector3(thirdColumn.x, thirdColumn.y, thirdColumn.z)
            self.mainSceneView.scene.rootNode.addChildNode(node)
        }
    }

```

以上で、実装完了です！！
最後に全体のサンプルコードを載せていますのでご参考ください。

また、今後もARKit入門記事を投稿予定です！ARKitを用いたサンプルアプリ、ARKitで使用されているメソッド、プロパティの詳細についてまとめていこうと思っています。お楽しみにっ！

## サンプルコード全体

```MainViewController.swift

import UIKit
import ARKit

class ViewController: UIViewController{

    @IBOutlet weak var mainSceneView: ARSCNView!
    
    let configuration = ARWorldTrackingConfiguration()
    var selectedItem: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        initialize()
        registerGestureRecognizers()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    /// ARSCNiew初期化設定    
    func initialize (){
        
        self.mainSceneView.debugOptions = [ARSCNDebugOptions.showWorldOrigin, ARSCNDebugOptions.showFeaturePoints]
        self.configuration.planeDetection = .horizontal
        self.mainSceneView.session.run(configuration)
        self.mainSceneView.autoenablesDefaultLighting = true
    }
    
    ///　メインのビューのタップを検知するように設定する
    func registerGestureRecognizers() {
        
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped))
        self.mainSceneView.addGestureRecognizer(tapGestureRecognizer)
    }
    
    @objc func tapped(sender: UITapGestureRecognizer) {
        // タップされた位置を取得する
        let sceneView = sender.view as! ARSCNView
        let tapLocation = sender.location(in: sceneView)

        // タップされた位置のARアンカーを探す
        let hitTest = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)
        if !hitTest.isEmpty {
            // タップした箇所が取得できていればitemを追加
            self.addItem(hitTestResult: hitTest.first!)
        }
    }
    
    /// アイテム配置メソッド
    func addItem(hitTestResult: ARHitTestResult) {
        if let selectedItem = self.selectedItem {

            // アセットのより、シーンを作成
            let scene = SCNScene(named: "Models.scnassets/\(selectedItem).scn")

            // ノード作成
            let node = (scene?.rootNode.childNode(withName: selectedItem, recursively: false))!
            
            // 現実世界の座標を取得
            let transform = hitTestResult.worldTransform
            let thirdColumn = transform.columns.3

            // アイテムの配置
            node.position = SCNVector3(thirdColumn.x, thirdColumn.y, thirdColumn.z)
            self.mainSceneView.scene.rootNode.addChildNode(node)
        }
    }
    
    
    @IBAction func cupButtonTapped(_ sender: Any) {
        selectedItem = "cup"
    }
    
    @IBAction func wineButtonTapped(_ sender: Any) {
        selectedItem = "wine_glass"
    }
}

```