地理空間アンカーを使用して Unity に現実世界のコンテンツを配置する

地理空間アンカーは、3D コンテンツを現実世界に配置できるアンカーの一種です。

地理空間アンカーのタイプ

地理空間アンカーには 3 つのタイプがあり、高度の扱い方はそれぞれ異なります。

  1. WGS84 アンカー:
    WGS84 アンカーを使用すると、任意の緯度に 3D コンテンツを配置できます。 経度、高度です

  2. 地形のアンカー:
    地形アンカーを使用すると、緯度と経度のみを使用してコンテンツを配置できます。 その位置の地形に対する高さで経度を表す 標高は、地上または階を基準にして決まります。 VPS です。

  3. 屋上アンカー:
    屋上アンカーを使用すると、緯度と経度のみを使用してコンテンツを配置できます。 経度と緯度を使用して、その位置の建物の屋上に対する高さを求めます。 標高は、建物の上部を基準として計算されます。 Streetscape Geometry を使用します。 建物に設置しない場合、デフォルトで地形標高に設定されます。

WGS84 地形 ルーフトップ
水平方向 緯度、経度 緯度、経度 緯度、経度
垂直方向 WGS84 高度を基準にします Google マップが決定した地形レベルに基づきます Google マップが決定した屋上のレベルを基準にします
サーバーで解決する必要があるか いいえ

前提条件

続行する前に、Geospatial API が有効になっていることを確認してください。

地理空間アンカーを配置する

各アンカータイプには、それらを作成するための専用 API があります。詳細については、地理空間アンカーのタイプをご覧ください。

ヒットテストからアンカーを作成する

ヒットテスト結果から地理空間アンカーを作成することもできます。 ヒットテストのポーズを使用して、GeospatialPose に変換します。これを使用して、ここで説明した 3 つのアンカータイプのいずれかを配置します。

AR ポーズから地理空間ポーズを取得する

AREarthManager.Convert(Pose) を使用すると、AR ポーズを地理空間ポーズに変換して緯度と経度を特定することができます。

地理空間ポーズから AR ポーズを取得する

AREarthManager.Convert(GeospatialPose) は、東と南の座標フレームを基準とする地球で指定された水平位置、高度、四元数の回転を、GL ワールド座標に基づく AR ポーズに変換します。

ユースケースに適した方法を選択する

アンカーを作成する各方法には、留意すべきトレードオフがあります。

  • ストリートビュー ジオメトリを使用する際は、 ヒットテストを使用してコンテンツを建物にアタッチする
  • WGS84 アンカーよりも Terrain アンカーや Rooftop アンカーが優先されます。Google マップが決定した標高値を使用します。

場所の緯度と経度を特定する

場所の緯度と経度は、次の 3 つの方法で計算できます。

  • Geospatial Creator を使用すると、実際にその場所に行かなくても 3D コンテンツで世界を見たり、拡張したりすることができます。これにより、Unity Editor で Google マップを使用して、3D の没入型コンテンツを視覚的に配置できます。コンテンツの緯度、経度、回転、高度が自動的に計算されます。
  • Googleマップを使用
  • Google Earth を使用する。Google マップではなく Google Earth を使用してこれらの座標を取得する場合は、最大数 m の誤差が生じます。
  • 物理的なビジネス拠点へ行く

Googleマップを使用

Google マップを使用して場所の緯度と経度を取得するには:

  1. パソコンで Google マップにアクセスします。

  2. [レイヤ] に移動します。その他

  3. [地図タイプ] を [航空写真] に変更し、画面の左下にある [地球表示] チェックボックスをオフにします。

    これにより、強制的に 2D の視点が表示され、斜めの 3D 表示から生じる可能性があるエラーを排除できます。

  4. 地図上で場所を右クリックし、経度と緯度を選択してクリップボードにコピーします。

Google Earth を使用する

Google Earth で場所の緯度と経度を計算するには、UI で場所をクリックし、目印の詳細からデータを読みます。

Google Earth で場所の緯度と経度を取得するには:

  1. デスクトップ パソコンで Google Earth にアクセスします。

  2. ハンバーガー メニュー に移動し、[地図のスタイル] を選択します。

  3. [建物の 3D 表示] スイッチをオフに切り替えます。

  4. [建物の 3D 表示] スイッチをオフに切り替えたら、ピンアイコン をクリックして、選択した場所に目印を追加します。

  5. 目印を格納するプロジェクトを指定し、[保存] をクリックします。

  6. 目印の [タイトル] フィールドに、目印の名前を入力します。

  7. プロジェクト ペインの戻る矢印 をクリックし、 [その他の操作] メニューを選択します。

  8. メニューから [KML ファイルとしてエクスポート] を選択します。

