はじめに

本書のコンセプトと構成

ARKitは、ちょっと試すだけなら超簡単です。APIはシンプルだし、Xcodeのテンプレートからサクッと動くものがつくれます。

しかしまた、ものすごく奥深くもあります。レンダリングはSceneKitやMetalと組み合わせられるので、これだけで3Dプログラミングのほぼあらゆるテクニックが使えるということになりますし、カメラからの生の入力データCVPixelBufferにもアクセスできるので、Core Image, Core ML, Vision, Metal, etc…と組み合わせて、画像/動画処理のあらゆるテクニックを駆使できるということにもなります。ARKitが検出している特徴点データや、デプスデータにもアクセスできます。

そんな手軽さも奥深さも兼ね備えるARKit、新機能が追加されるたびにインターネット上では多くのデモやプロトタイプが公開され、iOSアプリ開発者の枠を超えて広く話題になっています。App StoreではARKitのリリースから約半年で対応アプリケーションが約1300万回ダウンロードされたそうです。

本書では、ARKitの「超簡単な導入」から始めて、最終的にはネットやストアで話題になっていたようなアイデアを実装できるようになるところまでをカバーするように構成しました。

  • 入門編その1 - 最小実装で体験してみる
  • 入門編その2 - 水平面を検出する
  • 入門編その3 - 検出した水平面に仮想オブジェクトを置く
  • ARKit開発に必須の機能
  • 平面検出の基礎
  • 画像検出と画像トラッキング
  • 3D物体検出と3D物体スキャン
  • AR空間におけるインタラクションを実現する
  • AR体験の永続化と共有
  • フェイストラッキング
  • 特徴点を利用する
  • デプスを利用する
  • オクルージョン
  • モーションキャプチャ
  • ビデオフォーマット
  • アプリケーション実装例1: 現実空間の長さを測る
  • アプリケーション実装例2: 空中に絵や文字を描く
  • アプリケーション実装例3: Core ML + Vision + ARKit
  • Metal + ARKit

「入門編」では、はじめの一歩として、最小実装でARKitを体験します。実にシンプルな実装で強力なAR機能が利用できることを実感していただけることでしょう。

その後は平面を検出する方法、その平面に仮想オブジェクトを設置する方法、そしてその仮想オブジェクトとインタラクションできるようにする方法…と、読み進めるにつれて「作りながら」引き出しが増えていき、最終的にはARKitを用いた巻尺(メジャー)や、空間に絵や文字を描くといった、ARKitならではのアプリケーションの実装ができるよう構成しています。

ARKitのAPIはシンプルとはいえ、リファレンスだけから実装方法を汲み取るのは難しい部分もあります。またAppleのサンプルは動かして試してみたり、ちょっと改変してみたりして用いる分にはいいですが、実装内容は結構複雑で初心者には意図がわかりにくいものになっている面があります。

  • ARKitには興味があるけどなかなか手を動かせていない
  • 公式サンプルを動かしただけで止まっている
  • どこから始めていいかわからない

といった方は、ぜひ本書を手にとってみてください。本書がARKit開発のスタートを切るきっかけになれば幸いです。

動作環境

iOS 13 (ARKit 3) / Swift 5.1 / Xcode 11

サンプルコード

ARKitは現実の空間を利用するフレームワークなので、自分の手元(実機)で実際に動かし体感しながら学んでいくのがベストです。本書のサンプルプロジェクトはhttps://github.com/shu223/ARKitBookにありますので、ぜひXcodeを開いてサンプルを動かし、デバイスを持って歩き回ったりするなど、楽しみながら学んでください。

目次

はじめに

本書のコンセプトと構成
動作環境
サンプルコード

第1章 入門編その1 - 最小実装で体験してみる

1.1 手順1: プロジェクトの準備
1.2 手順2: ViewControllerの実装
1.3 基本クラスの解説
  • ARSession
  • ARConfiguration, ARWorldTrackingConfiguration
  • ARSCNView

第2章 入門編その2 - 水平面を検出する

2.1 水平面を検出するためのコンフィギュレーション
2.2 平面検出に関するイベントをフックする - ARSessionDelegate
  • ARAnchor
  • ARPlaneAnchor
