じゅころぐAR

AR/VRメインのブログ。時々ドローン。

ARKitのARObjectAnchorをUnityで使ってみる

ARKit2の新機能として追加されたARObjectAnchorをUnityで試してみます。

blogs.unity3d.com

ARObjectAnchorとは

現実の物体(オブジェクト)を検知して、Anchorの作成・トラッキングを行う機能です。
予め作成しておいたARReferenceObjectを元に検知を行います。

f:id:jyuko49:20180805172842p:plain

開発環境

ARKit2で追加された機能のため、iOS12およびXcode10が必要になります。
本記事執筆時点ではβ版のため、Apple Developerからダウンロードしました。

Unity ARKit Pluginのインストール

Unity ARKit PluginはBitbucketのから"arkit2.0_beta"ブランチをダウンロードします。

Unity-Technologies / Unity-ARKit-Plugin / Downloads — Bitbucket

ダウンロード後、Assets以下のUnityARKitPluginをUnityプロジェクトのAssetsにフォルダごとコピーして使います。

f:id:jyuko49:20180805171735p:plain

ARKitを使うのに必要なUnityの設定については割愛します。"Camera usage description"を忘れなければ、なんとかなると思います。

ARReferenceObjectを作成する

検知したいオブジェクトをスキャンして、ARReferenceObjectを作成します。
ここが上手くできないと検知の精度が落ちるので、重要な作業です。

UnityARKitPluginにExamplesとして付属しているUnityObjectScannerをビルドすると、スキャン用のアプリが起動します。

UnityARKitPlugin > Examples > ARKit2.0 > UnityObjectScanner

BoundingBoxを対象オブジェクトに合わせる

アプリ起動後の手順として、まずはBoundingBoxでスキャン対象のオブジェクトを囲み、Axisをオブジェクトの中心に合わせます。

f:id:jyuko49:20180805222935p:plain

基本的な操作方法は、以下の通り。

BoundingBoxの移動:オブジェクト付近の平面をタップ
BoundingBoxの伸縮:BoundingBoxの面をタップしてドラッグ
BoundingBoxの平行移動:Axisをタップしてドラッグ
BoundingBoxの回転:画面を二本指タップした状態で回転

対象オブジェクトをスキャンする

BoundingBoxの位置を合わせたら、その状態で対象オブジェクトを複数の方向からスキャンします。"Create Objects"、"Detect Objects"のボタンを押す必要はありません。カメラをかざすことで、オブジェクト上のPointCloudが特徴点として検出されていきます。

ARReferenceObjectを保存する

スキャンが完了したら、アプリ上のUIでARReferenceObjectを作成・保存します。

"Create Objects"でBoundingBox内の特徴点からARReferenceObjectが作られ、リストに追加されます。 この処理は多少時間がかかることがあり、画面中央のウィンドウにファイル名のリスト(objScan_0,objScan_1,...)が表示されたら、作成完了した合図です。
最後に、"Save Objects"でARReferenceObjectをファイルとしてデバイスに保存します。これを忘れると、せっかくスキャンした結果を利用できなくなります。

f:id:jyuko49:20180805225206p:plain

他のボタンは以下の用途に使えます。スキャンだけを行う場合、必須ではないです。

"Detect Object"は検知モードのON/OFFです。スキャン結果を用いた検知のテストに使えます。
"Clear Objects"は"Create Objects"で作成したARReferenceObjectを全て削除します。

ARReferenceObjectをコピーする

iTunesのファイル共有からコピーするのが簡単です。

スキャンを行ったデバイスMacに接続して、iTunesでファイル共有メニューを開きます。

f:id:jyuko49:20180805231521p:plain

アプリが作成したファイルに"ARReferenceObjects"という名称のフォルダがあり、ARReferenceObjectが保存されています。
フォルダごとMacにコピーしてFinderで開くと、拡張子が.arobjectのファイルがあるはずです。
このファイルをUnityにコピーして使います。

f:id:jyuko49:20180805232614p:plain

ARKitScannerを使ったARReferenceObjectの作成

スキャンを行う方法としてはもう一つ、Apple公式のサンプルコードをXcodeでビルドしたARKit Scannerが使えます。

Scanning and Detecting 3D Objects | Apple Developer Documentation

スキャンの流れはUnityのサンプルと同じですが、BoundingBoxの作成、Scan、Test、ファイルの保存・共有とステップを踏んでいくUIとなっており、UnityObjectScannerよりもわかりやすいです。

f:id:jyuko49:20180805221927p:plain

スキャンの進捗に応じてパーセンテージが表示され、スキャンを行った面はBoundingBoxが着色される機能もあるため、全方向から満遍なくスキャンを行えます。
100%になっていなくても"Finish" > "Cancel"(Continueのキャンセル)でスキャンを終了できます。

f:id:jyuko49:20180805221955p:plain

最終的に作成されるのは.arobjectファイルなので、Unityでも使えます。
ファイルの転送にAirDropが使える点も便利です。