KLM ファイルは、次のように <coordinates> タグをカンマで区切って、目印の緯度、経度、高度をレポートします。

<coordinates>-122.0755182435043,37.41347299422944,7.420342565583832</coordinates>

<LookAt> タグの緯度と経度は、場所ではなくカメラの位置を指定するものとして使用しないでください

物理的なビジネス拠点へ行く

実際にその場所に行ってローカルで観察することで、場所の標高を計算できます。

回転四元数を取得する

GeospatialPose.EunRotation は地理空間ポーズから向きを抽出し、ターゲットから東北(EUN)座標系にベクトルを変換する回転行列を表す四元数を出力します。X+ は東、Y+ は重力から上向き、Z+ は北を指します。

WGS84 アンカー

WGS84 アンカーはアンカーの一種で、指定された緯度、経度、高度に 3D コンテンツを配置できます。ポーズと向きによって、現実世界に配置されます。位置は緯度、経度、高度で構成され、WGS84 座標系で指定されます。向きは四元数回転で構成されます。

高度は、地面レベルがゼロではないように、基準となる WGS84 楕円体から高度をメートル単位でレポートします。アプリは、作成した各アンカーのこれらの座標を提供する役割を担います。

WGS84 アンカーを現実世界に配置する

場所の標高を特定する

アンカーを配置するための場所の高度を決定する方法はいくつかあります。

  • アンカーの場所がユーザーの物理的に近い場合は、ユーザーのデバイスの高度と同じ高度を使用できます。
  • 緯度と経度を取得したら、Elevation API を使用して、EGM96 仕様に基づく高度を取得します。標高 GeospatialPose と比較するには、Maps API EGM96 の高度を WGS84 に変換する必要があります。コマンドラインと HTML インターフェースの両方がある GeoidEval をご覧ください。Maps API は、すぐに WGS84 の仕様に従って緯度と経度をレポートします。
  • 場所の緯度、経度、高度は、Google Earth から取得できます。これにより、最大数 m の誤差が生じます。KML ファイルの <LookAt> タグではなく、<coordinates> タグの緯度、経度、高度を使用します。
  • 既存のアンカーが近くにあり、かつ急な傾斜ではない場合は、Maps API などの別のソースを使用しなくても、カメラの GeospatialPose から取得した標高を使用できる場合があります。

アンカーを作成する

緯度、経度、高度、回転四元数を取得したら、ARAnchorManagerExtensions.AddAnchor() を使用します。 指定した地理座標にコンテンツを固定できます。

if (earthTrackingState == TrackingState.Tracking)
{
  var anchor =
      AnchorManager.AddAnchor(
          latitude,
          longitude,
          altitude,
          quaternion);
  var anchoredAsset = Instantiate(GeospatialAssetPrefab, anchor.transform);
}

地形用アンカー

Terrain アンカーはアンカーの一種で、緯度と経度のみを使用して AR オブジェクトを配置し、VPS からの情報を活用して地上の正確な高度を特定します。

目的の高度ではなく、地形上の標高を指定します。これがゼロの場合、アンカーは地形と水平になります。

飛行機探索モードを設定する

飛行機の検出は任意であり、アンカーを利用するために必須ではありません。水平面のみが使用されることに注意してください。水平面を使用すると、地形アンカーを地面に動的に配置できます。

なお、地形アンカーは HorizontalHorizontal | Vertical の影響を受けます。

[検出モード] プルダウン メニューを使用して検出モードを設定します。

新しい Async API を使用して地形アンカーを作成する

Terrain アンカーを作成して配置するには、ARAnchorManagerExtensions.resolveAnchorOnTerrainAsync() を呼び出します。

アンカーはすぐには使用できるわけではないため、解決する必要があります。解決すると、ResolveAnchorOnTerrainPromiseに表示されます。

public GameObject TerrainAnchorPrefab;

public void Update()
{
    ResolveAnchorOnTerrainPromise terrainPromise =
        AnchorManager.ResolveAnchorOnTerrainAsync(
            latitude, longitude, altitudeAboveTerrain, eunRotation);

    // The anchor will need to be resolved.
    StartCoroutine(CheckTerrainPromise(terrainPromise));
}

