Maps SDK for Unity Key Concepts

The following sections contain descriptions of the concepts that are key to understanding and using the Maps SDK for Unity.

The MapsService class and component

The MapsService class serves as the entry point for interacting with the Maps SDK for Unity. It encapsulates the ApiKey, and it exposes the GameObjectManager, and the LoadMap function, as well as Events from the GameObject Creation pipeline.

To use the Maps SDK for Unity in your Unity project, you add the Map Service script component to an empty GameObject in your scene. The Map Service automatically adds generated map feature GameObjects as children of this anchor GameObject. With the Maps Service (Script) attached to your base GameObject, you can access its public attributes in the Unity Inspector—as shown here.

Maps Service (Script)

Geographic features as Unity GameObjects

The Maps SDK for Unity renders geographic features (such as building, roads, and water) from the Google Maps database, as Unity GameObjects in games. At runtime, they're created as children of the GameObject that the MapsService component is attached to, and they have names of the form {MapFeatureType} ({PlaceID}).

SDK Game Objects

GameObject creation

During gameplay, the SDK pulls-down geo data from the Google Maps database—as semantic vector tiles (via the Semantic Tile API). It decodes this data on-the-fly, transforming it into Unity GameObjects. This approach allows you to access map feature data (both the metadata, and the geometry data) at the earliest opportunity, so you can customize the GameObjects before they reach the end of the pipeline.

The first thing that the Maps SDK for Unity does when it receives vector data, is construct a MapFeature object out of it.

At an intermediate stage in the pipeline, MapFeature objects are specialized. That is, they become specific types (for example, a Google.Maps.Feature.ModeledStructure). These specialized MapFeature objects contain the MapFeatureShape geometry details ( ModeledVolume in the case of a ModeledStructure). These details include both MapFeature-specific data (such as vertices and triangles), and shared interfaces for accessing common fields (such as bounding boxes).

Geometry data is converted into a Unity Mesh, and is added to the spawned GameObject via MeshFilter, and then is displayed with a MeshRenderer.

Accessing the pipeline

MapFeatures are exposed to you through events that are triggered during various stages of the pipeline. These include WillCreate events—which are fired just before the GameObject is created, allowing you to specify the styling options, or even cancel creation; and DidCreate events—fired just after the GameObject is created, allowing you to make additions or changes to the finished mesh.

As an example, you could examine ExtrudedStructures after their WillCreateExtrudedStructureEvent fires, and hide all buildings shorter than 20 meters (or you could skip creating them altogether).

Types of events

The Google.Maps.Event namespace contains an event class for each type of geographic features.

Each of these event types has a WillCreate and a DidCreate public member event object that you can subscribe to, as demonstrated in the following code example.

dynamicMapsService.MapsService.Events.ExtrudedStructureEvents.DidCreate.AddListener(args => {

    // Apply nine-sliced walls and roof materials to this building.
    buildingTexturer.AssignNineSlicedMaterials(args.GameObject);

    // Add a border around the building base using the Building Border Builder class,
    // coloring it using the given border Material.
    Extruder.AddBuildingBorder(args.GameObject, args.MapFeature.Shape, BuildingAndRoadBorder);
});

WillCreate events

WillCreate events are fired immediately after a MapFeature is created, but before the final GameObject is generated from it. WillCreate events allow you to suppress or customize the GameObjects created from a MapFeature. WillCreate event arguments have the following form:

using System.ComponentModel;
using Google.Maps.Decoded;
using UnityEngine;

namespace Google.Maps {
  public class WillCreateGameObjectEventArgs<T, U>
      : CancelEventArgs where T : IMapObject, U : IGameObjectStyle {

    public readonly T MapObject;
    public U Style;
    public GameObject Prefab;

    Public WillCreateGameObjectEventArgs(T mapObject, U defaultStyle, GameObject prefab) {
      MapObject = mapObject;
      Style = defaultStyle;
      Prefab = prefab;
    }
  }
}
  • Setting Cancel (inherited from CancelEventArgs) to true suppresses the creation of the GameObject.
  • MapObject is readonly.
  • Setting Style allows you to customize the appearance of the created GameObject.
  • Setting Prefab replaces the GameObject that would have been generated, with the prefab.

DidCreate events

DidCreate events are fired after a GameObject is generated, after it has been added to the scene. They notify you when the creation of the GameObject was successful, allowing you to perform further processing. DidCreate event arguments have the following form:

using System.ComponentModel;
using Google.Maps.Decoded;
using UnityEngine;