2.3 平面検出に関するイベントをフックする - ARSCNViewDelegate
2.4 検出した平面を可視化する

第3章 入門編その3 - 検出した水平面に仮想オブジェクトを置く

3.1 3Dモデルを読み込む
3.2 仮想オブジェクトとして検出した平面に置く

第4章 ARKit開発に必須の機能

4.1 トラッキング状態を監視する
  • ARSessionObserver
  • ARCamera.TrackingState
4.2 デバッグオプションを利用する
4.3 トラッキング状態をリセットする / 検出済みアンカーを削除する
  • resetTracking
  • removeExistingAnchor

第5章 平面検出の基礎

5.1 垂直平面の検出
5.2 検出した平面のアラインメントを判別する
5.3 平面ジオメトリの取得
  • ARPlaneGeometry
  • ARSCNPlaneGeometry
  • 検出した平面の形状を可視化する
  • ARPlaneGeometryとARSCNPlaneGeometry

第6章 画像検出と画像トラッキング

6.1 画像検出
  • detectionImages
  • ARReferenceImage
  • ARImageAnchor
  • 実装
  • 画像検出のパフォーマンス
6.2 画像トラッキング
  • ARImageTrackingConfiguration
  • 実装
6.3 画像検出と画像トラッキングの違い
  • ワールドトラッキングコンフィギュレーションで画像トラッキング

第7章 3D物体検出と3D物体スキャン

7.1 3D物体検出
  • ARReferenceObject
  • detectionObjects
  • ARObjectAnchor
  • 実装
7.2 3D物体スキャン
  • 3D物体スキャンの公式サンプルと独自実装について

第8章 AR空間におけるインタラクションを実現する

8.1 ヒットテスト(当たり判定)を行う
  • ARSCNViewによるヒットテスト
  • SCNSceneRendererによるヒットテスト
  • 特徴点に対するヒットテスト
8.2 デバイスの移動に対するインタラクション
  • 最新フレームにおけるカメラの情報を取得する
  • カメラのワールド変換行列から、カメラの位置・向きを取得する
  • 仮想オブジェクトが常にカメラの方を向くようにする

第9章 AR体験の永続化と共有

9.1 ARWorldMap
  • ARWorldMapに保存されないアンカー
9.2 ワールドマップを取得する
  • ワールドマップ取得処理を実行するキュー
9.3 ワールドマップを永続化・共有する
9.4 ワールドマップからセッションを復元する
9.5 ワールドマップ取得タイミング

第10章 フェイストラッキング

10.1 フェイストラッキングを開始する - ARFaceTrackingConfiguration
10.2 検出した顔のアンカーを取得する - ARFaceAnchor
10.3 顔の動きを可視化する
  • ARFaceGeometry
  • ARSCNFaceGeometry
  • 実装
ブレンドシェイプでアニ文字風3Dアバター

第11章 特徴点を利用する

11.1 特徴点を可視化する
11.2 フレームに含まれる特徴点群データ
11.3 ワールドマップに含まれる特徴点群データ

第12章 デプスを利用する

12.1 ARFrameからデプスデータを取得する
12.2 制約
  • フェイストラッキング時のみ利用可能
  • 毎フレーム更新されるわけではない

第13章 オクルージョン

13.1 People Occlusionの実装方法
13.2 personSegmentationとpersonSegmentationWithDepthの違い
13.3 利用可能なコンフィギュレーション
13.4 segmentationBufferとestimatedDepthData

第14章 モーションキャプチャ

14.1 2D Body Detection
  • 2D Body Detectionの実装方法
  • detectedBody, ARBody2D
  • ARSkeleton2D
  • ARSkeleton.JointName
  • ARSkeletonDefinition
  • 利用可能なコンフィギュレーション
14.2 3D Body Tracking
  • ARBodyTrackingConfiguration
  • ARBodyAnchor
  • ARSkeleton3D

第15章 ビデオフォーマット

15.1 ARConfiguration.VideoFormat
15.2 ビデオフォーマットを指定する
15.3 使用可能なビデオフォーマット
  • 現行デバイスで使用可能なビデオフォーマット一覧
  • ビデオフォーマットはどう使い分けるのか?

第16章 アプリケーション実装例1: 現実空間の長さを測る

16.1 ARKitにおける座標と現実のスケール
16.2 現実空間における二点間の距離

