Geospatial developer guide for Unity (AR Foundation) targeting Android

This guide to developing with the ARCore Geospatial API shows you how to get a precise location, and how to place anchors at a precise location.

See the Introduction to the Geospatial API for more information about the Geospatial API.

If you're new to developing with ARCore, see Getting started for information about software and hardware requirements, prerequisities and other information specific to the platforms you are using.

To use the ARCore Geospatial API, your project must support AR Foundation and the ARCore Extensions for AR Foundation.

Set up a Google Cloud Project

To use the Visual Positioning System (VPS), your app needs to be associated with a Google Cloud Project that is enabled for the ARCore API.

You must enable the ARCore API in your Google Cloud Project. If you need to create the project, do the following:

  1. Visit Create a project in Google Cloud Platform.

  2. Enter an appropriate Project name, and choose a location for it.

  3. Click Create.

  4. In the sidebar, select APIs & Services, then Library.

  5. Search for the ARCore API, select it, and click Enable.

Set up authorization

To make Geospatial API calls to the VPS, your app needs authorization. Keyless authorization is preferred, but API key authorization is also supported.

The default authentication strategy for new Unity projects built with ARCore SDK 1.24.0 or later is DoNotUse. This is to prevent apps from being built with unnecessary libraries.

Keyless authorization

If you previously used an API key and no longer need it, delete it in the Google Cloud Platform Console and remove it from your app.

Note that you need to register separately for all of the different combinations of package name and signing key that you use: debug, release, etc.

Follow these steps to use keyless authorization your project:

  1. In Unity, go to Edit > Project Settings > XR > ARCore Extensions.

  2. In the Android Authentiation Strategy drop-down, select Keyless.

  3. Under Optional Features, check the boxes for any of the APIs listed here that you are using in your project.

  4. Generate the SHA-1 fingerprint signing key.

    1. From the Edit menu, select Project Settings > Player > Publishing Settings.

    2. Click the Keystore Manager and create a new key.

    3. Copy the SHA-1 fingerprint signing key (to be pasted in a later step).

  5. Create the OAuth client ID.

    1. In your Google Cloud Project, Create an OAuth client ID.

    2. In the SHA-1 fingerprint field, paste the SHA-1 fingerprint for the pertinent variant (from the previous step).

    3. Click CREATE to create the OAuth client ID.

API key authorization

Follow these steps to obtain and add an API key to your project:

  1. Get the key from Google Cloud Platform, as described in the Google Cloud Platform Console Help Center.

  2. In Unity, go to Edit > Project Settings > XR > ARCore Extensions.

  3. In the Android Authentiation Strategy drop-down, select API Key.

  4. In the Android API Key field, paste the API key you obtained from Google Cloud Platform.

  5. Under Optional Features, check the boxes for any of the APIs listed here that you are using in your project.

Enable the Geospatial API in your project

  1. Ensure that the project Assets folder contains an ARCoreExtensionsConfig scriptable object.

    To create one, in the Assets pane, right-click and select Create > ARCore Extensions > ARCore Extensions Config.

  2. Select the ARCoreExtensionsConfig scriptable object, and, in the Inspector window, for Geospatial Mode select Enabled from the drop-down menu.

  3. Configure the ARCore Extensions game object to use the ARCoreExtensionsConfig configuration:

    1. In Hierarchy pane locate the ARCore Extensions game object you created when you initially set up ARCore Extensions.

    2. Connect the ARCore Extensions Config field to the ARCoreExtensionsConfig scriptable object in your Assets folder.

Set up for privacy

Apps that use the ARCore Geospatial API must present the user with a prompt to acknowledge and allow the use of data from their device. See User privacy requirements for more information.

Location permissions

ARCore Extensions automatically requests the appropriate location permissions when Geospatial mode is enabled in ARCoreExtensions.Update(). If the user does not grant precise location permission, the session fails to resume, and a "permission not granted" error is produced. This is a terminate error, and requires a re-start to trigger the permission request again.

Check device compatibility

Not all devices that support ARCore also support the Geospatial API. To check the user's device for compatibility, call AREarthManager.IsGeospatialModeSupported(). If this returns FeatureSupported.Unsupported do not attempt to configure the session.

Get a precise location

The CameraGeospatialPose describes a specific location, altitude, and compass heading relative to Earth, and is managed with an AREarthManager.

Check the TrackingState

Geospatial values are only valid while TrackingState.EarthTrackingState is TrackingState.Tracking. Otherwise, TrackingState may be Limited or None. Always wrap your Geospatial API calls in a TrackingState control block, as shown below.

var earthTrackingState = EarthManager.EarthTrackingState;
if (earthTrackingState == TrackingState.Tracking)
{
     // Values obtained by the Geospatial API are valid as long as
     // earthTrackingState is TrackingState.Tracking.
     // Use Geospatial APIs in this block.
}

