おもちゃラボ

Unityで遊びを作ってます

【ARKit】GPSで特定の場所にARを表示する

ポケモンGOのように特定の場所に何かを表示したい場合や、Yahoo地図のように目的地までの道順をARで表示したい場合、ARとGPSを組み合わせて作るのが一般的です。

f:id:nn_hokuson:20190612214208j:plain:w600

この記事ではARKitとGPSを使って京都駅の上に矢印を出すアプリケーションの作り方を紹介したいと思います。この記事の目次は次のようになります。

GPSの情報からARを表示する方法

特定の場所にARオブジェクトを表示するには、目的地の緯度経度情報を使います。と言っても緯度経度の情報をそのまま指定することはできません。

そこで現在いる場所の緯度経度と、目的地の緯度経度の差分を計算し、この差分を距離に変換します。これにより「現在地点から北に〇〇km、東に〇〇km行ったところという指定が出来るようになります。

f:id:nn_hokuson:20190611213807p:plain:w600

ただ、北に〇〇と言ってもAR空間はどちらが北かという情報は持っていません。したがってARアプリ内でどちらが北かを把握して、AR空間と対応付ける必要があります。ARKitにはAlignmentというオプションがあり、これを使うと常に+z方向が北を指すようになります。

したがって、「北に〇〇km、東に〇〇km」は「+z方向にに〇〇、+x方向〇〇」と言い換えられ、無事、目的の場所にARオブジェクトを表示できる、というカラクリです。

f:id:nn_hokuson:20190611213820p:plain:w500

データのインポート

まずはプロジェクトを作成し、ARKit Pluginをインポートしておきましょう。今回もUnityARKitPlugin/Examples/UnityARKitSceneを使用します。詳しい手順はこちらで紹介しています。

nn-hokuson.hatenablog.com

続いて、3Dオブジェクトをインポートします。好きなモデルをAsset Storeなどからダウンロードしてインポートしましょう。ここでは矢印の3Dモデルを表示します。(ここで使用したファイルは↓からダウンロードできます)

矢印の3Dモデルのダウンロード

ARKitの設定

上でも書いたように、AR空間の+z方向が常に北を指すようにする必要があります。そこで、AR Config OptionのAlignmentの設定を行います。

ヒエラルキーウインドウからARCameraManagerを選択し、UnityARCameraManagerスクリプトStart Alignmentを「Unity AR Alignment Gravity and Heading」に設定してください。

f:id:nn_hokuson:20190611212219p:plain:w400

これによりARKitでは+z方向が北、-y方向が下(重力)方向を指すようになります。

カメラのFar Clipを設定する

また、デフォルトのカメラ設定では、Far Clipが30になっています。このままだと、30mよりも遠い場所にある物体はクリッピングされてしまいます(これ、はまった!)。そこで、カメラのFar Clipの距離は100から1000程度に設定しておきましょう。

f:id:nn_hokuson:20190611212322p:plain:w400

デスクリプションの記述

また、今回のアプリはARでカメラ映像、位置測定でGPSを使うため、descriptionに記述が必要です。これがないと、アプリが落ちるので注意してください。

f:id:nn_hokuson:20190611212336p:plain:w400

Build Settingsの画面でプラットフォームをiOSに変更したあとで、Player Settingsの画面から、Camera Usage DescriptionとLocation Usage Descriptionの欄に適当な文字列を設定します。

GPSの情報を取得する

それではこの矢印を京都駅の上に表示するプログラムを作っていきましょう。GPSControllerというスクリプトを作成して、次のプログラムを入力してください。

   
public class GPSController : MonoBehaviour
{
    public double latitude  = 34.984700;   // 京都駅の緯度
    public double longitude = 135.758257;  // 京都駅の経度
    const double lat2km = 111319.491;

    public Vector3 ConvertGPS2ARCoordinate(LocationInfo location)
    {
        double dz =   (latitude - location.latitude) * lat2km;   // -zが南方向
        double dx = - (longitude - location.longitude) * lat2km; // +xが東方向
        return new Vector3( (float)dx, 0, (float)dz );
    }
    
    void Start()
    {
        Input.location.Start();

        Invoke("UpdateGPS", 1.0f);
    }

    public void UpdateGPS()
    {
        if (Input.location.isEnabledByUser)
        {
            if(Input.location.status == LocationServiceStatus.Running)
            {
                LocationInfo location = Input.location.lastData;

                transform.position =  ConvertGPS2ARCoordinate(location);
            }
        }
    }
}

UnityではLocationクラスを使ってGPSの情報を取得できます。はStartメソッドの中でGPSモジュールをオンにし、Updateメソッドの中で毎フレームGPSの情報を取得しています。

最新の緯度と経度はInput.location.lastData構造体を使って得ることができます。

変数 データ
latitude 緯度
longitude 経度

次にConvertGPS2ARCoordinateメソッドの中で、緯度経度のデータをARのワールド座標に変換しています。

まずは現在の緯度経度と、目的地の緯度経度の差分を計算します。目的地の緯度経度はGoogleMapを使うと簡単に調べられます。Google Map上で調べたい地点を右クリックし、「この場所について」を選択してください。画面下に緯度と経度が表示されます。

f:id:nn_hokuson:20190611212249p:plain:w600

緯度経度の差分がわかったところで、この差分を距離(km)の情報に変換します。緯度(経度)はおおよそ1度が111319.491kmなので、これを差分の値に乗算しています。

ARKitの設定で「Unity AR Alignment Gravity and Heading」を設定したため、+z方向が北を向きます。したがって+x方向が東、-z方向が南を指します。この値に合うように、緯度に基づく差分の距離をz座標、経度に基づく差分の距離をx座標に設定します。これで、目的の場所にARオブジェクトを表示出来るようになりました。

スクリプトは矢印のオブジェクトにアタッチしておいてください。

実行結果

ビルドして実行してみましょう。実行結果は次のようになりました。ちゃんと京都駅の上(八条口ですが笑)に矢印が表示されていますね!
f:id:nn_hokuson:20190612214208j:plain:w450