第17章 アプリケーション実装例2: 空中に絵や文字を描く

17.1 実装方針
17.2 スクリーンの中心座標をワールド座標に変換する
17.3 頂点座標の配列から、線としてのカスタムジオメトリを構成する
17.4 その他の実装のポイント
  • デバイス位置の取得タイミング
  • 精度を安定させる

第18章 アプリケーション実装例3: Core ML + Vision + ARKit

18.1 実装方針
18.2 Core ML・Vision・ARKit連携のポイント
  • 毎フレームのカメラからの入力画像データへのアクセス
  • Core MLの認識を実行する
  • Core MLの認識結果をテキストノードとして設置する

第19章 Metal + ARKit

19.1 マテリアルをMetalで描画する
  • SCNProgram
19.2 他のSceneKitとMetalの連携機能
  • shaderModifiers
  • SCNTechnique
19.3 Metalによるカスタムレンダリング
  • 方法1: Metalだけでレンダリングする
  • 方法2: SCNRendererを用いてレンダリングする
  • 方法3: SceneKitレンダリング + Metalレンダリング
19.4 Metalカスタムレンダリング時のオクルージョン
  • ARMatteGenerator
  • オクルージョン処理のMetalシェーダ

参考文献

第1章 入門編その1 - 最小実装で体験してみる

非常に高機能・高性能なARKitですが、シンプルなAPIで簡単に扱えるようになっています。各クラスの役割や詳細な使い方は後述するとして、まずは(約)3行でできるARKitの最小実装を示しますので、「こんなに簡単にできるのか」と実感してもらいつつ、そこからARKitのAPIデザインの大枠を掴んでください。

実はXcodeの「Augmented Reality App」テンプレートからプロジェクトを生成すれば、一行もコードを書かずにそのままビルドしてAR機能が動作するアプリが新規作成できてしまいます。ですが、「非常に簡単に実装できる」という点を体感してもらうためにも、本章では既存プロジェクトに数行のコードを追加してAR機能を構築する、というところから始めます。

サンプルコード: FirstAR

1.1 手順1: プロジェクトの準備

プロジェクトの設定やアセットの追加を行います。

まず、ARKitではカメラを利用するので、Info.plistにNSCameraUsageDescriptionキー*1を追加しておきます。

次に、ARKitを用いて「現実世界にオーバーレイするシーン」のデータをプロジェクトに追加します。ここではship.scn(図1.1)というシーンファイル*2と、そこから参照しているtexture.pngを追加*3することにします。

ship.scn

図1.1: ship.scn

1.2 手順2: ViewControllerの実装

ARKitをインポートします。

import ARKit

Interface Builder(以降IB)からARSCNViewオブジェクトを追加*4し、ARSCNViewを保持するプロパティと接続しておきます。

@IBOutlet var sceneView: ARSCNView!

viewDidLoad()に次の3行を追加します。

// シーンを生成してARSCNViewにセット
sceneView.scene = SCNScene(named: "art.scnassets/ship.scn")!

// セッションのコンフィギュレーションを生成
let configuration = ARWorldTrackingConfiguration()

// セッション開始
sceneView.session.run(configuration)

これでもうビルドして実機で動かせるようになりました。アプリを起動してすぐにカメラ入力がスタートするので、周りをグルッと見てください。カメラから見える現実の世界に仮想の飛行機が設置されているはずです。デバイスを持って移動してみても、飛行機は最初の位置にしっかり固定され、色々な角度から見ることができます。

仮想オブジェクトが現実世界に設置され、色々な角度から見ることができる

図1.2: 仮想オブジェクトが現実世界に設置され、色々な角度から見ることができる

つまり、わずか3行程度の実装によって、現実世界に仮想シーンをオーバーレイし、デバイスの位置や角度の変化に追従するARの機能が構築できたことになります。

1.3 基本クラスの解説

最小実装での挙動を確認できたところで、上で書いたコードが何をしていたのかを把握するため、出てきたクラスについて簡単に見ていきましょう。

ARSession

ARKitでは、そのAR機能全体をARSessionクラスを用いてセッション単位で管理します。

