使用地理空間錨點在 iOS 上定位實際內容

地理空間錨點是一種錨點,可讓您將 3D 內容放置在現實世界中。

地理空間錨點類型

地理空間錨點分為三種類型,每種類型處理高度的方式各不相同:

  1. WGS84 錨點
    WGS84 錨點可讓您在任何指定的緯度、經度和高度上放置 3D 內容。

  2. 地形錨點
    地形錨點可讓您只使用緯度和經度來放置內容,並以該位置的地形高度為依據。高度會根據 VPS 所知的地上或樓層來決定。

  3. 屋頂錨點
    屋頂錨點可讓您只使用經緯度和相對於該位置建築物屋頂的高度來放置內容。高度會根據 街景幾何圖形所知的建築物頂端來決定。未放置在建築物上時,預設為地形高度。

WGS84 地形 屋頂
水平位置 緯度, 經度 緯度, 經度 緯度, 經度
垂直位置 相對於 WGS84 高度 相對於 Google 地圖所判定的地形高度 相對於 Google 地圖所判定的屋頂樓層
是否需要由伺服器解析?

必要條件

請務必先啟用 Geospatial API,再繼續操作。

地點地理空間錨點

每個錨點類型都有專屬的 API 可用來建立錨點,詳情請參閱「地理空間錨點類型」。

根據命中測試建立錨點

您也可以使用命中測試結果建立地理空間錨點。使用命中測試中的 Transform,並將其轉換為 GARGeospatialTransform。可用來放置上述任一錨點類型。

從 AR 轉換取得地理空間轉換

GARSession.geospatialTransformFromTransform:error: 可將 AR 轉換轉換為地理空間轉換,提供另一種判斷經緯度的方法。

從地理空間轉換取得 AR 轉換

GARSession.transformFromGeospatialCoordinate:altitude:eastUpSouthQTarget:error: 會將地球指定的水平位置、高度和四元數旋轉 (相對於東-上-南座標架構) 轉換為 AR 轉換 (相對於 GL 世界座標)。

選擇最適合用途的方法

每種建立錨點的方法都會帶來相關的取捨,請留意:

  • 使用 街景地形時,請使用命中測試將內容附加至建築物。
  • 優先使用 Terrain 或 Rooftop 錨點,而不是 WGS84 錨點,因為它們使用 Google 地圖判定的海拔高度值。

判斷位置的經緯度

計算地點的經緯度有三種方法:

  • 使用地理空間創作者,即可透過 3D 內容查看及擴增世界,無須實際前往該地。這可讓您在 Unity 編輯器中使用 Google 地圖,以視覺化方式放置 3D 沉浸式內容。系統會自動計算內容的緯度、經度、旋轉角度和高度。
  • 使用 Google 地圖
  • 使用 Google 地球。請注意,使用 Google 地球取得這些座標 (而非 Google 地圖) 時,誤差範圍最多可達數公尺。
  • 前往實際位置

使用 Google 地圖

如要使用 Google 地圖取得某個地點的經緯度,請按照下列步驟操作:

  1. 在電腦上前往 Google 地圖

  2. 依序前往「圖層」 >「更多」

  3. 將「地圖類型」變更為「衛星」,然後取消勾選畫面左下角的「地球儀檢視」核取方塊。

    這會強制使用 2D 視角,並消除可能因 3D 角度檢視畫面而產生的錯誤。

  4. 在地圖上按一下要複製的位置,然後選取經度/緯度,將其複製到剪貼簿。

使用 Google 地球

您可以透過在使用者介面中按一下某個位置,然後讀取地標詳細資料中的資料,計算 Google 地球中某個位置的緯度和經度。

如要使用 Google 地球取得某個地點的經緯度,請按照下列步驟操作:

  1. 在電腦上前往 Google 地球

  2. 前往漢堡選單 ,然後選取「地圖樣式」

  3. 關閉「3D 建築物」切換鈕。

  4. 關閉「3D 建築物」開關後,按一下圖釘圖示 ,即可在所選位置新增地標。

  5. 指定要包含地標的專案,然後按一下「儲存」

  6. 在地標的「Title」欄位中,輸入地標名稱。

  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 Anchor 是一種錨點,可讓您在任何指定的經緯度及高度位置放置 3D 內容。它會依據轉換和方向,放置在真實世界中。位置包含緯度、經度和海拔高度,這些項目皆以 WGS84 座標系統指定。方向由四元數旋轉組成。

海拔高度值於參考 WGS84 橢圓球體上方以公尺為單位,因此地面等級「不是」0。您的應用程式負責為每個建立的錨點提供這些座標。

在現實世界中放置 WGS84 錨點

判斷位置的海拔高度

您可以透過下列幾種方式,判斷地點的高度以便放置錨點:

  • 如果錨點位置位於使用者附近,您可以使用與使用者裝置高度相近的高度。
  • 取得經緯度後,請使用 Elevation API 取得根據 EGM96 規格計算的海拔高度。您必須將 Maps API EGM96 海拔高度轉換為 WGS84,以便與 GARGeospatialTransform 高度進行比較。請參閱含有指令列和 HTML 介面的 GeoidEval。Maps API 會根據預設的 WGS84 規格回報經緯度。
  • 您可以透過 Google 地球取得位置的緯度、經度和高度。這會產生最多數公尺的誤差範圍。使用 KML 檔案中 <coordinates> 標記而非 <LookAt> 標記的經緯度和高度。
  • 如果現有錨點在靠近附近不是陡坡,即使不使用其他來源 (例如 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];

查看未來狀況

Future 會具有相關的 GARFutureState

說明
GARFutureStatePending 這項作業仍在處理中。
GARFutureStateDone 作業已完成,且已取得結果。
GARFutureStateCancelled 作業已取消。

檢查 Future 結果的 Terrain 錨點狀態

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 建立 Rooftop 錨點

錨點不會立即就緒,需要解決。

如要建立並放置屋頂定位基準,請呼叫 GARSession.createAnchorWithCoordinate:altitudeAboveRooftop:eastUpSouthQAnchor:completionHandler:error:。與地形錨點類似,您也可以存取未來的 GARFutureState。接著,您可以查看 Future 結果,存取 GARRooftopAnchorState

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

查看未來狀態

Future 會有相關聯的 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;
}

後續步驟