見出し画像

ARKit入門 / タップ位置へのモデル配置

iOSの「ARKit」でタップ位置のモデル配置を行うプログラムを作ります。

1. モデルの追加

プロジェクトの「art.scnassets」にモデルを追加します。テクスチャなどを設定した後、メニュー「Editor → Convert to SeaneKit scene file format(.scn)」でscnに変換します。

画像1

2. タップ位置へのモデル配置

検出した平面のタッチ位置にモデル配置を行います。

画像2

import UIKit
import SceneKit
import ARKit

//タップ位置へのモデル配置
class ViewController: UIViewController, ARSCNViewDelegate {
   @IBOutlet var sceneView: ARSCNView!

   //ロード時に呼ばれる
   override func viewDidLoad() {
       super.viewDidLoad()
   
       //シーンの作成
       sceneView.scene = SCNScene()

       //特徴点とワールド原点の表示
       sceneView.debugOptions = [
           ARSCNDebugOptions.showFeaturePoints,
           ARSCNDebugOptions.showWorldOrigin]
   
       //光源の有効化
       sceneView.autoenablesDefaultLighting = true;
   
       //ARSCNViewデリゲートの指定
       sceneView.delegate = self
       
       //ジェスチャーの追加
       let gesture = UITapGestureRecognizer(target: self, action:#selector(onTap))
       self.sceneView.addGestureRecognizer(gesture)
   }
  
   //ビュー表示時に呼ばれる
   override func viewWillAppear(_ animated: Bool) {
       super.viewWillAppear(animated)
   
       //コンフィギュレーションの生成
       let configuration = ARWorldTrackingConfiguration()
   
       //平面検出の有効化
       configuration.planeDetection = .horizontal
   
       //セッションの開始
       sceneView.session.run(configuration)
   }

   //ビュー非表示時に呼ばれる
   override func viewWillDisappear(_ animated: Bool) {
       super.viewWillDisappear(animated)
       //セッションの一時停止
       sceneView.session.pause()
   }
  
   //ARアンカー追加時に呼ばれる
   func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
       DispatchQueue.main.async {
           //ARAnchorのnameがmodelの時
           if anchor.name == "model" {
               //モデルノードの追加
               let scene = SCNScene(named: "art.scnassets/heniheni.scn")
               let modelNode = (scene?.rootNode.childNode(withName: "heniheni", recursively: false))!
               modelNode.scale = SCNVector3(0.001, 0.001, 0.001)
               node.addChildNode(modelNode)
           }
       }
   }
   
   //タップ時に呼ばれる
   @objc func onTap(sender: UITapGestureRecognizer) {
       //タップ位置の取得
       let location = sender.location(in: sceneView)

       //ヒットテスト
       let hitTest = sceneView.hitTest(location, types: .existingPlaneUsingExtent)
       if !hitTest.isEmpty {
           //ARアンカーの追加
           let anchor = ARAnchor(name:"model", transform: hitTest.first!.worldTransform)
           sceneView.session.add(anchor: anchor)
       }
   }
}

◎ジェスチャーの追加
ジェスチャーの追加には、UITapGestureRecognizerを生成し、addGestureRecognizer()で追加します。

       //ジェスチャーの追加
       let gesture = UITapGestureRecognizer(target: self, action:#selector(onTap))
       self.sceneView.addGestureRecognizer(gesture)

◎ヒットテスト
ヒットテストには、ARSCNViewのhitTest()を使います。

func hitTest(_ point: CGPoint, types: ARHitTestResult.ResultType) -> [ARHitTestResult]
SceneKitViewのポイントに対応するカメラ映像で、実世界のオブジェクトまたはARアンカーを検索
    point: ポイント
    types: 種別
        .featurePoint: 特徴点
        .estimatedHorizontalPlane: 水平面
        .existingPlane: 平面
        .existingPlaneUsingExtent: 平面内
    戻り値: ヒットテスト結果

ヒットテストで衝突検出時に、ARアンカーの生成と追加を行います。

◎モデルノードの追加
ARAnchorのnameが"model"の時、モデルノードを追加します。

           //ARAnchorのnameがmodelの時
           else if anchor.name == "model" {
               //モデルノードの追加
               let scene = SCNScene(named: "art.scnassets/heniheni.scn")
               let modelNode = (scene?.rootNode.childNode(withName: "heniheni", recursively: false))!
               modelNode.scale = SCNVector3(0.001, 0.001, 0.001)
               node.addChildNode(modelNode)
           }


この記事が気に入ったらサポートをしてみませんか?