namespace Google.Maps {
  public class DidCreateGameObjectEventArgs<T, U>
      : EventArgs where T : IMapObject, U : IGameObjectStyle {

    public readonly T MapObject;
    public GameObject CreatedObject;

    Public DidCreateGameObjectEventArgs(T mapObject, GameObject createdObject) {
      MapObject = mapObject;
      CreatedObject = createdObject;
    }
  }
}
  • MapObject is readonly - so mutating it will not cause any change to the scene.
  • Altering CreatedObject will alter the GameObject added to the scene.

Buildings

There are two types of buildings: extruded buildings, and modeled structures.

Extruded buildings

Extruded buildings are generated from an outline (that is, a 2D footprint) and a height. The SDK represents most buildings in this manner, and it generates them in the following three ways:

  • Using real-world height data (where this information is available). This is the default behavior.

  • By providing a fixed height for all building, disregarding their real-world height.

  • By providing a backup height for all buildings that don't have a real-world height (by default, this value is set to 10 meters).

Combining these three methods allows the Maps SDK for Unity to create cityscapes with realistic variance reflecting the real world, or with a constant building height, or a mixture of the two.

Modeled structures

Modeled structures are generated using the standard 3D modeling approach of tessellated triangles. This approach is typically used for landmark buildings, such as the Statue of Liberty.

The Modeled Statue of Liberty

Applying materials

In Unity, the rendering process uses shaders, materials, and textures, to add realism to GameObjects. Shaders define how textures, colors, and lighting, are applied to displayed geometry, with the specific textures, colors and other settings used stored as a material. You use materials to define how a surface is rendered—by including references to the textures it uses, to tiling information, and to color.

Shaders are small scripts that contain the logic for calculating the color of each pixel—based on the lighting input, and on the material configuration. The Maps SDK for Unity comes with a standard shader for modeled structures, and another for basemap features, but it also supports advanced material application. Coordinates for UV mapping are calculated for map feature GameObjects in such a way that any basic material can be applied, and it will look reasonable without modification.

For more advanced material effects, the Maps SDK for Unity provides additional data per-vertex via extra UV channels, as well as a number of convenience functions for cg shaders via the GoogleMapsShaderLib library. This allows things like Nine-Sliced building textures—cutting-up a texture into the roof, ground, wall-corners, and tiled walls, for a building.

For more information, see Creating and Using Materials in the Unity User Manual.

UV channels

The UV channels for each MapFeature type contain data of the following form:

ExtrudedStructure

Walls

Each wall on an ExtrudedStructure is constructed as a quad of the following form:

Walls

UV coordinates for walls are calculated per quad. Vertices are not shared between quads—to allow for hard normals between walls (that is, letting the corners of walls appear as hard angles, rather than soft rounded edges).

Channel 0: (x, y, width, height)
x and y are the coordinates relative to the bottom left corner of this quad (square section) of the wall, whereas width and height are the width and height of this quad of the wall. This applies to every quad making up the wall.
Roof

Roof textures have the option of being either axis-aligned, or aligned to the direction of the ExtrudedStructure. You set this via the ExtrudedStructureStyle object.

Channel 0: (x, y, width, height)
x and y are the coordinates of each vertex, relative to the bottom-left corner of the roof (specifically, the corner of the minimum-cover axis-aligned bounding box for the roof). width and height define the size of the roof's bounding box.

Region

Channel 0: (x, y, width, height)
x and y are the coordinates of each vertex relative to the bottom-left corner of the axis-aligned bounding box for the region. width and height define the size of the bounding box.

Segment

Channel 0: (x, y, width, length)
x and y are the coordinates of each vertex, calculated as if the segment were completely straight—to allow texturing to bend around corners. width and length define the dimensions of the segment.

ModeledStructure

Channel 0:
Each coordinate is set to (0, 0, 0, 0) because there is currently no texture-coordinate implementation.

GoogleMapsShaderLib

The Maps SDK for Unity includes a shader library called GoogleMapsShaderLib, to help you build shaders that work well with MapFeature GameObjects. The library is implemented in the file GoogleMapsShaderLib.cginc. You can use the library by including the following #include directive within the CGPROGRAM flags section in your shader script.

CGPROGRAM
// ...
#include "/Assets/GoogleMaps/Materials/GoogleMapsShaderLib.cginc"
// ...
ENDCG

