地理空間アンカーを使用して iOS で実際のコンテンツを配置する

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

地理空間アンカーの種類

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

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

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

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

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

前提条件

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

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

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

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

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

AR 変換から地理空間変換を取得する

GARSession.geospatialTransformFromTransform:error: を使用すると、AR 変換を地理空間変換に変換して緯度と経度を判別できます。

地理空間変換から AR 変換を取得する

GARSession.transformFromGeospatialCoordinate:altitude:eastUpSouthQTarget:error: は、東が上、南が下、北が左の座標フレームに対する地球で指定された水平位置、高度、クォータニオン回転を、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. メニューから [KML ファイルとしてエクスポート] を選択します。

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

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

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

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

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

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

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

WGS84 アンカー

WGS84 アンカーは、任意の緯度、経度、高度に 3D コンテンツを配置できるアンカーの一種です。現実世界に配置するには、変換と向きを使用します。位置は緯度、経度、高度で構成され、WGS84 座標系で指定されます。向きは四元数回転で構成されます。

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

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

場所の標高を特定する

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

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

アンカーを作成する

緯度、経度、高度、回転クォータニオンを取得したら、createAnchorWithCoordinate:altitude:eastUpSouthQAnchor:error: を使用して、指定した地理座標にコンテンツを固定します。

  NSError *error = nil;
  GARAnchor *anchor = [self.garSession createAnchorWithCoordinate:coordinate
                                                         altitude:altitude
                                               eastUpSouthQAnchor:eastUpSouthQAnchor
                                                            error:&error];

地形用アンカー

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

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

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

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

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

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

地形アンカーを作成して配置するには、GARSession.createAnchorWithCoordinate:altitudeAboveTerrain:eastUpSouthQAnchor:completionHandler:error: を呼び出します。

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

GARCreateAnchorOnTerrainFuture *future = [self.garSession createAnchorWithCoordinate:coordinate
                                                                altitudeAboveTerrain:altitude
                                                                  eastUpSouthQAnchor:eastUpSouthQTarget
                                                                   completionHandler:^(GARAnchor *anchor, GARTerrainAnchorState state) {
                                                                     // handle completion
                                                                   }
                                                                               error:&error];

State of the Future を確認する

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

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

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

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

switch (future.resultTerrainAnchorState) {
  case GARTerrainAnchorStateSuccess:
    // Terrain anchor finished resolving.
    break;
  case GARTerrainAnchorStateErrorUnsupportedLocation:
    // The requested anchor is in a location that isn't supported by the Geospatial API.
    break;
  case GARTerrainAnchorStateErrorNotAuthorized:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/ios/group/GARTerrainAnchorState#garterrainanchorstateerrornotauthorized
    // for troubleshooting steps.
    break;
  case GARTerrainAnchorStateErrorInternal:
    // The Terrain anchor could not be resolved due to an internal error.
    break;
  default:
    break;
}

屋上アンカー

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

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

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

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

屋上アンカーを作成して配置するには、GARSession.createAnchorWithCoordinate:altitudeAboveRooftop:eastUpSouthQAnchor:completionHandler:error: を呼び出します。Terrain アンカーと同様に、Future の GARFutureState にもアクセスできます。その後、Future の結果を確認して GARRooftopAnchorState にアクセスできます。

GARCreateAnchorOnRooftopFuture *future = [self.garSession createAnchorWithCoordinate:coordinate
                                                                altitudeAboveRooftop:altitude
                                                                  eastUpSouthQAnchor:eastUpSouthQTarget
                                                                   completionHandler:^(GARAnchor *anchor, GARRooftopAnchorState state) {
                                                                     // handle completion
                                                                   }
                                                                               error:&error];

将来の状況をチェック

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

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

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

switch (future.resultRooftopAnchorState) {
  case GARRooftopAnchorStateSuccess:
    // Rooftop anchor finished resolving.
    break;
  case GARRooftopAnchorStateErrorUnsupportedLocation:
    // The requested anchor is in a location that isn't supported by the Geospatial API.
    break;
  case GARRooftopAnchorStateErrorNotAuthorized:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/ios/group/GARRooftopAnchorState#garrooftopanchorstateerrornotauthorized
    // for troubleshooting steps.
    break;
  case GARRooftopAnchorStateErrorInternal:
    // The Rooftop anchor could not be resolved due to an internal error.
    break;
  default:
    break;
}

次のステップ