【Swift】初心者でも簡単にできるARKitを使ってみよう(2)

by

スクリーンショット 2018-02-28 13.08.59

こんにちは、松田翔大です。

前回(初心者でも簡単にできるARKitを使ってみよう)最後に書いた通り、カメラで平面を検知して、そこに3Dモデルを表示させるところまでやってみたので書いてみました。

 

#事前準備

まずは前回同様、Xcodeでプロジェクトを作成します。

Xcodeの環境も前回と同様です。

まず、新規のファイルを作成します。今回は、PlaneNode.swiftファイルを作成します。

作成する方法は、作成したプロジェクトのプロジェクト名のフォルダを右クリック -> New File… -> Cocoa Touch Classを選択してNextを押す。

スクリーンショット 2018-02-28 13.08.59

Class:に[PlaneNode]と入力し、Subclass of:はNSObjectを選択し、Nextを押します。

スクリーンショット 2018-02-28 13.07.16

この画面はそのままCreateを押せば問題ないです。

スクリーンショット 2018-02-28 13.09.31

これでPlaneNode.swiftが作成されます。
スクリーンショット 2018-02-28 13.12.00

 

#実装

まずは、先程作成したPlaneNode.swiftを実装していきます。

以下のように実装してください。

PlaneNode.swift

import UIKit
import SceneKit
import ARKit

class PlaneNode: SCNNode {
    
    fileprivate override init() {
        super.init()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    init(anchor: ARPlaneAnchor) {
        super.init()
        // ARAnchorの情報に基づいて、半透明の平面を表現するノードオブジェクトの作成
        geometry = SCNPlane(width: CGFloat(anchor.extent.x), height: CGFloat(anchor.extent.z))
        let planeMaterial = SCNMaterial()
        planeMaterial.diffuse.contents = UIColor.white.withAlphaComponent(0.5)
        geometry?.materials = [planeMaterial]
        SCNVector3Make(anchor.center.x, 0, anchor.center.z)
        transform = SCNMatrix4MakeRotation(-Float.pi / 2, 1, 0, 0)
    }
    
    func update(anchor: ARPlaneAnchor) {
        (geometry as! SCNPlane).width = CGFloat(anchor.extent.x)
        (geometry as! SCNPlane).height = CGFloat(anchor.extent.z)
        position = SCNVector3Make(anchor.center.x, 0, anchor.center.z)
    }
}

 

次にViewController.swiftを実装します。

以下のように実装してください。

ViewController.swift

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        sceneView.delegate = self
        sceneView.scene = SCNScene()
    }
    
    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()
    }
    
    // MARK: - ARSCNViewDelegate
    // ARPlaneAnchorが検出されて、自動的にシーンに追加される時に呼ばれる
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        DispatchQueue.main.async {
            if let planeAnchor = anchor as? ARPlaneAnchor {
                // 平面を表現するノードを追加する
                node.addChildNode(PlaneNode(anchor: planeAnchor) )
            }
        }
    }
    
    // 情報が更新されるたびにARPlaneAnchorも更新されて呼ばれる
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        DispatchQueue.main.async {
            if let planeAnchor = anchor as? ARPlaneAnchor, let planeNode = node.childNodes[0] as? PlaneNode {
                // ノードの位置及び形状を修正する
                planeNode.update(anchor: planeAnchor)
            }
        }
    }
}

これで実装は終わりです。
ビルドして確認して以下の画像のようになっていれば問題ありません。
Image uploaded from iOS

今回は、ARKitで平面を検出するところまでで終わりたいと思います。
次回は、今回書ききれなかった検出した平面に3Dオブジェクトを設置するところまで書きたいと思います。

松田翔大
2017年9月入社。iOSの開発を担当してます。開発言語はswiftとunity。
趣味はフットサルと読書。彼女募集中です。

Egg Device Application

東京品川のスマホアプリ製作・開発会社です。
一般アプリ業務用アプリからVRアプリまで開発可能。

ライター一覧

求人情報

スマホアプリ製作・開発の
相談を受け付けています

メールでのご相談

お電話でのご相談
TEL 03-5422-7524
平日10:00~18:00