private IEnumerator CheckTerrainPromise(ResolveAnchorOnTerrainPromise promise)
{
    yield return promise;

    var result = promise.Result;
    if (result.TerrainAnchorState == TerrainAnchorState.Success &&
        result.Anchor != null)
    {
        // resolving anchor succeeded
        GameObject anchorGO = Instantiate(TerrainAnchorPrefab,
            result.Anchor.gameObject.transform);
        anchorGO.transform.parent = result.Anchor.gameObject.transform;
    }
    else
    {
       // resolving anchor failed
    }

    yield break;
}

Promise の状態を確認する

Promise には PromiseState が関連付けられます。

説明
Pending オペレーションはまだ保留中です。
Done オペレーションが完了し、結果が利用可能になっています。
Cancelled オペレーションはキャンセルされました。

Promise の結果の Terrain アンカー状態を確認する

TerrainAnchorState は非同期処理に属し、最終的な Promise の結果の一部です。

switch (result.TerrainAnchorState)
{
    case TerrainAnchorState.Success:
        // Anchor has successfully resolved
        break;
    case TerrainAnchorState.ErrorUnsupportedLocation:
        // The requested anchor is in a location that isn't supported by the Geospatial API.
        break;
    case TerrainAnchorState.ErrorNotAuthorized:
        // An error occurred while authorizing your app with the ARCore API. See
        // https://developers.google.com/ar/reference/unity-arf/namespace/Google/XR/ARCoreExtensions#terrainanchorstate_errornotauthorized
        // for troubleshooting steps.
        break;
    case TerrainAnchorState.ErrorInternal:
        // The Terrain anchor could not be resolved due to an internal error.
        break;
    default:
        break;
}

屋上アンカー

屋上アンカーのヒーロー画像

屋上アンカーはアンカーの一種で、上記の地形アンカーによく似ています。違いは、地形の上の高度ではなく、屋根の上の高度を指定する点です。

新しい Async API を使用して屋上アンカーを作成する

アンカーはすぐには使用できるわけではないため、解決する必要があります。

屋上アンカーを作成して配置するには、ARAnchorManagerExtensions.resolveAnchorOnRooftopAsync() を呼び出します。Terrain アンカーと同様に、Promise の PromiseState にもアクセスできます。その後、Promise の結果を確認して RooftopAnchorState にアクセスできます。

public GameObject RooftopAnchorPrefab;

public void Update()
{
    ResolveAnchorOnRooftopPromise rooftopPromise =
        AnchorManager.ResolveAnchorOnRooftopAsync(
            latitude, longitude, altitudeAboveRooftop, eunRotation);

    // The anchor will need to be resolved.
    StartCoroutine(CheckRooftopPromise(rooftopPromise));
}

private IEnumerator CheckRooftopPromise(ResolveAnchorOnTerrainPromise promise)
{
    yield return promise;

    var result = promise.Result;
    if (result.RooftopAnchorState == RooftopAnchorState.Success &&
        result.Anchor != null)
    {
        // resolving anchor succeeded
        GameObject anchorGO = Instantiate(RooftopAnchorPrefab,
            result.Anchor.gameObject.transform);
        anchorGO.transform.parent = result.Anchor.gameObject.transform;
    }
    else
    {
       // resolving anchor failed
    }

    yield break;
}

Promise の状態を確認する

Promise には PromiseState が関連付けられています。上記のをご覧ください。

Promise の結果の屋上アンカー状態を確認する

RooftopAnchorState は非同期処理に属し、最終的な Promise の結果の一部です。

switch (result.RooftopAnchorState)
{
    case TerrainAnchorState.Success:
        // Anchor has successfully resolved
        break;
    case RooftopAnchorState.ErrorUnsupportedLocation:
        // The requested anchor is in a location that isn't supported by the Geospatial API.
        break;
    case RooftopAnchorState.ErrorNotAuthorized:
        // An error occurred while authorizing your app with the ARCore API. See
        // https://developers.google.com/ar/reference/unity-arf/namespace/Google/XR/ARCoreExtensions#terrainanchorstate_errornotauthorized
        // for troubleshooting steps.
        break;
    case RooftopAnchorState.ErrorInternal:
        // The Rooftop anchor could not be resolved due to an internal error.
        break;
    default:
        break;
}

次のステップ