ARCore Geospatial APIのサンプルを元にナビを作ってみた

Google I/O 2022で、ARCore Geospatial APIが発表されました。
Unityで使えるサンプルプロジェクトも公開されたので早速使ってみたのですが、これがものすごく良い!!
画期的すぎていろいろ夢が広がります。

Discover how to use ARCore Geospatial API to remotely attach content to any area covered by Google Street View and create AR experiences on a global scale.

これまでパブリックで使えるVPS(Visual Positioning System)は、Immersalなどが公開されていました。利用するには、位置合わせをしたい場所の写真を自分で大量に撮影し、マップを作成する必要がありました。

このマップを、Google Mapsでお馴染みのStreet Viewの情報を使って行ってしまうのがGeospatial APIです。
なので、Street Viewに公開されている場所なら自分でマップを生成することなしに、あらゆる場所で正確な位置合わせが行えてしまうわけです。

逆に言うと、Street Viewに公開されていない場所、例えば屋内などのプライベートな場所や機密性の高い場所で使用するには、Immersalなどマップを自分で作成できるサービスが依然として必要になります。
公開されていても、Geospatial APIの精度では足りない場合は同じく自分でマップを作ることができるサービスが必要ですね。

サンプルを動かす

まずは、SDKとサンプルプロジェクトが動作する状態にします。
APIを使うためのKeyを取得する方法を含めて、必要下記ページにとてもわかりやすくまとまっています。

サンプルのGeospatialシーンや公式ドキュメントを見ていくと大体の使い方が見えてきます。

まず、Geospatial APIを使うときには、緯度・経度・高度の値が重要になります。
Geospatial APIでできる重要なことの1つが、プログラムが動いているスマホの「緯度・経度・高度・向き」がかなり正確にわかる、ということです。
これは高精度で高価な外付けのGPS(GNSS)を使ってもなかなか難しかったことで、これがスマホ単体で正確に速くわかってしまうのが本当に画期的です。

さらに、緯度・経度・高度を指定してオブジェクトを配置する、という機能もとても便利です。
これまでは端末の緯度経度が正確に分かったとしても、そこを基準にしてオブジェクトを配置するためには、面倒な緯度経度とUnity座標系の変換が必要でした。
Geospatial APIを使用すると、緯度・経度・高度・向きからUnity座標を簡単に算出してオブジェクトを配置することができます。

さっそくサンプルのGeospatialController.csで、オブジェクトを配置するメソッドを見てみましょう。

public void OnSetAnchorClicked()
{
    var pose = EarthManager.CameraGeospatialPose;
 
    GeospatialAnchorHistory history = new GeospatialAnchorHistory(
        pose.Latitude, pose.Longitude, pose.Altitude, pose.Heading);
 
    if (PlaceGeospatialAnchor(history))
    {
        _historyCollection.Collection.Add(history);
        SnackBarText.text = $"{_anchorObjects.Count} Anchor(s) Set!";
    }
    (略)
}

これは、端末の位置にオブジェクトを配置する、という流れなのですが、端末の位置は、EarthManager.CameraGeospatialPose から簡単に取得できることがわかります。
繰り返しになりますが、スマホ単体で正確にこの値が取得できるのは本当に素晴らしいです。
そして、オブジェクトを配置するために、PlaceGeospatialAnchorを呼び出しています。

private bool PlaceGeospatialAnchor(GeospatialAnchorHistory history)
{
    Quaternion quaternion =
        Quaternion.AngleAxis(180f - (float)history.Heading, Vector3.up);
 
    var anchor = AnchorManager.AddAnchor(
        history.Latitude, history.Longitude, history.Altitude, quaternion);
 
    if (anchor != null)
    {
        GameObject anchorGO = Instantiate(GeospatialPrefab, anchor.transform);
        _anchorObjects.Add(anchorGO);
        return true;
    }
 
    return false;
}

AnchorManager.AddAnchorに、端末の位置から作ったGeospatialAnchorHistoryを渡すことによってアンカーを作成し、そのアンカーのtransformを使ってPrefabをInstantiateしています。
これだけで、指定した緯度経度の位置にオブジェクトを配置できてしまうわけです。

ナビアプリを作る

サンプルを拡張して、ARナビアプリを作ってみました。

アンカーの配置方法はわかったので、あとはGoogle MapsのDirections APIの結果から道順の情報(ナビを行う緯度経度)を取り出して配置すれば作れます。

#本投稿を書くきっかけ自宅から行き先を調べるとき、行き先が1つの場合は Googleマップで入力すれば問題ないですが、遊びにいく候補地(目的地)のリストがあって、自宅からの所要時間を調べるとき、…

Directions APIの結果のJSONをUnity C#で扱うには、Visual Studioの自動生成機能で作ったクラスで、JsonConvert.Deserializeを行うと簡単です。

はじめにあんまりこの辺の基本機能が有名ではないようなので紹介しておこうかと思います。ちなみにですが XML でもまったく同じことが可能です。前提適当な C# プロジェクトを作っておいてください…
高度問題

しかしながら、アンカーを配置する際に1点問題があります。それは「高度」です。
いま端末がある緯度・経度・高度は簡単に取得できますが、オブジェクトを遠くに配置する場合、そこの高度は何を指定すればいいのでしょうか?
単純化して、いまの端末の高さと同じ値を指定することも場合によってはアリですが、そうすると、地面の高さが違うので地面に埋まったり空中に浮いたりしてしまいます。

ドキュメントには、遠くのものは緯度経度から標高を求めよう、とあり、その方法が記載されています。

仕組み的には、緯度経度で異なる「ジオイド」と「標高」を組み合わせて算出を行います。
算出方法はドキュメントに記載されているものの他、幾つもやり方がありそうなのですが、今回はたぬ福さんに教えてもらったジオイドと標高を求める国土地理院のAPIを使用しました。

上記ツイートにあるように、ジオイドと標高の値を緯度経度から算出し、足し算することでAddAnchorに指定する高度を求めています。
いろいろな要素があるので完全に正確ではなさそうなのですが、いまのところ自然に表示できています。

また、ジオイドの値はかなり広い範囲で変化がないので、オブジェクトを配置する範囲がそれほど広くなければ、最初の1回だけ取得して、その値を使い回すのでも大丈夫です(と社内勉強会で教えてもらいました)

以上のように、ちょっと触った感じですがGeospatial APIは本当に強力です。ARが日常で必須のツールになる日がぐっと近づいた気がしました!

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク