【ARKit】タップした水平面に球体を出現させる

みなさん、こんにちは。
ホットコーヒーおいしい季節ですね、渋谷です。
最近AR関係の記事が続いていますが、今回もARです!
平面をタップすると前回書いたような球体を出現させる物を作っていきます。プロジェクトの作成準備などは、前回の記事を参考にしてください。
■完成イメージ
環境
Swift version 4.2.1
Xcode 10.1
実装
ViewController.swiftに処理を書き加えていきます。
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Set the scene to the view
sceneView.scene = SCNScene()
// デバッグ用のポイント表示
sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
// ライトの追加
sceneView.autoenablesDefaultLighting = true
// タップした時のaction追加
let tapScreen = UITapGestureRecognizer(target: self, action: #selector(tapped))
self.sceneView.addGestureRecognizer(tapScreen)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// 平面検出
configuration.planeDetection = .horizontal
// Run the view's session
sceneView.session.run(configuration)
}
// タップされた位置を取得する
@objc func tapped(sender: UITapGestureRecognizer) {
// タップされた位置のARアンカーを探す
let tapLocation = sender.location(in: sceneView)
let hitTest = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)
// タップした箇所が取得できていればアンカーを追加
if !hitTest.isEmpty {
let anchor = ARAnchor(transform: hitTest.first!.worldTransform)
sceneView.session.add(anchor: anchor)
}
}
以上!
実機にビルドして検知された平面をタップしてみましょう。白い球体が出現するはずです。
解説
平面のタップされた場所に球体を出現させるには以下の3つの手順を踏む必要があります。
- 平面でタップした座標の検出
- タップした座標にARAnchorを追加
- Anchorに合わせて3Dモデルの表示
■平面でタップした座標の検出
viewDidLoadメソッドの最後に
let tapScreen = UITapGestureRecognizer(target: self, action: #selector(tapped))
self.sceneView.addGestureRecognizer(tapScreen)
が書かれていますが、ここのUITapGestureRecognizer
にタップされた時の挙動を書いていきます。
target
にタップ時に呼び出す3Dオブジェクト(今回はself
)を、action
に作成したtapped
メソッドを指定しています。
■タップした座標にARAnchorを追加
ARAnchorの追加は、tappedメソッド
で行っています。
tapLocation
に、タップした画面の座標を格納し、hitTest
メソッドでtapLocation
が平面かどうかを調べます。第二引数のtypes
に.existingPlaneUsingExtent
を指定することで、タップ位置が平面内かどうかを調べることができます。水平面内であれば、ARAnchorをsceneに追加します。
また、types
には他にも以下のような引数を指定する事ができます。
- featurePoint・・・一番近い特徴点の結果を返す。平面に限らず、自由にオブジェクトを配置したい時に使う。
- estimatedHorizontalPlane・・・水平面だと推定される位置を返す。
- existingPlane・・・検出された平面を返す。
■Anchorに合わせて3Dモデルの表示
Anchorが追加されると、renderer(_:didAdd:for)
が自動的に呼び出れます。renderer(_:didAdd:for)
に関しては、前回の記事と同様なので、ぜひ参考にしてください。
まとめ
今回はhitTest
メソッドのtypes
に指定する値に.existingPlaneUsingExtent
を指定しましたが、.existingPlane
を使ってもあまり違いがわからなかったので、検証を重ねて理解を深める必要があると感じました。
次回はしっかりと3Dオブジェクトを使った開発をしていこうと考えています。