地理空間アンカーを使用して Android SDK(Kotlin/Java)上に実際のコンテンツを配置する

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

地理空間アンカーの種類

ジオスペース アンカーには 3 種類あり、それぞれ高度を異なる方法で処理します。

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

  2. 地形アンカー:
    地形アンカーを使用すると、緯度と経度のみを使用してコンテンツを配置し、その位置の地形に対する高さを指定できます。高度は、VPS で知られている地面または床に対して測定されます。

  3. 屋上アンカー:
    屋上アンカーを使用すると、緯度と経度のみを使用してコンテンツを配置し、その位置にある建物の屋上からの高さを指定できます。高度は、街並みのジオメトリで知られている建物の頂点に対して相対的に決定されます。建物に配置されていない場合は、デフォルトで地形の高さに設定されます。

WGS84 地形 屋上
水平方向 緯度、経度 緯度、経度 緯度、経度
垂直方向 WGS84 高度に相対 Google マップによって決定された地形レベルを基準とする Google マップによって決定された屋上レベルからの相対値
サーバー側で解決する必要があるか いいえ

前提条件

続行する前に、Geospatial API を有効にしてください。

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

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

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

ヒットテストの結果から地理空間アンカーを作成することもできます。ヒットテストの Pose を使用して、それを GeospatialPose に変換します。これを使用して、前述の 3 種類のアンカーを配置できます。

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

Earth.getGeospatialPose() は、AR ポーズを地理空間ポーズに変換することで、緯度と経度を特定する追加の方法を提供します。

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

Earth.getPose() は、地球で指定された水平位置、高度、東北上座標フレームに対するクォータニオン回転を、GL ワールド座標に対する AR ポーズに変換します。

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

アンカーを作成する方法にはそれぞれトレードオフが伴います。

  • 街並みのジオメトリを使用する場合は、ヒットテストを使用して建物にコンテンツを配置します。
  • WGS84 アンカーよりも、地形アンカーまたは屋上アンカーを使用することをおすすめします。これらのアンカーは、Google マップによって決定された高度値を使用します。

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

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

  • Geospatial Creator を使用すると、実際にその場所に移動しなくても、3D コンテンツで世界を表示して拡張できます。これにより、Unity エディタで Google マップを使用して、没入感のある 3D コンテンツを視覚的に配置できます。コンテンツの緯度、経度、回転、高度は自動的に計算されます。
  • Googleマップを使用
  • Google Earth を使用します。Google マップではなく Google Earth を使用して座標を取得する場合、誤差は最大で数メートルになる可能性があります。
  • 物理的な場所に移動する

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. メニューから [Export as KML file] を選択します。

KLM ファイルでは、プレースマークの緯度、経度、高度が <coordinates> タグでカンマ区切りで報告されます。次に例を示します。

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

<LookAt> タグの緯度と経度は使用しないでください。これは、位置情報ではなくカメラの位置を指定します。

物理的な場所に移動する

場所の高度を計算するには、その場所に実際に足を運んで現地で測定します。

回転クォータニオンを取得する

GeospatialPose.getEastUpSouthQuaternion() は、地理空間ポーズから向きを抽出し、ベクトルをターゲットから東北上(EUS)座標系に変換する回転行列を表すクォータニオンを出力します。X+ は東、Y+ は上、Z+ は南を指します。値は {x, y, z, w} の順序で書き込まれます。

WGS84 アンカー

WGS84 アンカーは、任意の緯度、経度、高度に 3D コンテンツを配置できるアンカーの一種です。現実世界に配置するには、ポーズと向きが必要です。位置は、WGS84 座標系で指定される緯度、経度、高度で構成されます。向きはクォータニオン回転で構成されます。

高度は、基準となる WGS84 楕円体からの高さ(メートル単位)で報告されます。地面は 0 ではないためです。作成されたアンカーごとに、これらの座標をアプリが提供する必要があります。

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

場所の標高を特定する

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

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

アンカーを作成する

緯度、経度、高度、回転クォータニオンを取得したら、Earth.createAnchor() を使用して、指定した地理座標にコンテンツを固定します。

Java

if (earth != null && earth.getTrackingState() == TrackingState.TRACKING) {
  Anchor anchor =
    earth.createAnchor(
      /* Location values */
      latitude,
      longitude,
      altitude,
      /* Rotational pose values */
      qx,
      qy,
      qz,
      qw);

  // Attach content to the anchor specified by geodetic location and pose.
}

Kotlin

if (earth.trackingState == TrackingState.TRACKING) {
  val anchor =
    earth.createAnchor(
      /* Location values */
      latitude,
      longitude,
      altitude,
      /* Rotational pose values */
      qx,
      qy,
      qz,
      qw
    )

  // Attach content to the anchor specified by geodetic location and pose.
}

地形アンカー

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

目的の高度を入力するのではなく、地形からの高度を指定します。0 に設定すると、アンカーは地形と同じ高さになります。

飛行機の検出モードを設定する

