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

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

地理空間錨點類型

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

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

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

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

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

必要條件

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

放置地理空間錨點

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

根據命中測試建立錨點

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

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

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

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

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

選擇最適合用途的方法

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

  • 使用 街景地形時,請使用命中測試將內容附加至建築物。
  • 請優先使用地形或屋頂錨點,而非 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. 從選單中選擇「Export as KML file」。

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 規格取得海拔高度。您必須將 Maps API EGM96 海拔高度轉換為 WGS84,以便與 GARGeospatialTransform 高度進行比較。請參閱同時提供指令列和 HTML 介面的 GeoidEval。Maps API 會根據預設的 WGS84 規格回報經緯度。
  • 您可以透過 Google 地球取得位置的緯度、經度和高度。這會產生最多數公尺的誤差範圍。使用 KML 檔案中 <coordinates> 標記而非 <LookAt> 標記的經緯度和高度。
  • 如果附近有現有的錨點,而且你並未處於陡峭的斜坡上,則可以使用相機的 GARGeospatialTransform 提供的高度資訊,而不需要使用其他來源,例如 Maps API。

建立錨點

取得經緯度、高度和旋轉四元數後,請使用 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;
}

屋頂錨點

屋頂固定點 Hero

屋頂固定點是一種固定點,與上述地形固定點非常相似。差別在於你要提供屋頂以上的高度,而不是地形以上的高度。

使用新的 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;
}

後續步驟