イケメンテックラボでエンジニアをしている寺林です。
今回は以前紹介したARCoreの導入記事以来のARCoreネタになります。
前回の記事では、『平面を認識し、その平面にオブジェクトを置く』という、所謂マーカーレスARを紹介しました。
ARCoreでは、このマーカーレスAR以外にもマーカーを使ったAR、AugmentedImageをサポートしています。今回はUnityでマーカーを使ったARCoreアプリの作り方を紹介します!
今回の記事では、ARCoreを導入済みのUnity環境がある前提で説明していきます。まだ環境のない方は先に、以前紹介した導入の記事をご覧ください。バージョンは少し古くなってしまいますが、手順は同じになります。
そもそもマーカーARとは?
マーカーARは文字通り、マーカー(画像)を使ったARです。

マーカーをカメラで捉える事で識別し、その上にオブジェクトを出す、という仕組みです。
ARkitやARCoreのような、平面を検知してその上に置く、という手法が出るずっと前からマーカーARは存在しており、結構歴史があります。
Nintendo3DSでもARマーカーで遊ぶゲームがありましたね。懐かしい。
開発環境について
今回記事を書く上で検証した環境は以下の通りです。
・Unity2018.3.11
・ARCore-Unity-SDK1.9.0 (https://github.com/google-ar/arcore-unity-sdk/releases/tag/v1.9.0)
ARCoreのバージョンは可能な限り1.9以上を使用することをお薦めします。
と、言うのもARCoreは1.9からAugmentedImageの精度がかなり上がっており、マーカーのトラッキング性能がとても良くなっています。1.8以下でも基本的には実装の方法は同じですが、ARの体験としては1.9の方が良いです。
準備 マーカーを用意しよう
それではいつも通り、Unityのプロジェクトを作成しましょう。
作成したら、ARCoreのSDKのインポートとAndroidへSwitch Platformをしておきましょう。

インポートが終わったら、最初から開かれてるSampleSceneにAssets/GoogleARCore/Prefabsの中にあるARCore Deviceを配置しましょう。

これでARCore自体の準備はできました。
次にマーカー画像の登録をしましょう。
今回マーカー画像にこちらを用意しました。

みんな大好きいらすとやのAR・拡張現実のイラストです!
一般的に、ARマーカーはチェック柄のような、繰り返しの少ない模様が適していると言われています。このイラスト素材は適度に複雑で、色数も多い画像なのでマーカーに適していそうですね!
この画像をUnityにインポートします。(今回はJPGにしてます)
インポートしたら、画像を右クリック→Create→Google ARCore→AugmentedImageDatabaseをクリックします。するとデータベースファイルが生成されるので適当な名前をつけておきましょう。今回は「marker」としました。

markerを選択してみるとこのようにマーカーの情報が表示されます。
マーカーに対応する名前、マーカーの大きさ(今回は0.1、10cmくらいにしておきましょう)、
そしてQuality(マーカーにどれくらい適しているかの指標)が表示されます。

いらすとやの画像はQualityが95でした!最大値が100なのでこれはかなり高いです。いらすとや優秀ですね…
次にARCore Deviceを選択し、ARCoreSessionの中にあるSession Configをダブルクリックし、セットされているDefaultSessionConfigを開きます。

その中にあるAugmentedImage Databaseに、先ほど作ったmarkerを入れます。
これでマーカーを検知することが可能になりました。

検出するコードを書く
このマーカーを検知できるようにコードを書きましょう!
まずは空のGameObjectを作成します。今回はManagerという名前のオブジェクトを作りました。

スクリプトを作成し、このManagerにアタッチしましょう。
今回はこのようなスクリプトを作成しました。
using System.Collections;
using System.Collections.Generic;
using GoogleARCore;
using UnityEngine;
public class AugmentedImageSample : MonoBehaviour {
private List<AugmentedImage> augmentedImageList = new List<AugmentedImage> ();
[SerializeField] private GameObject ObjPrefab;
private GameObject arObj = null;
void Update ()
{
if (Session.Status != SessionStatus.Tracking)
{
return; //トラッキングできてないのでreturn
}
//ARCoreがトラッキングしているものを取得する。
Session.GetTrackables<AugmentedImage> (augmentedImageList, TrackableQueryFilter.Updated);
foreach (AugmentedImage image in augmentedImageList)
{
if (image.TrackingState == TrackingState.Tracking)
{
if (arObj == null)
{
//トラッキング中かつarObjがNullなのでオブジェクトを生成する
Anchor anchor = image.CreateAnchor (image.CenterPose);
arObj = Instantiate (ObjPrefab, anchor.transform);
}
else
{
//トラッキング中かつarObjが既に存在するので位置・回転の更新を行う。
arObj.transform.position = image.CenterPose.position;
arObj.transform.rotation = image.CenterPose.rotation;
}
}
}
}
}
サンプルなので必要最低限ですが、このようなコードを書きました。
このコードを実行すると、カメラでマーカーを捉えた際に自動的にオブジェクトを生成し、位置の調整がされるようになります。
Obj Prefabに生成したいオブジェクトをセットしましょう。

今回はこのようなSphereを生成し、Prefabにしました。

このSphereですが、Scaleが1,1,1のままだととんでもなく大きいサイズで出てしまうので0.1くらいにしてあげましょう。
Unityではscale1は1メートルとして扱われます。そのためそのまま出すと1メートルの大きさになってしまいます。(参考: https://blogs.unity3d.com/2017/11/16/dealing-with-scale-in-ar/ )

ビルドの設定をしてビルドをしましょう。ビルド設定周りは前回記事を参照してください。

実機で動かしてみた
マーカーを検知したらSphereが生成されているのがわかると思います。
紙をずらしたりしても、しっかりとオブジェクトがついてきます!(ARCore1.8以下だとこの辺が弱いです)
とてもシンプルなコードでこれだけ精度が取れるのは嬉しいですね。
まとめ
ARCoreでAugmentedImageを使用してみました。
マーカーARは最近主流の平面を認識するタイプのARと比べると若干古い技術感はありますが、その分、精度も高く、安定感があるような印象です。
作りたいアプリやゲームに合わせてARの方式を決められるように、両方触っておくと良いかもしれないですね。
おまけ GetTrackingMethod()
ARCore1.9よりGetTrackingMethodというものが追加されました。
これはAugmentedImage型のメンバーにいるもので、マーカーのトラッキング状態を取得することができます。
サンプルを改造してTrackingMethodの中身を画面左上に出してみました。
今まさにトラッキングしているのか、見失ったけど見失う直前の場所に出しているのか、といった判別ができます。
アプリの仕様としてトラッキングしていないといけないようなアプリの場合はこの情報を見ることで処理を分岐させたりできる訳ですね。とても便利。