Features and Metadata Technical Reference
In Unreal Engine, metadata about the features in a 3D Tileset can use one of several different formats. A model may use Feature IDs and Feature Tables to store metadata properties (As Feature ID Attributes or Feature ID Textures), or it can use Feature Textures.
For a brief follow-along tutorial covering some of the concepts below, visit the Visualize Mesh Features and Metadata tutorial.
This type of metadata is stored in Feature Tables with typed Property columns. A row of Properties from the Feature Table can be referenced with a Feature ID index. There are two ways Feature IDs can be associated with a tile’s geometry, Feature ID Attributes and Feature ID Textures. The relevant terms are defined and shown through examples below:
// Property example 1:
string buildingName;
// Property example 2:
int numberOfFloors;
// Class example:
Building {
string buildingName;
int numberOfFloors;
bool passesFireCode;
bool openToPublic;
}
// Object example:
Building cesiumBuilding {
“Cesium Building”,
5,
true,
false
}
Feature ID | buildingName | numberOfFloors | passesFireCode | openToPublic |
---|---|---|---|---|
0 | “Cesium Building” | 5 | true | false |
1 | “Abandoned Warehouse” | 1 | false | false |
2 | “Bodega” | 1 | true | true |
Feature ID Attribute
In this form, each vertex in a tile has a corresponding feature ID. It can be assumed that the three vertices in each triangle have the same feature ID. This is taken to mean that all the metadata in the feature table row indexed by the feature ID is associated with this vertex (and its triangle).
A common use of feature ID attributes is to associate buildings with corresponding metadata such as height, year-of-construction, longitude, latitude, etc. The metadata will be the same across each individual building, so the per-vertex granularity of metadata is sufficient.
To retrieve a feature ID from a feature ID attribute, you will need to know the face ID of the triangle you want to retrieve the feature ID from.
Feature ID Texture
In this form, each texel fragment on a tile has a corresponding feature ID. This is taken to mean that all the metadata in the feature table row indexed by the feature ID is associated with the texel.
A common use of feature ID textures is to associate low-poly geometry like terrain with high-frequency metadata like land coverage data (e.g., water, swamp, desert, etc.). In such a case, the metadata varies at a higher frequency than can be expressed with per-vertex feature IDs. So instead, we use a texture with each pixel containing a feature ID, allowing us to vary the feature ID even within a single triangle.
To retrieve a feature ID from a feature ID texture, you will need to know the UV coordinates of the texel from which you want to retrieve the feature ID. The UV coordinate must correspond to the UV coordinate set associated with the feature ID texture.
Not to be confused with Feature ID Textures.
Feature textures are perhaps the most straightforward form of per-feature metadata. They have nothing to do with feature IDs or feature tables.
Each Feature Texture has a list of Feature Texture Properties, which are simply texture channels that contain metadata values within their pixels. This is useful for expressing discretized scalar and vector fields across the surface of a tile’s geometry (e.g., heatmaps, ocean current maps, weather maps, etc.). Each pixel will contain a scalar or vector depending on what kind of field the feature texture represents.
The Cesium Metadata Blueprint API will be described in the context of a line trace that hits a Primitive component. We will look at how to retrieve the metadata of a primitive from such a line trace, if any metadata exists. The parameters of the line trace itself are irrelevant to this reference documentation. For an example of setting up a line trace, see Visualizing Per-Feature Metadata.
As described in the previous section, there are two types of per-feature metadata. Namely, metadata that uses Feature IDs to index into Feature Tables and then the much simpler, self-contained Feature Textures.
This section demonstrates the Blueprint API for Feature Table metadata. In order to access specific per-feature metadata from a line trace, you will need a Feature ID and a Feature Table, which can be obtained through the Feature ID Attributes or Feature ID Textures.
Accessing Feature ID Attributes from a primitive
In this small blueprint excerpt below, we see that there is a Cesium Metadata Primitive retrieved from the HitResult→HitComponent that has a list of Feature ID Attributes. Each attribute has a corresponding Feature Table name and each attribute has its own mapping of per-vertex Feature IDs. For a specific triangle face ID, as given by HitResult→Face Index, we can determine a Feature ID for each Feature ID Attribute.
Accessing Feature ID Textures from a primitive
Accessing Feature ID Textures is similar to accessing Feature ID Attributes. We use a Cesium Metadata Primitive to retrieve a list of Feature ID Textures. For each Feature ID Texture, we retrieve the Feature Table name and a Feature ID at the UV coordinates where the line trace hit the mesh.
In order for the Find Collision UV node to work, you must enable the “Support UV from Hit Results” option in Project Settings → Physics.
Retrieving Metadata from a Feature Table
Now that we have a Feature Table name and Feature ID for each Feature ID Attribute / Texture, we can look up the corresponding data in the corresponding Feature Table.
The Blueprint below shows how to retrieve a Cesium Metadata Model from the HitResult and how to list the Feature Tables for the Cesium Metadata Model.
You can find a specific Feature Table by name and use any of the nodes shown below to explore the metadata in the table.
- To retrieve the metadata Properties for a specific Feature ID use Get Metadata Values (as String) for Feature ID.
- To retrieve the columns as a list of Property arrays use Get Properties.
- Get Number Of Features simply returns the number of rows in the Feature Table.
We can plug in our Feature Table name from our previous blueprints into the Find node and we can plug in our Feature ID into the Get Metadata Values (as String) for Feature ID node. This gives us a row of metadata Property values from the Feature Table. This is formatted as a map from column name (string) to Cesium Metadata Generic Value.
Types of Feature Table Metadata Values
Depending on how you accessed the metadata, you may have different types:
- If you used Get Metadata Values for Feature ID you should have Cesium Metadata Generic Values.
- If you used Get Properties you should have Cesium Metadata Properties (which are really column arrays from the Feature Table).
- You can also use Get Array to retrieve Cesium Metadata Arrays from Cesium Metadata Generic Value or Cesium Metadata Property when the property value type is an array.
The below nodes are available to retrieve type info and coerce usable values from the generic value accessors above.
While metadata properties can come in a variety of types, only some types are available in Blueprint. You can retrieve metadata as a Boolean, Byte, Integer, Integer64, Float, String, or Array. The above nodes will attempt to convert values to the requested data type.
If you require the original type, you can use a GetTrueType method to retrieve the actual underlying type.
You can also access a “best fit” Blueprint-supported lossless data type with GetBlueprintType. For example, if you are using UE4 and a property's original data type is a Double, it will be converted to a String, which is the only lossless option available in UE4's Blueprint.
Get Metadata Values for Face
The nodes Get Metadata Values for Face and Get Metadata Values as String for Face can be used to access rudimentary metadata properties. These nodes are simplified helper functions, and may not return all metadata. If the face is associated with multiple feature tables, the node only returns the metadata of the first feature table.
Get Metadata Values for Face preserves the original data type. Get Metadata Values as String for Face converts everything to a string, which does not preserve the original data type.
Each Feature Texture has a number of Feature Texture Properties, each of which has its own texture with metadata pixel values.
Each Cesium Metadata Primitive has a list of Feature Texture names that can be looked up on the Cesium Metadata Model, similar to how we looked up Feature Table names.
For each Feature Texture we find, we can look through each of its Feature Texture Properties.
For each Feature Texture Property, the following nodes are available.
- Get Component Count returns the number of channels the metadata pixel value uses.
- Get [Float / Integer] Color from Texture Coordinates returns the metadata pixel value coerced to float or integer respectively at the given UV coordinates. The UV coordinates have to correspond to the Feature Texture Property.
- Get Swizzle returns a string representing how the metadata value components sit in the pixel channels (e.g., “rgba”, “gbr”, etc.).
- Get Texture Coordinate Index returns the index of the UV coordinates set to use with Get [Float / Integer] Color from Texture Coordinates.
- Is Normalized returns whether the metadata pixel value should be interpreted as a normalized integer.
Similar to Feature ID Textures, you will need to use UV coordinates from the HitResult (using the Find Collision UV node) to retrieve the appropriate pixel value. The result will be a Cesium Integer Color or Cesium Float Color depending on which node you use to retrieve the metadata pixel value. These are structs with 4 channels of either integers or floats. Only the first n channels will be relevant, where n is the component count of the Feature Texture Property. For example, if the component count is 3, only the R, G, and B channels will have relevant metadata.
You can split the return struct pins by right clicking on them to directly access the integer or float metadata components.
The Cesium Encoded Metadata component can be added to tilesets to prepare per-feature metadata properties for material styling. Some of the component's parameters will be outlined below. For a tutorial on using this component to style a tileset, see the Visualizing Per-Feature Metadata tutorial.
The Auto Fill button accesses available metadata properties. Not all types of metadata properties can be used in materials.
Keep in mind the following notes best practices for using this component:
- Be sure to delete properties that aren't being used for the styling logic. Leaving unused properties will impact performance and cause excessive GPU texture memory usage. Deleted properties can be re-added via Auto Fill or manually.
- The Auto Fill button will be suitable for most scenarios. While you can add additional properties to the component, this functionality can only be used to access properties that already exist - it will not add new properties to the tileset itself.
- It is not recommended to edit property parameters (such as name, type, etc) for the auto-filled properties, as this may cause the component to work incorrectly.
Generating Materials
The Generate Material button will propagate listed properties from the Encoded Metadata component to a Material Layer.
- If the Target Material Layer property is not set, the Generate Material button will create a new Material Layer at the root of your project's Content folder, and set the Target Material Layer to that new auto-generated layer.
- If the Target Material Layer is set, the button will instead update the provided Material Layer with new nodes. Re-generating materials is usually non-destructive, and the component will attempt to keep existing node graphs intact.
The Material Layer must be added to a Material Instance, and the Material Instance assigned to your tileset, before metadata properties can be visualized. See the Editing Tileset Materials tutorial for more information.