ARSessionrun(_:)メソッドを呼ぶと、セッションが動作開始します。セッションが開始すると、ARKit内部でカメラからの入力の画像解析や、デバイスのモーション情報の取得・解析が開始され、現実空間の認識とデバイスのトラッキング(現実空間におけるデバイス=自分の位置や向きを追跡)が始まります。

session.run(configuration)

ARKitのない時代にARを実現しようとした場合、AVFoundationでカメラ入力画像データの取得、Core Motionでモーション情報の取得、かつそれらを「リアルタイムに」解析・統合するという、非常に複雑で難易度の高い実装が必要でした。それが、run(_:)メソッドを呼ぶだけで実現できるようになったのです。

runメソッドの定義は次のようになっており、第1引数には次項で解説するARConfigurationを指定します。

func run(_ configuration: ARConfiguration,
         options: ARSession.RunOptions = [])

第2引数のoptionsはデフォルト値(オプションなし)が与えられているため省略可能です。本章でもできるだけコードをシンプルにするために省略しています。*5

ARKitのセッションを中断したい場合は、pause()メソッドを呼びます。

session.pause()

なお、セッションにはもう1つ「リセット」という概念が存在します。これについては、後の「ARKit開発に必須の機能」で解説します。

ARConfiguration, ARWorldTrackingConfiguration

ARConfigurationクラスは、ARKitのセッションの様々なコンフィギュレーションを管理するためのクラスです。ARSessionをrunするときの引数に渡します。

このクラスを用いて、たとえば「オーディオデータも取得するか(providesAudioDataプロパティ)」「カメラ入力からシーンのライティングを推定するか(isLightEstimationEnabledプロパティ)」といったことが設定できます。

上の実装で出てきたARWorldTrackingConfigurationARConfigurationのサブクラスで、デバイスの向きや位置をトラッキングし、かつデバイスのカメラから見える現実世界の「面」*6を検出する、というコンフィギュレーションを表します*7

ARSCNView

ARKitはコアな処理のみを行い、実際の描画はSceneKitやSpriteKit、Metalが担当します。

図1.3:

特に、3D空間の描画は基本的にSceneKitが担当します。SceneKitには、描画する3次元のシーン(SCNScene)を、UIKitベースのUI階層内で共存して描画するためのSCNViewというUIViewを継承したクラスがあり、

class SCNView : UIView, SCNSceneRenderer, SCNTechniqueSupport

これを継承してARKit関連の機能を持たせたものが、ARSCNViewクラスです。

class ARSCNView : SCNView

ARSCNViewは、上述したARSessionオブジェクトをプロパティで保持しており、また「AR空間におけるインタラクションを実現する」で後述するヒットテストの機能も持っています。すなわちARSCNViewは、「ARKit関連の機能を取り扱いつつ、UIKitベースのUI階層内で3次元シーンを描画するためのクラス」といえます。

前述のコードにはARSessionオブジェクトを生成する処理はありませんでした。ARSCNViewオブジェクトを生成した時点で、そのsessionプロパティにはすでにARSessionオブジェクトが生成されて入っているためです。そのおかげで、ARSCNViewオブジェクトを用意すればあとはセッションをrunするだけ(sceneView.session.run(configuration))という手軽さでARが実現できるようになっています。


[*1] XcodeのInfo.plistエディタでは「Privacy - Camera Usage Description」と表示されます。

[*2] .scnはSceneKit用のシーンのデータを扱うファイルの拡張子です。なお、ここで用いているship.scnはXcodeの「Augmented Reality App」テンプレートに含まれています。

[*3] サンプルではこれらのファイルを、.scnassetsという拡張子のついたSceneKitのアセット管理用フォルダに入れています。

[*4] ViewController直下のUIViewオブジェクトのクラスをARSCNViewに変更するだけでもOKです。

[*5] 第2引数のoptionsに指定できるARSession.RunOptionsは、「ARKit開発に必須の機能」で解説しています。

[*6] 公式リファレンスでは「Surface」と表現されています。平面(Plane)だけではなく曲面も含めるという意味での「Surface」なので、本書では「面」と訳しました。

[*7] ARWorldTrackingConfigurationを使用して水平面を検出する方法については、後の「水平面を検出するためのコンフィギュレーション」で解説します。

試し読みはここまでです。
この続きは、製品版でお楽しみください。