はじめに

今回は、 Unity 向けに ARKit と ARCore の機能をまとめた AR Foundation について調べました。

開発環境

  • Unity 2019.1.1f1 (2019.1以降が推奨されています)

  • AR Foundation 2.1.0

  • ARCore XR Plugin 2.1.0

  • ARKit XR Plugin 2.1.0

環境構築

1. 必要なパッケージをインストール

Setup_01

Unity2019.1では ARFoundation は preview となっているので、まず、 Package Manager -> Advanced で Show preview packages を選択して、一覧に表示する。

一覧の中から AR FoundationARCore XR PluginARKit XR Plugin の3つをインストールする。

2. Android の API レベルを変更

Setup_02

  • Project Settings -> Player -> Identification -> Minimum API Level を 7.0以上に変更する。

3. Hierarchy に必要な GameObject を配置

初めから置かれている Main Camera を削除する。

Setup_03

GameObject -> XR -> AR Session OriginAR Session をヒエラルキーに配置する。

以上で ARFoundation の開発環境が整いました

動かしてみる

ここからはサンプルプロジェクトのシーンを動かしながら、各機能を確認していきます。

平面検出

平面を検出する

PlaneDetection_01

GameObject -> XR -> AR Default Plane を一旦ヒエラルキーに配置して、 Prefab 化する。

Prefab 化したら、ヒエラルキーから削除する。

PlaneDetection_02

AR Session Origin に AR Plane Managerコンポーネントを追加する。

AR Plane Manager コンポーネントの Plane Plefab に Prefab 化した AR Default Plane を設定する。

ここまでで、 Android 、 iOS 両方に対応した平面検出が実装できました。

実機にビルドして動かすとこんな感じです。

ここまで、コードを一切書かずに作ることができます。

  • 検出速度、精度共に ARKit 、 ARCore と同じくらいの性能です。

  • iOS 上で動かす時のみ ARKit 同様、検出した平面が存在しない方向を向いた後に平面に向き直ると、平面の場所が大きくズレてしまう事があります。

平面にオブジェクトを置く

PlaneDetection_03

平面に向けて Ray を飛ばすために、 AR Session Origin に AR Raycast Managerコンポーネントを追加する。

var hits = new List<ARRaycastHit>();
if (_arRaycastManager.Raycast(touch.position, hits,TrackableType.PlaneWithinPolygon))
{
    Pose pose = hits[0].pose;

    // ここに生成、移動処理を書く
}

AR Raycast Managerコンポーネントの ARRaycastManager.Raycastメソッド で、平面に向けて Ray を飛ばして、 List<ARRaycastHit> を取得することができる。

ARRaycastHit から Pose を取得してオブジェクトを生成、移動させる。

出来上がったものがコチラです。

マーカー認識

ImageTracking_01

AR Session Origin に AR Tracked Image Managerコンポーネント を追加する。

ImageTracking_02

Project ビューで右クリック -> Create -> XR -> Reference Image Library を作成する。

ImageTracking_03

Add Image ボタンをクリックして、項目を増やし、Reference Image Library に認識したいマーカー画像を設定する。

※ Specify Size を有効にし、 Physical Size(物理サイズ)を設定すると、認識の精度が上がります。

ImageTracking_04

  1. AR Tracked Image Managerコンポーネント に作成した Reference Image Library を設定する。

また、検出したマーカーの位置に3D モデル等を表示たい場合は、 Tracked Image Prefab に任意の Prefab を設定する。

  1. ARTrackedImageManager.trackedImagesChanged に Event を登録する事で、 ARTrackedImagesChangedEventArgsクラス が取得できる。

  2. ARTrackedImagesChangedEventArgsクラス には、「新たに検出したマーカー」、「情報が更新されたマーカー」、「検出されなくなったマーカー」の情報 (ARTrackedImageクラス) が addedupdatedremoved にそれぞれ格納されている。

ARTrackedImageクラス から取得した値をもとに3D モデル等の Scale を調整する。

  • Position 、 Rotation は AR Session Originコンポーネント が検出したマーカーに合わせて自動で調整しているようです。
  • 移動するマーカーには対応していませんでした。

  • マーカーの移動後の再認識までの速度は iOS の方が早いようです。

顔認識

FaceTracking_01

AR Session OriginAR Face Managerコンポーネント を追加する。

AR Face Managerコンポーネント の Face Prefab に、顔に重ねて表示する Prefab を設定する。

  • iOS 、 Android どちらも同じプロジェクトでビルド出来るが、 Rig は ARKit と同様のものを取得しているので、 Android では顔の位置と向きのみのトラッキングとなり、 Rig は動かない。

  • UnityEngine.XR.ARCore.ARCoreFaceSubsystem.GetRegionPoses関数 で、 ARKit の Rig を ARCore の Rig に変換する事が可能。(変換可能なのは ARCore に定義されている額2点と鼻1点の合計3点のみ)

Environment Probes

EnvironmentProbes_01

AR Session OriginAR Environment Probe Managerコンポーネント を追加する。

EnvironmentProbes_02

周囲の風景を写したい GameObject のマテリアルの MetallicSmoothness を1に設定する。(この2つの値で見た目の調整ができる)

  • iOS のみ対応

EnvironmentProbes_03

  • カメラに映った物を映し出すので、本来映らないものまで映り込んでしまう。

(赤枠で囲んだ部分に本来写らないはずのコップやキーボードが写っています。)

  • ARKit の同機能とほぼ同じ。

World Map

ARKit 、 ARCore 共に似たような機能はあるが AR Foundation では iOS のみ対応

ARKitSessionSubsystem sessionSubsystem = (ARKitSessionSubsystem)m_ARSession.subsystem;

ARWorldMapRequest request = sessionSubsystem.GetARWorldMapAsync();

// World Map を取得
ARWorldMap worldMap = request.GetWorldMap();

// シリアライズ化
var data = worldMap.Serialize(Allocator.Temp);

UnityEngine.XR.ARKit.ARKitSessionSubsystem から WorldMap を取得し、シリアライズ化する事で、 AR 空間の情報を保存する事ができる。

// デシリアライズ
if (ARWorldMap.TryDeserialize(data, out worldMap))
{
    data.Dispose();
}

// World Map を適用
sessionSubsystem.ApplyWorldMap(worldMap);

byte 配列で保存してある World Map をデシリアライズする事で、同じ AR 空間を再現する事ができる。

  • 検出した平面や、生成した GameObject の位置、向き、大きさを再現する事ができています。

  • ロード用のメソッドを呼んでから、再現されるまで、3秒程かかります。

おわりに

  • Unity Technologies が作っているだけあって、 UnityEditor 上で簡単に AR が実装できました。

  • ただ、 ARFoundation を使用して iOS 向けに作ったプロジェクトを、そのまま Android 向けにビルドすると動作に差が生まれることがありそうです。