See also, AREarthManager.EarthState for other error states and conditions that may prevail. When TrackingState is Limited or None, AREarthManager.EarthState may describe the cause of this failure.

Obtain camera Geospatial pose

While the TrackingState is Tracking, request the camera's pose relative to Earth:

var earthTrackingState = EarthManager.EarthTrackingState;
if (earthTrackingState == TrackingState.Tracking)
{
  // camera_geospatial_pose contains geodetic location, rotation, and
  // confidences values.
  var cameraGeospatialPose = EarthManager.CameraGeospatialPose;
}

The AREarthManager.CameraGeospatialPose holds a GeospatialPose, which contains the following information:

  • Location, expressed in latitude and longitude. An estimate of the location accuracy is also supplied.
  • Altitude, and an estimate of the altitude's accuracy.
  • Heading, an approximation of the direction the device is facing, and an estimate of the accuracy of the heading.

Adjust for pose accuracy

The accuracy of the pose from the VPS may vary, due to the availability of VPS data for the location, or due to temporal conditions at the location. Your app may have to make adjustments for the accuracy of the pose, as determined by the Geospatial API.

The Geospatial API provides an estimate for the accuracy of the latitude/longitude, altitude, and heading values returned from the VPS. For example, if the heading value returned from GeospatialPose.Heading is 60 degrees, and the value from GeospatialPose.HeadingAccuracy is 10, there is a 68% probability that the VPS heading is within 10 degrees of the observed heading, as illustrated in the diagram on the left.

Heading accuracy

If the value from GeospatialPose.HeadingAccuracy is 15, there is a 68% chance that the true heading is within 15 degrees of 60 degrees, as shown in the diagram on the right. Note that the higher the value returned from GeospatialPose.HeadingAccuracy, the lower the accuracy of the heading value from GeospatialPose.Heading.

Similarly, GeospatialPose.HorizontalAccuracy reports the number of meters within which the true latitude/longitude value has a 68% probability of being within the given distance, and GeospatialPose.VerticalAccuracy reports the number of meters within which the true altitude value has a 68% probability of being within the given distance.

Place a Geospatial anchor

Use ARAnchorManager.AddAnchor from ARAnchorManagerExtensions to create an ARGeospatialAnchor to anchor content to geographical coordinates that you specify.

When placing an anchor at the specified location and orientation relative to the Earth, latitude and longitude are defined by the WGS84 specification, and the altitude value is defined by the elevation above the WGS84 ellipsoid in meters. An identity rotation has the anchor oriented such that X+ points to the east, Y+ points up, away from the center of the earth, and Z+ points to the south.

To create a Pose.rotation quaternion that has the +Z axis pointing in the same direction as the heading obtained from GeospatialPose, use the following formula.

Quaternion quaternion =
                Quaternion.AngleAxis(180f - (float)pose.Heading, Vector3.up);

Use AnchorManager.AddAnchor (the ARCore extension) to create an ARGeospatialAnchor to anchor content to geographical coordinates that you specify.

if (earthTrackingState == TrackingState.Tracking)
{
  var anchor =
      AnchorManager.AddAnchor(
          latitude,
          longitude,
          altitude,
          quaternion);
  var anchoredAsset = Instantiate(GeospatialAssetPrefab, anchor.transform);
}

Calculate the altitude

Getting the altitude for placing an anchor is a bit tricky. You have to compare the altitude at the device's location against the altitude from the Geospatial API. There are two ways to determine the altitude:

  • If the anchor's location is near the user, consider using an altitude that's similar to the device's altitude.
  • Otherwise, consider getting the altitude value from the elevation in Google Maps.

Use the altitude from the camera's GeospatialPose

It may suffice to simply use the altitude you get from the AREarthManager.CameraGeospatialPose without cross-checking against data from another source such as the Maps API. See Obtain camera Geospatial pose, above.

If you can obtain the pose at the location in advance, by making your own local observation, you can use that data to cross-check the GeospatialPose obtained by your app for the user.

Get the elevation from Google Maps

A GeospatialPose reports altitude in meters above the WGS84 ellipsoid. Your app needs to compare the value from GeospatialPose.Altitude against the altitude at the device's location to determine an accurate altitude for the anchor.

The Google Maps API can get the elevation, but the Maps API elevation is based on the EGM96 specification. Note that the Maps API reports latitude and longitude according to the WGS84 specification, but the elevation is based on EGM96. You must convert the Maps API EGM96 elevation to WGS84 for comparison against the GeospatialPose altitude. See the GeoidEval conversion tool that has both a command line and an HTML interface.

API usage quota

The ARCore SDK limits API requests to the ARCore service to the following limits for each project that uses the ARCore SDK:

  • 1,000 sessions started per minute, or
  • 100,000 requests per minute

API requests in excess of these limits may result

in an EarthState.ErrorResourcesExhausted error and an unfulfilled request.