The shader library is bundled inside the GoogleMaps.unitypackage. After you import the package, you can find GoogleMapsShaderLib.cginc inside the project folder /Assets/GoogleMaps/Materials/.

Nine-slicing

GoogleMapsShaderLib includes a convenience function that you can use in fragment shaders to provide nine-slicing of textures. Nine-slicing is a technique for covering surfaces with a texture, where the texture is divided into nine portions using a series of bounds. Areas between the bounds are tiled, and areas outside the bounds remain fixed—as illustrated here:

Nine-slicing

For example, when applying a nine-sliced texture to a building's wall, the top of the texture is applied to the top of the wall (just under the roof), the bottom of the texture is applied to the bottom of the wall (connected to the ground), the sides of the texture are applied to the edges of the wall, and the area in the middle of the texture is tiled evenly across the wall.

On roads (for another example), nine-slicing allows you to have a sidewalk of fixed width, but with a variable number of lanes, depending on the width of the road.

You can use nine-slicing by including GoogleMapsShaderLib.cginc in your shader, and then calling the nineSlice function. Sample shaders and materials are included in the GoogleMaps.unitypackage to demonstrate how you can use the nineSlice function to create a realistic skyscraper of variable size—without stretching or tearing.

Example Materials location
/Assets/GoogleMaps/Examples/04_Advanced/MoreStyling/Materials/NineSlicing
Example Shader location
/Assets/GoogleMaps/Examples/04_Advanced/MoreStyling/Materials/NineSlicing/BuildingWall.shader

You can use nine-slicing on any MapFeature, except for ModeledStructures, which don't currently have any texturing coordinates.

The coordinate system

The Maps SDK for Unity coordinate system uses the Web Mercator Projection to convert between spherical WGS 84 latitude-longitude and cartesian Unity Worldspace (Vector3).

Vector3 values are relative to a floating origin, which is typically set to the user's starting location. As a result, you should not persist Vector3 values outside of a session (that is, on your server, or on the user's device). We recommend that you specify physical world locations using latitude-longitude pairs.

A floating origin is used to avoid floating-point stability issues. Unity's Vector3 class uses single-precision floating-point numbers, and the density of representable floating-point numbers decreases as their magnitude increases (meaning larger floating-point numbers become less accurate). You can update the floating origin whenever users move far enough away from the origin that this becomes an issue. You can set this to a relatively small value (for example, 100 or 200 meters), or larger (greater than 1 km) depending on how often you want to update things.

Unity Worldspace is scaled to 1:1 (meters), based on the initial origin's latitude. In the Mercator Projection, scale varies slightly by latitude, so the Unity Wordspace scale diverges marginally from 1:1 as users move North and South; however, users are not expected to move far (or fast) enough for this to be noticeable.

The Maps SDK for Unity contains conversion functions for converting between Google.Maps.LatLng and Unity Worldspace (Vector3)—that take into account floating origin and scale.

Load errors

Errors that occur while loading map data from the network can be handled with the MapLoadErrorEvent event. The Maps SDK for Unity handles most types of errors itself if you don't add an event handler. However, there is an error that requires that your app take some action. This is specified by MapLoadErrorArgs.DetailedErrorCode and is described below.

UnsupportedClientVersion

This version of the Maps SDK for Unity is no longer supported, possibly in combination with the current API Key. Typically your app should prompt the user to update to a newer version of your app.

This error usually means that the Maps SDK for Unity version is too old. In rare cases, we might use this if we discover a critical problem with a version of the Maps SDK for Unity or with an API Key. We will make every effort to communicate this and ensure that this doesn't happen until there is a working version of the app available to update to.

It's best practice to ensure your app has suitable upgrade path in the event this error occurs, allowing your users to migrate to a newer version of your app with a supported SDK version. For more information, see the Client Kill Switch documentation.

Known issues

Base map features are rendered back-to-front without z-testing because all features of this type are rendered in the same plane. You must set z-testing to ZTest Always on any replacement materials that you apply to base map features to ensure that they are rendered correctly.

Google has included a sample shader that addresses these issues—in the GoogleMaps.unitypackage. It's called "BaseMapTextured.shader, and it's located in the /Assets/GoogleMaps/Materials/ folder. To use it on a material, select Google > Maps > Shaders > BaseMap Textured from the shader drop-down in the material inspector.

When styling a Feature.Region or a Feature.AreaWater object, you can apply a fill using either a material, a custom color, or an automatically generated color chosen via the FillModeType enum within the styling object. Auto colors are generated based on the value of the Region's usage type.