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.
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}).
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
MapFeature
s 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.
- Segments Events
- Regions Events
- Line Water Events
- Area Water Events
- Extruded Structures Events
- Modeled Structures Events
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 fromCancelEventArgs
) 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.
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:
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:
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.