Terrain anchors

Stay organized with collections Save and categorize content based on your preferences.

A Terrain anchor is a type of Geospatial anchor that allows you to place AR objects using only latitude and longitude, leveraging information from Google Maps to find the precise altitude above ground.

Prerequisites

Make sure that you enable the Geospatial API before proceeding.

Set the plane-finding mode

The chosen plane detection mode controls the stability of placed Terrain anchors. Use Config.PlaneFindingMode to select how your app detects planes.

Mode Behavior Use case
HORIZONTAL_AND_VERTICAL Default mode. ARCore detects horizontal and vertical surfaces, such as floors and walls, as planes and accurately renders AR objects placed on them. Your app needs to recognize both horizontal and vertical surfaces.
HORIZONTAL ARCore detects horizontal surfaces only. Your app needs to recognize horizontal surfaces only. Use to save computational power.
VERTICAL ARCore detects vertical surfaces only. Your app needs to recognize vertical surfaces only. Use to save computational power.
DISABLED Plane detection is disabled. May cause the vertical positioning of the Terrain anchor to be less accurate. Your app does not need accurate plane detection.

Create a Terrain anchor

To create and place a Terrain anchor, call Earth.resolveAnchorOnTerrain().

Java

if (earth.getTrackingState() == TrackingState.TRACKING) {
  terrainAnchor =
      earth.resolveAnchorOnTerrain(
          /* Locational values */
          latitude,
          longitude,
          altitudeAboveTerrain,
          /* Rotational pose values */
          qx,
          qy,
          qz,
          qw);
  // This anchor can't be used immediately; check its TrackingState
  // and TerrainAnchorState before rendering content on this anchor.
}

Kotlin

if (earth.trackingState == TrackingState.TRACKING) {
  terrainAnchor =
    earth.resolveAnchorOnTerrain(
      /* Locational values */
      latitude,
      longitude,
      altitudeAboveTerrain,
      /* Rotational pose values */
      qx,
      qy,
      qz,
      qw
    )
  // This anchor can't be used immediately; check its TrackingState
  // and TerrainAnchorState before rendering content on this anchor.
}

Creating anchors within 0.1 degrees of the North or South Poles (90 degrees or -90 degrees) is not supported. If such an anchor is specified, Earth.resolveAnchorOnTerrain() will throw an IllegalArgumentException and the anchor will fail to be created.

Check the Terrain anchor state

Once created, a Terrain anchor will have a state attached to it.

State Description
TASK_IN_PROGRESS The Terrain anchor has just been created, and ARCore is communicating with the ARCore API on Google Cloud to determine the anchor's exact pose.
SUCCESS The Terrain anchor has been successfully hosted and is now trackable. You can now use it to attach content to your AR experience.
Error state An error has occurred during the resolving process.

Check Anchor.TerrainAnchorState to check the current state of the Terrain anchor:

Java

switch (terrainAnchor.getTerrainAnchorState()) {
  case SUCCESS:
    if (terrainAnchor.getTrackingState() == TrackingState.TRACKING) {
      renderAnchoredContent(terrainAnchor);
    }
    break;
  case TASK_IN_PROGRESS:
    // ARCore is contacting the ARCore API to resolve the Terrain anchor's pose.
    // Display some waiting UI.
    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;
  case NONE:
    // This Anchor isn't a Terrain anchor or it became invalid because the Geospatial Mode was
    // disabled.
    break;
}

Kotlin

when (terrainAnchor.terrainAnchorState) {
  TerrainAnchorState.SUCCESS ->
    if (terrainAnchor.trackingState == TrackingState.TRACKING)
      renderAnchoredContent(terrainAnchor)
  TerrainAnchorState.TASK_IN_PROGRESS -> {
    // ARCore is contacting the ARCore API to resolve the Terrain anchor's pose.
    // Display some waiting UI.
  }
  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.
  }
  TerrainAnchorState.NONE -> {
    // This Anchor isn't a Terrain anchor or it became invalid because the Geospatial Mode was
    // disabled.
  }
}

What's next