iOS11で登場したARKitを使って、画面上に立方体を配置してみました。
下のように地面に複数のオブジェクトが並ぶようにしています。
まずはプロジェクト作成から「Augmented Reality App」を選んでARKitのテンプレートを作成します。
次はサンプルコードを消してコードを最小限にします。
import UIKit import SceneKit import ARKit class ViewController: UIViewController, ARSCNViewDelegate { @IBOutlet var sceneView: ARSCNView! override func viewDidLoad() { super.viewDidLoad() sceneView.delegate = self sceneView.showsStatistics = true let scene = SCNScene() sceneView.scene = scene } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let configuration = ARWorldTrackingConfiguration() sceneView.session.run(configuration) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) sceneView.session.pause() } }
次はデバック用オプションを指定します。
このオプションは認識した特徴点を表示してくれるものです。
特徴点が一定数を超えるとその場所を平面としてみなしてくれます。
class ViewController: UIViewController, ARSCNViewDelegate { @IBOutlet var sceneView: ARSCNView! override func viewDidLoad() { // 省略 sceneView.debugOptions = ARSCNDebugOptions.showFeaturePoints } // 省略 }
実行すると画面に特徴点が黄色い点として現れます。
次は平面認識をする設定をします。
ARWorldTrackingConfigurationのplaneDetectionに.horizontalをセットします。
今は.horizontalしかないので、平面以外の認識はできません。
class ViewController: UIViewController, ARSCNViewDelegate { // 省略 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let configuration = ARWorldTrackingConfiguration() configuration.planeDetection = .horizontal // 今回追加 sceneView.session.run(configuration) } }
最後にタップ時にボックスを配置する処理を記述します。
下のようにUITapGestureRecognizerのセットと、タップ時に呼ばれるメソッドを実装します。
class ViewController: UIViewController, ARSCNViewDelegate { @IBOutlet var sceneView: ARSCNView! override func viewDidLoad() { // 省略 let gesture = UITapGestureRecognizer(target: self, action: #selector(tapView)) sceneView.addGestureRecognizer(gesture) } @objc func tapView(sender: UITapGestureRecognizer) { let location = sender.location(in: sceneView) let hitTestResult = sceneView.hitTest(location, types: .existingPlane) if let result = hitTestResult.first { let geometry = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0) let material = SCNMaterial() material.diffuse.contents = UIColor.darkGray geometry.materials = [material] let node = SCNNode(geometry: geometry) node.position = SCNVector3(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y + 0.20, result.worldTransform.columns.3.z) sceneView.scene.rootNode.addChildNode(node) } } // 省略 }
場所の取得は下メソッドで行っています。
locationメソッドで画面上のタップ位置を取得して、hitTestでタップ位置と認識済平面との交点の座標を計算しています。
取得後は、普通のSceneKitアプリ同様にボックスを配置すれば完成です。
let location = sender.location(in: sceneView) let hitTestResult = sceneView.hitTest(location, types: .existingPlane)
参考URL
[iOS 11][ARKit] 物理衝突を実装して、キューブを落として見る #WWDC2017 | Developers.IO