平面の検出は任意であり、アンカーを使用する必要はありません。水平面のみが使用されます。水平面は、地面上の地形アンカーの動的な配置に役立ちます。

Config.PlaneFindingMode を使用して、アプリで飛行機を検出する方法を選択します。

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

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

アンカーはすぐには使用できず、解決する必要があります。問題が解決すると、[ResolveAnchorOnTerrainFuture] に表示されます。

Java

final ResolveAnchorOnTerrainFuture future =
  earth.resolveAnchorOnTerrainAsync(
    latitude,
    longitude,
    /* altitudeAboveTerrain= */ 0.0f,
    qx,
    qy,
    qz,
    qw,
    (anchor, state) -> {
      if (state == TerrainAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    });

Kotlin

var future =
  earth.resolveAnchorOnTerrainAsync(
    latitude,
    longitude,
    altitudeAboveTerrain,
    qx,
    qy,
    qz,
    qw,
    { anchor, state ->
      if (state == TerrainAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    }
  )

State of the Future を確認する

Future には FutureState が関連付けられます。

説明
FutureState.PENDING オペレーションはまだ保留中です。
FutureState.DONE オペレーションが完了し、結果が利用可能になります。
FutureState.CANCELLED オペレーションがキャンセルされました。

将来の結果の地形アンカーの状態を確認する

Anchor.TerrainAnchorState は非同期オペレーションに属し、最終的な Future 結果の一部です。

Java

switch (terrainAnchorState) {
  case SUCCESS:
    // A resolving task for this Terrain anchor has finished successfully.
    break;
  case ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the Geospatial API.
    break;
  case ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.TerrainAnchorState#error_not_authorized
    // for troubleshooting steps.
    break;
  case ERROR_INTERNAL:
    // The Terrain anchor could not be resolved due to an internal error.
    break;
  default:
    // not reachable
    break;
}

Kotlin

when (state) {
  TerrainAnchorState.SUCCESS -> {
    // A resolving task for this Terrain anchor has finished successfully.
  }
  TerrainAnchorState.ERROR_UNSUPPORTED_LOCATION -> {
    // The requested anchor is in a location that isn't supported by the Geospatial API.
  }
  TerrainAnchorState.ERROR_NOT_AUTHORIZED -> {
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.TerrainAnchorState#error_not_authorized
    // for troubleshooting steps.
  }
  TerrainAnchorState.ERROR_INTERNAL -> {
    // The Terrain anchor could not be resolved due to an internal error.
  }
  else -> {
    // Default.
  }
}

屋上アンカー

屋上アンカーのヘルプセンター記事

屋上アンカーはアンカーの一種で、上記の地形アンカーとよく似ています。違いは、地面からの標高ではなく、屋上からの標高を指定することです。

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

アンカーはすぐには使用できず、解決する必要があります。

屋上アンカーを作成して配置するには、Earth.resolveAnchorOnRooftopAsync() を呼び出します。地形アンカーと同様に、Future の FutureState にもアクセスできます。その後、[将来の結果] を確認して Anchor.RooftopAnchorState にアクセスできます。

Java

final ResolveAnchorOnRooftopFuture future =
  earth.resolveAnchorOnRooftopAsync(
    latitude,
    longitude,
    /* altitudeAboveRooftop= */ 0.0f,
    qx,
    qy,
    qz,
    qw,
    (anchor, state) -> {
      if (state == RooftopAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    });

Kotlin

var future =
  earth.resolveAnchorOnRooftopAsync(
    latitude,
    longitude,
    altitudeAboveRooftop,
    qx,
    qy,
    qz,
    qw,
    { anchor, state ->
      if (state == RooftopAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    }
  )

State of the Future を確認する

将来の値には FutureState が関連付けられます(上記のを参照)。

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

Anchor.RooftopAnchorState は非同期オペレーションに属し、最終的な Future 結果の一部です。

Java

switch (rooftopAnchorState) {
  case SUCCESS:
    // A resolving task for this Rooftop anchor has finished successfully.
    break;
  case ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the Geospatial API.
    break;
  case ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API.
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.RooftopAnchorState#error_not_authorized
    // for troubleshooting steps.
    break;
  case ERROR_INTERNAL:
    // The Rooftop anchor could not be resolved due to an internal error.
    break;
  default:
    // not reachable
    break;
}

Kotlin

when (state) {
  RooftopAnchorState.SUCCESS -> {
    // A resolving task for this Rooftop anchor has finished successfully.
  }
  RooftopAnchorState.ERROR_UNSUPPORTED_LOCATION -> {
    // The requested anchor is in a location that isn't supported by the Geospatial API.
  }
  RooftopAnchorState.ERROR_NOT_AUTHORIZED -> {
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.RooftopAnchorState#error_not_authorized
    // for troubleshooting steps.
  }
  RooftopAnchorState.ERROR_INTERNAL -> {
    // The Rooftop anchor could not be resolved due to an internal error.
  }
  else -> {
    // Default.
  }
}

次のステップ