Edited at

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

More than 1 year has passed since last update.


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

こんな感じのです

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