Xcode
iOS
AR
Swift
ARKit

【ARKit】今日からはじめる AR プログラミング Part.2

この記事について

前回の記事( 今日からはじめる AR プログラミング Part.1)では、
ARKit を使ったシンプルなアプリケーションを開発して、どのように空間トラッキングをしているかを体験した。
今回は、もう少しだけ ARKit の機能を使ってみる。

どんな人のための記事?

  • Xcode の基本的な使い方を理解している。
  • Swift プログラミングの基本を理解している。
  • AR (Augmented Reality) に興味がある。

要件

  • Xcode9 以降が動作する Mac
  • A9 プロセッサを搭載している iOS デバイス(iOS11~)

開発するアプリケーションの概要

  • AR 空間に、3D コンテンツの画像を配置する。
  • タッチジェスチャー
  • SceneKit

ARKit と SceneKit

AR は「拡張された現実」のこと。
今回の記事では、現実空間を仮想の 3D コンテンツで拡張してみる。
iOS プログラミングで、3D コンテンツを扱う時に便利なフレームワークが SceneKit
SceneKit の仮想空間では「x,y,z」の3軸、つまり「水平、垂直、奥行き」の座標系で位置情報を扱う。

手順

1. Xcode プロジェクトを作成

プロジェクトの設定

Info.plist

2. ユーザーインターフェース

iPhoneX 向けのデザイン

オートレイアウト

タップを検知する

UITapGestureRecognizer を配置する

IBOutlet 接続

arScnView

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var arScnView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()        
    }

}

IBAction 接続

handleTap メソッド

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var arScnView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()        
    }

    @IBAction func handleTap(_ sender: UITapGestureRecognizer) {
    }

}

3. ソースコード

フレームワークをインポートする

今回は ARKit に加えて、3D オブジェクトを生成・配置するために SceneKit フレームワークを使用する。

ViewController.swift
import ARKit
import SceneKit

class ViewController: UIViewController {

    @IBOutlet weak var arScnView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    @IBAction func handleTap(_ sender: UITapGestureRecognizer) {
    }

}

セッションとコンフィギュレーション

前回とほぼ同じ内容。ただし、今回はデバッグ情報は表示しない。

ViewController.swift
import ARKit
import SceneKit

class ViewController: UIViewController {

    @IBOutlet weak var arScnView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let scene = SCNScene()
        arScnView.scene = scene
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let configuration = ARWorldTrackingConfiguration()
        arScnView.session.run(configuration)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        arScnView.session.pause()
    }

    @IBAction func handleTap(_ sender: UITapGestureRecognizer) {
    }

}

完成したソースコード

ViewController.swift
import ARKit
import SceneKit

class ViewController: UIViewController {

    @IBOutlet weak var arScnView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let scene = SCNScene()
        arScnView.scene = scene
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let configuration = ARWorldTrackingConfiguration()
        arScnView.session.run(configuration)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        arScnView.session.pause()
    }

    @IBAction func handleTap(_ sender: UITapGestureRecognizer) {
        guard let currentFrame = arScnView.session.currentFrame else { return  }

        let viewWidth  = arScnView.bounds.width
        let viewHeight = arScnView.bounds.height
        let imagePlane = SCNPlane(width: viewWidth/6000, height: viewHeight/6000)
        imagePlane.firstMaterial?.diffuse.contents = arScnView.snapshot()
        imagePlane.firstMaterial?.lightingModel = .constant

        let planeNode = SCNNode(geometry: imagePlane)
        arScnView.scene.rootNode.addChildNode(planeNode)

        var translation = matrix_identity_float4x4
        translation.columns.3.z = -0.1
        planeNode.simdTransform = matrix_multiply(currentFrame.camera.transform, translation)
    }

}

4. ビルド

アプリが起動したら、画面をタップしてみる。
タップした瞬間にデバイス画面に映っていた画像が AR 空間に配置されれば、アプリケーションは正しく動作している。