18
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-12-19

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

こんな感じのです
IMG_4898.TRIM.MOV.gif

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

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

ではでは本題です!!

タップの検出

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"
    }
}

18
17
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?