ARObjectAnchorを使う

作成したARReferenceObjectを使って、ARObjectAnchorの作成、コンテンツの重ね合わせを行います。

Unity ARKit PluginでARObjectAnchorを使うには、UnityARCameraManagerの"Detection Objects"ARReferenceObjectsSetAssetをセットします。

f:id:jyuko49:20180805235927p:plain

ARReferenceObjectsSetAssetは、プロジェクトウィンドウで右クリックから"Create" > "UnityARKitPlugin" > "ARReferenceObjectsSetAsset"で作成できます。

f:id:jyuko49:20180805165517p:plain

ARReferenceObjectsSetAssetには、検知対象のARReferenceObjectAssetを複数セットできます。

f:id:jyuko49:20180806001817p:plain

ARReferenceObjectAssetもプロジェクトウィンドウで右クリックから"Create" > "UnityARKitPlugin" > "ARReferenceObjectAsset"で作成できます。

f:id:jyuko49:20180806002206p:plain

ARReferenceObjectsAssetには、スキャンで作成した.arobjectファイルをARReferenceObjectとしてセットします。

ここまでで、ARSessionに検知対象のARReferenceObjectが設定され、ARObjectAnchorが作成されるようになります。

作成されたARObjectAnchorを使ってARコンテンツを重ねるにはスクリプトを使います。UnityARObjectAnchorで利用されているGenerateObjectAnchor.csが参考になります。

まず、Start()でARObjectAnchor作成時、更新時に実行するメソッドを定義します。

void Start () {
    UnityARSessionNativeInterface.ARObjectAnchorAddedEvent += AddObjectAnchor;
    UnityARSessionNativeInterface.ARObjectAnchorUpdatedEvent += UpdateObjectAnchor;
}

ARSessionでオブジェクトが検知されると、定義したメソッドが呼ばれ、ARObjectAnchorが渡されます。
作成時に呼ばれるメソッド(AddObjectAnchor())では、ARObjectAnchorからposition、rotationを取得して、GameObjectを生成(Instantiate)しています。

void AddObjectAnchor(ARObjectAnchor arObjectAnchor)
{
    Debug.Log ("object anchor added");
    if (arObjectAnchor.referenceObjectName == referenceObjectAsset.objectName) {
        Vector3 position = UnityARMatrixOps.GetPosition (arObjectAnchor.transform);
        Quaternion rotation = UnityARMatrixOps.GetRotation (arObjectAnchor.transform);

        objectAnchorGO = Instantiate<GameObject> (prefabToGenerate, position, rotation);
    }
}

検知したオブジェクトの位置が更新されると、更新されたARObjectAnchorが渡されます。
更新時のメソッド(UpdateObjectAnchor())では、生成したGameObjectの位置をARObjectAnchorの更新に合わせて上書きしています。

void UpdateObjectAnchor(ARObjectAnchor arObjectAnchor)
{
    Debug.Log ("object anchor added");
    if (arObjectAnchor.referenceObjectName == referenceObjectAsset.objectName) {
        objectAnchorGO.transform.position = UnityARMatrixOps.GetPosition (arObjectAnchor.transform);
        objectAnchorGO.transform.rotation = UnityARMatrixOps.GetRotation (arObjectAnchor.transform);
    }
}

基本的には、上記のサンプルコードと同様にGameObjectの生成、位置の更新を行えばARコンテンツが現実のオブジェクトに重ねて表示され、対象が動いても追従するようになります。
複数のオブジェクトを検出しつつ、異なるARコンテンツを表示したい場合は、ARReferenceObjectAssetに設定したObjectNameがARObjectAnchorにセットされるため、何を検知したかを名称によって制御できます。

アプリで動かしてみる

まず、UnityARObjectAnchorと同様にAxisを表示してみます。

スキャンしたARReferenceObjectの精度にもよりますが、検知に数秒かかるようなこともなく、オブジェクトにカメラをかざすとすぐに検知してくれます。

続いて、ARコンテンツを3D Textに変更して、追従のテストを行ってみました。

検知対象のオブジェクトが移動すると、テキストも移動していることがわかります。

まとめ

ARKit2で追加されたARObjectAnchorは、現実の物体をARで拡張するのに適した機能です。
ARReferenceObjectのスキャンがやや面倒ではありますが、アプリの操作に慣れれば数分で作成できます。一度作成してしまえば、どのアプリでも使えますし、ファイルを共有することで同じ物を持っている人も使えます。

用途としてイメージしやすいのは、今回試したようにフィギュアや模型にエフェクトやUIを重ねる使い方でしょうか。市販されている製品であれば、ARReferenceObjectをインターネットで配布・共有できる点も魅力です。
また、物体の移動を検知できるので、チェスのような物の配置によって局面が変わるようなゲームにも使えそうです。

立体的な特徴が少なく検知が難しい場合、平面画像を検知・追従するARImageAnchorが代用できます。