The 3D Metadata Specification defines a standard format for structured metadata in 3D content. Metadata — represented as entities and properties — may be closely associated with parts of 3D content, with data representations appropriate for large, distributed datasets. For the most detailed use cases, properties allow vertex- and texel-level associations; higher-level property associations are also supported.
Many domains benefit from structured metadata — typical examples include historical details of buildings in a city, names of components in a CAD model, descriptions of regions on textured surfaces, and classification codes for point clouds.
The specification defines core concepts to be used by multiple 3D formats, and is language and format agnostic. This document defines concepts with purpose and terminology, but does not impose a particular schema or serialization format for implementation. For use of the format outside of abstract conceptual definitions, see:
-
3D Tiles Metadata - Assigns metadata to tilesets, tiles, and contents in 3D Tiles 1.1
-
3DTILES_metadata
- An extension for 3D Tiles 1.0 that assigns metadata to tilesets, tiles, and contents -
EXT_structural_metadata
(glTF 2.0) — Assigns metadata to vertices, texels, and features in a glTF asset
The specification does not enumerate or define the semantic meanings of metadata, and assumes that separate specifications will define semantics for their particular application or domain. One example is the 3D Metadata Semantic Reference which defines built-in semantics for 3D Tiles and glTF. Identifiers for externally-defined semantics can be stored within the 3D Metadata Specification.
This specification defines metadata schemas and methods for encoding metadata.
Schemas contain a set of classes and enums. A class represents a category of similar entities, and is defined as a set of properties. Each property describes values of a particular type. An enum defines a set of named values representing a single value type, and may be referenced by class properties. Schema definitions do not describe how entities or properties are stored, and may be represented in a file format in various ways. Schemas can be reused across multiple assets or even file formats.
Entities are instantiations of a class, populated with property values conforming to the class definition. Every property value of an entity shall be defined by its class, and an entity shall not have extraneous property values. Properties of a class may be required, in which case all entities instantiating the class are required to include them.
Note
|
Informative
Entities may be defined at various levels of abstraction. Within a large dataset, individual vertices or texels may represent entities with granular metadata properties. Vertices and texels may be organized into higher-order groups (such as meshes, scene graphs, or tilesets) having their own associated properties. |
Metadata, as used throughout this specification, refers to any association of 3D content with entities and properties, such that entities represent meaningful units within an overall structure. Other common definitions of metadata, particularly in relation to filesystems or networking as opposed to 3D content, remain outside the scope of the document.
Property values are stored with flexible representations to allow compact transmission and efficient lookups. This specification defines two possible storage formats.
Throughout this specification, IDs (identifiers) are strings that match the regular expression ^[a-zA-Z_][a-zA-Z0-9_]*$
: Strings that consist of upper- or lowercase letters, digits, or underscores, starting with either a letter or an underscore. These strings should be camel case strings that are human-readable (wherever possible). When IDs subject to these restrictions are not sufficiently clear for human readers, applications should also provide a name
for the structures that support dedicated names.
A schema defines the organization and types of metadata used in 3D content, represented as a set of classes and enums. Class definitions are referenced by entities whose metadata conforms to the class definition. This provides a consistent and machine-readable structure for all entities in a dataset.
Components of a schema are listed below, and implementations may define additional components.
IDs (id
) are unique identifiers for a schema.
Note
|
Informative
The schema ID is required for each schema. The main purpose of this ID is to be able to resolve possible ambiguities. The exact mechanism for this disabiguation depends on the client application, and how the access to metadata properties is implemented. But the schema ID makes sure that a compound identifier of the form |
Schema version (version
) is an application-specific identifier for a given schema revision. Version shall be a string, and should be syntactically compatible with SemVer.
When a schema has multiple versions, the (id, version)
pair uniquely identifies a particular schema and revision.
Note
|
Example
Valid semantic versions include strings like |
Names (name
) provide a human-readable label for a schema, and are not required to be unique. Names shall be valid Unicode strings, and should be written in natural language.
Descriptions (description
) provide a human-readable explanation of a schema, its purpose, or its contents. Typically at least a phrase, and possibly several sentences or paragraphs. Descriptions shall be valid Unicode strings.
Unordered set of enums.
An enum consists of a set of named values, represented as (string, integer)
pairs. Each enum is identified by a unique ID.
Note
|
Example
A "species" enum with three possible tree species, as well as an "Unknown" value.
|
IDs (id
) are unique identifiers for an enum within a schema.
Names (name
) provide a human-readable label for an enum, and are not required to be unique within a schema. Names shall be valid Unicode strings, and should be written in natural language.
Descriptions (description
) provide a human-readable explanation of an enum, its purpose, or its contents. Typically at least a phrase, and possibly several sentences or paragraphs. Descriptions shall be valid Unicode strings.
An enum consists of a set of named values, represented as (string, integer)
pairs. The following enum value types are supported: INT8
, UINT8
, INT16
, UINT16
, INT32
, UINT32
, INT64
, and UINT64
. See the Component Type section for definitions of each. Smaller enum types limit the range of possible enum values, and allow more efficient binary encoding. Duplicate names or values within the same enum are not allowed.
Classes represent categories of similar entities, and are defined by a collection of one or more properties shared by the entities of a class. Each class has a unique ID within the schema, and each property has a unique ID within the class, to be used for references within the schema and externally.
IDs (id
) are unique identifiers for a class within a schema.
Names (name
) provide a human-readable label for a class, and are not required to be unique within a schema. Names shall be valid Unicode strings, and should be written in natural language.
Descriptions (description
) provide a human-readable explanation of a class, its purpose, or its contents. Typically at least a phrase, and possibly several sentences or paragraphs. Descriptions shall be valid Unicode strings.
Properties describe the type and structure of values that may be associated with entities of a class. Entities may omit values for a property, unless the property is required. Entities shall not contain values other than those defined by the properties of their class.
Note
|
Example
The following example shows the basics of how classes describe the types of metadata. A building
tree
|
IDs (id
) are unique identifiers for a property within a class.
Names (name
) provide a human-readable label for a property, and shall be unique to a property within a class. Names shall be valid Unicode strings, and should be written in natural language. Property names do not have inherent meaning; to provide such a meaning, a property shall also define a semantic.
Note
|
Example
A typical ID / Name pair, in English, would be |
Descriptions (description
) provide a human-readable explanation of a property, its purpose, or its contents. Typically at least a phrase, and possibly several sentences or paragraphs. Descriptions shall be valid Unicode strings. To provide a machine-readable semantic meaning, a property shall also define a semantic.
Property IDs, names, and descriptions do not have an inherent meaning. To provide a machine-readable meaning, properties may be assigned a semantic identifier string (semantic
), indicating how the property’s content should be interpreted. Semantic identifiers may be defined by the 3D Metadata Semantic Reference or by external semantic references, and may be application-specific. Identifiers should be uppercase, with underscores as word separators.
Note
|
Example
Semantic definitions might include temperature in degrees Celsius (e.g. |
A property’s type (type
) describes the structure of the value given for each entity.
name | type |
---|---|
SCALAR |
Single numeric component |
VEC2 |
Fixed-length vector with two (2) numeric components |
VEC3 |
Fixed-length vector with three (3) numeric components |
VEC4 |
Fixed-length vector with four (4) numeric components |
MAT2 |
2x2 matrix with numeric components |
MAT3 |
3x3 matrix with numeric components |
MAT4 |
4x4 matrix with numeric components |
STRING |
A sequence of characters |
BOOLEAN |
True or false |
ENUM |
An enumerated type |
Scalar, vector, and matrix types comprise of numeric components. Each component is an instance of the property’s component type (componentType
), with the following component types supported:
name | componentType |
---|---|
INT8 |
Signed integer in the range |
UINT8 |
Unsigned integer in the range |
INT16 |
Signed integer in the range |
UINT16 |
Unsigned integer in the range |
INT32 |
Signed integer in the range |
UINT32 |
Unsigned integer in the range |
INT64 |
Signed integer in the range |
UINT64 |
Unsigned integer in the range |
FLOAT32 |
A number that can be represented as a 32-bit IEEE floating point number |
FLOAT64 |
A number that can be represented as a 64-bit IEEE floating point number |
Floating-point properties (FLOAT32
and FLOAT64
) shall not include values NaN
, +Infinity
, or -Infinity
.
Note
|
Informative
Developers of authoring tools should be aware that many JSON implementations support only numeric values that can be represented as IEEE-754 double precision floating point numbers. Floating point numbers should be representable as double precision IEEE-754 floats when encoded in JSON. When those numbers represent property values (such as |
Enum properties are denoted by ENUM
. An enum property shall additionally provide the ID of the specific enum it uses, referred to as its enum type (enumType
).
A property can be declared to be a fixed- and variable-length array, consisting of elements of the given type. For fixed-length arrays, a count (count
) denotes the number of elements in each array, and shall be greater than or equal to 2. Variable-length arrays do not define a count and may have any length, including zero.
Normalized properties (normalized
) provide a compact alternative to larger floating-point types. Normalized values are stored as integers, but when accessed are transformed to floating-point according to the following equations:
componentType | int to float | float to int |
---|---|---|
INT8 |
|
|
UINT8 |
|
|
INT16 |
|
|
UINT16 |
|
|
INT32 |
|
|
UINT32 |
|
|
INT64 |
|
|
UINT64 |
|
|
normalized
is only applicable to scalar, vector, and matrix types with integer component types.
Note
|
Informative
Depending on the implementation and the chosen integer type, there may be some loss of precision in values after denormalization. For example, if the implementation uses 32-bit floating point variables to represent the value of a normalized 32-bit integer, there are only 23 bits in the mantissa of the float, and lower bits will be truncated by denormalization. Client implementations should use higher precision floats when appropriate for correctly representing the result. |
A property may declare an offset (offset
) and scale (scale
) to apply to property values. This is useful when mapping property values to a different range.
The offset
and scale
can be defined for types that either have a floating-point componentType
, or when normalized
is set to true
. This applies to SCALAR
, VECN
, and MATN
types, and to fixed-length arrays of these types. The structure of offset
and scale
is explained in the Property Values Structure section.
The following equation is used to transform the original property value into the actual value that is used by the client:
transformedValue = offset + scale * normalize(value)
These operations are applied component-wise, both for array elements and for vector and matrix components.
The transformation that is described here allows arbitrary source value ranges to be mapped to arbitrary target value ranges, by first computing the float
value for the original normalized
value, and then mapping that floating point range to the desired target range.
Note
|
Informative
The result of transforming a |
When the offset
for a property is not given, then is is assumed to be 0
for each component of the respective type. When the scale
value of a property is not given, then it is assumed to be 1
for each component of the respective type. Instances of the class that defines the respective property can override the offset- and scale factors, to account for the actual range of property values that are provided by the instance.
Properties may specify a minimum (min
) and maximum (max
) value. Minimum and maximum values represent component-wise bounds of the valid range of values for a property. Both values are inclusive, meaning that they denote the smallest and largest allowed value, respectively.
The min
and max
value can be defined for SCALAR
, VECN
, and MATN
types with numeric component types, and for fixed-length arrays of these types. The structure of min
and max
is explained in the Property Values Structure section.
For properties that are normalized
, the component type of min
and max
is a floating point type. Their values represent the bounds of the final, transformed property values. This includes the normalization and offset
- or scale
computations, as well as other transforms or constraints that are not part of the class definition itself: A normalized
unsigned value is in the range [0.0, 1.0] after the normalization has been applied, but [min
, max
] may specify a different value range.
For all other properties, the component type of min
and max
matches the componentType
of the property, and the values are the bounds of the original property values.
Note
|
Example
A property storing GPS coordinates might define a range of |
Property values outside the [minimum, maximum]
range are not allowed, with the exception of noData
values.
When associated property values shall exist for all entities of a class, a property is considered required (required
).
Individual elements in an array or individual components in a vector or matrix cannot be marked as required; only the property itself can be marked as required.
Properties may optionally specify a No Data value (noData
, or "sentinel value") to be used when property values do not exist. A noData
value may be provided for any type
except BOOLEAN
. For ENUM
types, a noData
value should contain the name of the enum value as a string, rather than its integer value. The structure of the noData
value is explained in the Property Values Structure section.
A noData
value is especially useful when only some entities in a property table are missing property values (see Binary Table Format). Otherwise if all entities are missing property values the column may be omitted from the table and a noData
value need not be provided. Entities encoded in the JSON Format may omit the property instead of providing a noData
value. noData
values and omitted properties are functionally equivalent.
A default value (default
) may be provided for missing property values. For ENUM
types, a default
value should contain the name of the enum value as a string, rather than its integer value. For all other cases, the structure of the default
value is explained in the Property Values Structure section.
If a default value is not provided, the behavior when encountering missing property values is implementation-defined.
Note
|
Example
In the example below, a "tree" class is defined with
|
Property values that appear as part of the class definition are the offset, scale, minimum, maximum, default values and no-data values. The structure of these values inside the class definition depends on the type of the property. For SCALAR
(non-array) types, they are single values. For all other cases, they are arrays:
-
For
SCALAR
array types with fixed lengthcount
, they are arrays with lengthcount
. -
For
VECN
types, they are arrays, with lengthN
. -
For
MATN
types, they are arrays, with lengthN * N
. -
For
VECN
array types with fixed lengthcount
, they are arrays with lengthcount
, where each array element is itself an array of lengthN
-
For
MATN
array types with fixed lengthcount
, they are arrays with lengthcount
, where each array element is itself an array of lengthN * N
.
For noData
values and numeric values that are not normalized
, the type of the innermost elements of these arrays corresponds to the componentType
. For numeric values that are normalized
, the innermost elements are floating-point values.
Schemas provide templates for entities, but creating an entity requires specific property values and storage. This section covers two storage formats for entity metadata:
-
Binary Table Format - property values are stored in parallel 1D arrays, encoded as binary data
-
JSON Format - property values are stored in key/value dictionaries, encoded as JSON objects
Both formats are suitable for general purpose metadata storage. Binary formats may be preferable for larger quantities of metadata.
Additional serialization methods may be defined outside of this specification. For example, property values could be stored in texture channels or retrieved from a REST API as XML data.
Note
|
Informative
Any specification that references 3D Metadata shall state explicitly which storage formats are supported, or define its own serialization. For example, the |
The binary table format is similar to a database table where entities are rows and properties are columns. Each column represents one of the properties of the class. Each row represents a single entity conforming to the class.
The rows of a table are addressed by an integer index called an entity ID. Entity IDs are always numbered 0, 1, ..., N - 1
where N
is the number of rows in the table.
Property values are stored in parallel arrays called property arrays, one per column. Each property array stores values for a single property. The i-th
value of each property array is the value of that property for the entity with an entity ID of i
.
Binary encoding is efficient for runtime use, and scalable to large quantities of metadata. Because property arrays contain elements of a single type, bitstreams may be tightly packed or may use compression methods appropriate for a particular data type.
Property values are binary-encoded according to their data type, in little-endian format. Values are tightly packed: there is no padding between values.
A scalar value is encoded based on the componentType
. Multiple values are packed tightly in the same buffer. The following data types are supported:
Name | Description |
---|---|
INT8 |
8-bit two’s complement signed integer |
UINT8 |
8-bit unsigned integer |
INT16 |
16-bit two’s complement signed integer |
UINT16 |
16-bit unsigned integer |
INT32 |
32-bit two’s complement signed integer |
UINT32 |
32-bit unsigned integer |
INT64 |
64-bit two’s complement signed integer |
UINT64 |
64-bit unsigned integer |
FLOAT32 |
32-bit IEEE floating point number |
FLOAT64 |
64-bit IEEE floating point number |
Matrix components are tightly packed in column-major order and encoded based on the componentType
.
A boolean value is encoded as a single bit, either 0 (false
) or 1 (true
). Multiple boolean values are packed tightly in the same buffer. These buffers of tightly-packed bits are sometimes referred to as bitstreams.
For a table with N
rows, the buffer that stores these boolean values will consist of ceil(N / 8)
bytes. When N
is not divisible by 8, then the unused bits of the last byte of this buffer shall be set to 0.
Note
|
Informative
Example accessing a boolean value for entity ID byteIndex = floor(i / 8)
bitIndex = i % 8
bitValue = (buffer[byteIndex] >> bitIndex) & 1
value = bitValue == 1 |
A string value is a UTF-8 encoded byte sequence. Multiple strings are packed tightly in the same buffer.
Because string lengths may vary, a string offset buffer is used to identify strings in the buffer. If there are N
strings in the property array, the string offset buffer has N + 1
elements. The first N
of these point to the first byte of each string, while the last points to the byte immediately after the last string. The number of bytes in the i-th
string is given by stringOffset[i + 1] - stringOffset[i]
. UTF-8 encodes each character as 1-4 bytes, so string offsets do not necessarily represent the number of characters in the string.
The data type used for offsets is defined by a string offset type, which may be UINT8
, UINT16
, UINT32
, or UINT64
.
A fixed-length array value is encoded as a tightly packed array of count
elements, where each element is encoded according to the type
.
Variable-length arrays use an additional array offset buffer. The i-th
value in the array offset buffer is an element index — not a byte offset — identifying the beginning of the i-th
array. String values within an array may have inconsistent lengths, requiring both array offset and string offset buffers (see: Strings).
The data type used for offsets is defined by an array offset type, which may be UINT8
, UINT16
, UINT32
, or UINT64
.
If there are N
arrays in the property array, the array offset buffer has N + 1
elements. The first N
of these point to the first element of an array within the property array, or within a string offset buffer for string component types. The last value points to a (non-existent) element immediately following the last array element.
For each case below, the offset of an array element i
within its binary storage is expressed in terms of entity ID id
and element index i
.
Type | Offset type | Offset |
---|---|---|
|
byte offset |
|
All other types |
array index |
|
Each expression in the table above defines an index into the underlying property array. For a property array of SCALAR
elements with FLOAT32
component type, index 3
corresponds to byte offset 3 * sizeof(FLOAT32)
. For a property array of VEC4
elements with FLOAT32
component type, index 3
corresponds to byte offset 3 * 4 * sizeof(FLOAT32) = 48
. For an array of BOOLEAN
elements, offset 3
would correspond to bit offset 3
.
Note
|
Example
Five variable-length arrays of UINT8 components, binary-encoded in a buffer. The associated property definition would be |
Note
|
Example
Two variable-length arrays of strings, binary-encoded in a buffer. The associated property definition would be |
JSON encoding is useful for storing a small number of entities in human readable form.
Each entity is represented as a JSON object with its class
identified by a string ID. Property values are defined in a key/value properties
dictionary, having property IDs as its keys. Property values are encoded as corresponding JSON types: numeric types are represented as number
, booleans as boolean
, strings as string
, enums as string
, vectors and matrices as array
of number
, and arrays as array
of the containing type.
Note
|
Example
The following example demonstrates usage for both fixed- and variable-length arrays: An enum, "basicEnum", composed of three
A class, "basicClass", composed of ten properties.
A single entity encoded in JSON. Note that the optional property is omitted in this example. {
"entity": {
"class": "basicClass",
"properties": {
"floatProperty": 1.5,
"integerProperty": -90,
"vectorProperty": [0.0, 1.0],
"floatArrayProperty": [1.0, 0.5, -0.5],
"vectorArrayProperty": [[0.0, 1.0], [1.0, 2.0]],
"booleanProperty": true,
"stringProperty": "x123",
"enumProperty": "Enum B",
"stringArrayProperty": ["abc", "12345", "おはようございます"]
}
}
} |
All component types (INT8
, UINT8
, INT16
, UINT16
, INT32
, UINT32
, INT64
, UINT64
, FLOAT32
, and FLOAT64
) are encoded as JSON numbers. Floating point values shall be representable as IEEE floating point numbers.
Note
|
Informative
For numeric types the size in bits is made explicit. Even though JSON only has a single |
Enums are encoded as JSON strings using the name of the enum value rather than the integer value. Therefore the enum value type, if specified, is ignored for the JSON encoding.