diff --git a/extensions/2.0/Vendor/EXT_mesh_features/README.md b/extensions/2.0/Vendor/EXT_mesh_features/README.md
new file mode 100644
index 0000000000..5dcd8fde7a
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/README.md
@@ -0,0 +1,443 @@
+
+# EXT_mesh_features
+
+
+## Contributors
+
+* Peter Gagliardi, Cesium
+* Sean Lilley, Cesium
+* Sam Suhag, Cesium
+* Patrick Cozzi, Cesium
+* Bao Tran, Cesium
+* Samuel Vargas, Cesium
+
+
+## Status
+
+Draft
+
+
+## Dependencies
+
+Written against the glTF 2.0 specification.
+
+Adds new functionality to the [`EXT_mesh_gpu_instancing` extension](../../EXT_mesh_gpu_instancing).
+
+
+## Optional vs. Required
+
+This extension is optional, meaning it should be placed in the `extensionsUsed` list, but not in the `extensionsRequired` list.
+
+
+## Contents
+
+- [Overview](#overview)
+- [Feature Identification](#feature-identification)
+ - [Feature ID Vertex Attributes](#feature-id-vertex-attributes)
+ - [Feature ID Accessors](#feature-id-accessors)
+ - [Implicit Feature IDs](#implicit-feature-ids)
+ - [Feature ID Textures](#feature-id-textures)
+ - [Feature ID Instance Attributes](#feature-id-instance-attributes)
+- [Feature Properties](#feature-properties)
+ - [Schemas](#schemas)
+ - [Property Tables](#property-tables)
+ - [Property Textures](#property-textures)
+- [Binary Data Storage](#binary-data-storage)
+- [Examples](#examples)
+- [Schema](#schema)
+- [Revision History](#revision-history)
+
+## Overview
+
+A **feature** is an entity that has both geometry and associated properties. In Geographic Information Systems (GIS) a feature is an entity such as a point, polyline, or polygon that represents some element on a map. In another domain like CAD/BIM a feature might be a component of a design model. A feature could also be a 3D building in a city, a tree in a forest, a sample point in a weather model, or a patch of texels on a 3D model.
+
+This extension allows batching features for efficient streaming to a client for rendering and interaction. Efficiency comes from transferring multiple features in the same glTF and rendering them in the least number of draw calls necessary.
+
+Feature IDs enable individual features to be identified and updated at runtime. For example, a selected feature could be shown/hidden, or highlighted a different color. Feature IDs may be assigned on a per-vertex, per-texel, or per-instance basis.
+
+Feature IDs may be used to access associated properties, such as passing a building's ID to get its address. Feature properties are stored in a compact binary tabular format described in the [Cesium 3D Metadata Specification](https://github.com/CesiumGS/3d-tiles/tree/3d-tiles-next/specification/Metadata).
+
+
+
+In the image above, a glTF consists of two houses batched together into a single primitive. A feature ID attribute on the primitive indicates that all of the vertices making up the first house have a feature ID of 0, while all vertices making up the second house have the feature ID 1. The feature ID is then used to access the building's properties from the property table.
+
+Feature properties may also be stored directly in textures. This is especially useful when texture mapping high frequency data, such as material properties, to less detailed 3D surfaces. Property textures enable new styling and analytics capabilities, and complement glTF PBR textures.
+
+See [Examples](#examples) for a full list of use cases for this extension.
+
+## Feature Identification
+
+Features in a glTF primitive are identified in three ways:
+
+* Per-vertex using a vertex attribute
+* Per-texel using a glTF texture
+* Per-instance using an instance attribute with the [`EXT_mesh_gpu_instancing` extension](../../EXT_mesh_gpu_instancing)
+
+
+
+### Feature ID Vertex Attributes
+
+#### Feature ID Accessors
+
+The most straightforward method for defining feature IDs is to store them in a glTF vertex attribute. Feature ID attributes must follow the naming convention `FEATURE_ID_X` where `X` is a non-negative integer. The first feature ID attribute is `FEATURE_ID_0`, the second `FEATURE_ID_1`, and so on.
+
+Feature IDs are whole numbers in the range `[0, count - 1]` (inclusive), where `count` is the total number of features in the property table. Values outside this range indicate that no feature is associated.
+
+The attribute's accessor `type` must be `"SCALAR"` and `normalized` must be false. There is no restriction on `componentType`.
+
+> **Implementation Note:** since glTF accessors do not support `UNSIGNED_INT` types for 32-bit integers, `FLOAT` may be used instead. This allows for integer feature IDs up to 2²⁴. For smaller ranges of feature IDs, `UNSIGNED_BYTE` or `UNSIGNED_SHORT` can still be used. Note that this requires aligning each feature ID to 4-byte boundaries to adhere to glTF's alignment rules.
+
+
+
+```jsonc
+{
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "FEATURE_ID_0": 1
+ },
+ "indices": 2,
+ "mode": 4,
+ "extensions": {
+ "EXT_mesh_features": {
+ "propertyTables": [0],
+ "featureIds": [{"attribute": 0}]
+ }
+ }
+ }
+ ]
+}
+```
+
+#### Implicit Feature IDs
+
+In some cases it is possible to define feature IDs implicitly, such as when all vertices in a primitive have the same feature ID or when each vertex in a primitive has a different feature ID.
+
+This is accomplished by using `offset` and `repeat`.
+
+* `offset` specifies the initial value for the vertex feature ID range. The default is `0`.
+* `repeat`, if defined, specifies the number of vertices for which to repeat each feature ID before incrementing the ID by 1. If `repeat` is undefined, the feature ID for all vertices is `offset`.
+
+For example
+
+* If `offset` is 0 or undefined and `repeat` is undefined, the feature IDs are `[0, 0, 0, ...]`
+* If `offset` is 0 and `repeat` is 1, the feature IDs are `[0, 1, 2, ...]`
+* If `offset` is 0 and `repeat` is 2, the feature IDs are `[0, 0, 1, 1, 2, 2, ...]`
+* If `offset` is 2 and `repeat` is 3, the feature IDs are `[2, 2, 2, 3, 3, 3, 4, 4, 4, ...]`
+* If `offset` is 2 and `repeat` is undefined, the feature IDs are `[2, 2, 2, ...]`
+
+`offset` and `repeat` must be omitted when `attribute` is used. These two methods of assigning feature IDs are mutually exclusive.
+
+
+
+```jsonc
+{
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0
+ },
+ "mode": 0,
+ "extensions": {
+ "EXT_mesh_features": {
+ "propertyTables": [0],
+ "featureIds": [{"offset": 0, "repeat": 1}]
+ }
+ }
+ }
+ ]
+}
+```
+### Feature ID Textures
+
+Feature ID textures classify the pixels of an image into different features. Some examples include image segmentation or marking regions on a map.
+
+Often per-texel feature IDs provide finer granularity than per-vertex feature IDs as in the example below.
+
+
+
+```jsonc
+{
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 1
+ },
+ "indices": 2,
+ "material": 0,
+ "extensions": {
+ "EXT_mesh_features": {
+ "propertyTables": [0],
+ "featureIds": [
+ {"index": 0, "texCoord": 0, "channel": 0}
+ ]
+ }
+ }
+ }
+ ]
+}
+```
+
+The `featureId` entry for a feature ID texture extends the glTF [`textureInfo`](../../../../../specification/2.0/schema/textureInfo.schema.json) object. Each `channel` must be a non-negative integer corresponding to a channel of the source texture. Channels of an `RGBA` texture are numbered 0–3 respectively, although specialized texture formats may allow additional channels. Feature IDs are whole numbers in the range `[0, count - 1]` (inclusive), stored in linear space, where `count` is the total number of features in the property table. Values outside this range indicate that no feature is associated.
+
+Texture filtering must be `9728` (NEAREST), or undefined, for any texture object referenced as a feature ID texture.
+
+### Feature ID Instance Attributes
+
+Feature IDs may also be assigned to individual instances when using the [`EXT_mesh_gpu_instancing` extension](../../EXT_mesh_gpu_instancing). This works the same way as assigning feature IDs to vertices. Feature IDs may be stored in accessors or generated implicitly. Nodes with `EXT_mesh_features` must also define an `EXT_mesh_gpu_instancing` extension providing feature ID instance attributes, and are invalid without this dependency.
+
+```jsonc
+{
+ "nodes": [
+ {
+ "mesh": 0,
+ "extensions": {
+ "EXT_mesh_gpu_instancing": {
+ "attributes": {
+ "TRANSLATION": 0,
+ "ROTATION": 1,
+ "SCALE": 2,
+ "FEATURE_ID_0": 3
+ },
+ },
+ "EXT_mesh_features": {
+ "propertyTables": [0],
+ "featureIds": [{"attribute": 0}]
+ }
+ }
+ }
+ ]
+}
+```
+
+## Feature Properties
+
+Feature properties are structured according to a **schema**. A schema has a set of **classes** and **enums**. A class contains a set of **properties**, which may be numeric, boolean, string, enum, or array types.
+
+A **feature** is a specific instantiation of class containing **property values**. Property values are stored in either a **property table** or a **property texture** depending on the use case. Both formats are designed for storing property values for a large number of features.
+
+By default, properties do not have any inherent meaning. A property may be assigned a **semantic**, an identifier that describes how the property should be interpreted. Built-in semantics include `ID` and `NAME`, as defined below.
+
+- `ID`: Unique identifier for the feature.
+- `NAME`: Name of the feature; not required to be unique.
+
+Model authors may define their own application- or domain-specific semantics separately. For application-specific semantics, authoring implementations are encouraged to use a `_*` prefix. For semantics common to a particular domain or vendor, creation of new uppercase, alphanumeric prefixes is encouraged.
+
+This extension implements the [Cesium 3D Metadata Specification](https://github.com/CesiumGS/3d-tiles/tree/3d-tiles-next/specification/Metadata), which describes the metadata format in full detail.
+
+### Schemas
+
+A schema defines a set of classes and enums used in a model. Classes serve as templates for features - they provide a list of properties and the type information for those properties. Enums define the allowable values for enum properties. Schemas are defined in full detail in the [Schemas](https://github.com/CesiumGS/3d-tiles/tree/3d-tiles-next/specification/Metadata#schemas) section of the [Cesium 3D Metadata Specification](https://github.com/CesiumGS/3d-tiles/tree/3d-tiles-next/specification/Metadata).
+
+A schema may be embedded in the extension directly or referenced externally with the `schemaUri` property. Multiple glTF models may refer to the same external schema to avoid duplication.
+
+Schemas may be given a `name`, `description`, and `version`.
+
+### Property Tables
+
+A property table stores property values in a parallel array format. Each property array corresponds to a class property. The values contained within a property array must match the data type of the class property. Furthermore, the set of property arrays must match one-to-one with the class properties. There is one exception - if a property specifies a `noData` value, the property table may omit that property.
+
+The schema and property tables are defined in the root extension object in the glTF model. See the example below:
+
+```jsonc
+{
+ "extensions": {
+ "EXT_mesh_features": {
+ "schema": {
+ "classes": {
+ "tree": {
+ "properties": {
+ "height": {
+ "description": "Height of tree measured from ground level",
+ "type": "FLOAT32"
+ },
+ "birdCount": {
+ "description": "Number of birds perching on the tree",
+ "type": "UINT8"
+ },
+ "species": {
+ "description": "Species of the tree",
+ "type": "STRING"
+ }
+ }
+ }
+ }
+ },
+ "propertyTables": [{
+ "name": "tree",
+ "class": "tree",
+ "count": 10,
+ "properties": {
+ "height": {
+ "bufferView": 0
+ },
+ "birdCount": {
+ "bufferView": 1
+ },
+ "species": {
+ "bufferView": 2,
+ "stringOffsetBufferView": 3
+ }
+ }
+ }]
+ }
+ }
+}
+```
+
+`class` is the ID of the class in the schema. `count` is the number of features in the property table, as well as the length of each property array. Property arrays are stored in glTF buffer views and use the binary encoding defined in the [Table Format](https://github.com/CesiumGS/3d-tiles/tree/3d-tiles-next/specification/Metadata#table-format) section of the [Cesium 3D Metadata Specification](https://github.com/CesiumGS/3d-tiles/tree/3d-tiles-next/specification/Metadata).
+
+As in the core glTF specification, values of NaN, +Infinity, and -Infinity are never allowed.
+
+Each buffer view `byteOffset` must be aligned to a multiple of 8 bytes.
+
+### Property Textures
+
+Property textures use textures rather than parallel arrays to store values. Property textures are accessed directly by texture coordinates, and do not require feature IDs. Property textures are especially useful when texture mapping high frequency data to less detailed 3D surfaces. For each property that does not specify a `noData` value, a mapping to the corresponding texture channel or channels is required. Properties with a `noData` value are optional in property textures instantiating a given class.
+
+Property textures use the [Raster Format](https://github.com/CesiumGS/3d-tiles/tree/3d-tiles-next/specification/Metadata#raster-format) of the [Cesium 3D Metadata Specification](https://github.com/CesiumGS/3d-tiles/tree/3d-tiles-next/specification/Metadata) with a few additional constraints:
+
+* A scalar property cannot be encoded into multiple channels. For example, it is not possible to encode a `UINT32` property in an `RGBA8` texture.
+* Components of fixed-length array properties must be separate channels within the same texture.
+* Variable-length arrays are not supported.
+
+Additionally, the data type and bit depth of the image must be compatible with the property type. An 8-bit per pixel RGB image is only compatible with `UINT8` or normalized `UINT8` properties, and array properties thereof with three components or less. Likewise, a floating point property requires a floating point-compatible image format like KTX2 which may require additional extensions.
+
+Property textures are defined with the following steps:
+
+1. A class is defined in the root `EXT_mesh_features` extension object. This is used to describe the properties in the texture.
+2. A property texture is defined in the root `EXT_mesh_features.propertyTextures` object. This must reference the class ID defined in step 1.
+3. A property texture is associated with a primitive by listing the property texture ID in the `primitive.EXT_mesh_features.propertyTextures` array.
+
+
+_Class and property texture_
+
+```jsonc
+{
+ "extensions": {
+ "EXT_mesh_features": {
+ "schema": {
+ "classes": {
+ "heatSample": {
+ "properties": {
+ "heatLoss": {
+ "type": "UINT8",
+ "normalized": true
+ },
+ "insulation": {
+ "type": "UINT8",
+ "normalized": true
+ },
+ }
+ }
+ }
+ },
+ "propertyTextures": [{
+ "class": "heatSample",
+ "index": 0,
+ "texCoord": 0,
+ "properties": {
+ "heatLoss": [0],
+ "insulation": [1]
+ }
+ }]
+ }
+ }
+}
+```
+
+_Primitive_
+
+```jsonc
+{
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 1
+ },
+ "indices": 2,
+ "material": 0,
+ "extensions": {
+ "EXT_mesh_features": {
+ "propertyTextures": [0]
+ }
+ }
+ }
+ ]
+}
+```
+
+
+A `propertyTexture` object extends the glTF [`textureInfo`](../../../../../specification/2.0/schema/textureInfo.schema.json) object. `texCoord` refers to the texture coordinate set of the referring primitive. The `properties` map specifies the texture channels providing data for all required class properties, and perhaps optional class properties. An array of integer index values identify channels, where multiple channels may be used only for fixed-length arrays of 2, 3, or 4 components. Channels of an `RGBA` texture are numbered 0–3 respectively, although specialized texture formats may allow additional channels. All values are stored in linear space.
+
+Texture filtering must be `9728` (NEAREST), `9729` (LINEAR), or undefined, for any texture object referenced as a property texture.
+
+## Binary Data Storage
+
+`EXT_mesh_features` imposes additional binary data alignment requirements on an asset, extending the 4-byte alignment in the core glTF specification:
+
+- GLB-stored `JSON` chunk must be padded with trailing `Space` characters (`0x20`) to 8-byte boundary.
+- GLB-stored `BIN` chunk must be padded with trailing zeroes (`0x00`) to 8-byte boundary.
+
+As a result, byte length of the `BIN` chunk may be up to 7 bytes larger than JSON-defined `buffer.byteLength` to satisfy alignment requirements.
+
+## Examples
+
+_This section is non-normative_
+
+The examples below shows the breadth of possible use cases for this extension.
+
+Example|Description|Image
+--|--|--
+Triangle mesh|Feature IDs are assigned to each vertex to distinguish components of a building.|
+Per-vertex metadata
|An implicit feature ID is assigned to each vertex. The property table stores `FLOAT64` accuracy values. |
+Per-triangle metadata|An implicit feature ID is assigned to each set of three vertices. The property table stores `FLOAT64` area values.|
+Per-point metadata|An implicit feature ID is assigned to each point. The property table stores `FLOAT64` , `STRING`, and `ENUM` properties, which are not possible through glTF vertex attribute accessors alone.|
+Per-node metadata|Vertices in node 0 and node 1, not batched together, are assigned different `offset` feature IDs.|
+Multi-point features|A point cloud with two property tables, one storing metadata for groups of points and the other storing metadata for individual points.|
+Multi-instance features|Instanced tree models where trees are assigned to groups with a per-instance feature ID attribute. One property table stores per-group metadata and the other stores per-tree metadata.|
+Material classification|A textured mesh using a property texture to store both material enums and normalized `UINT8` thermal temperatures.|
+Composite|A glTF containing a 3D mesh (house), a point cloud (tree), and instanced models (fencing) with three property tables.|
+
+## Schema
+
+* [gltf.EXT_mesh_features.schema.json](./schema/gltf.EXT_mesh_features.schema.json)
+* [primitive.EXT_mesh_features.schema.json](./schema/primitive.EXT_mesh_features.schema.json)
+* [node.EXT_mesh_features.schema.json](./schema/node.EXT_mesh_features.schema.json)
+
+## Revision History
+
+* **Version 0.0.0** December 4, 2020
+ * Initial draft
+* **Version 1.0.0** February 24, 2021
+ * Changes to class properties
+ * Removed `FLOAT16` type
+ * Removed `BLOB` type
+ * Added `ENUM` to the list of supported types and component types and added `enumType` to refer to the chosen enum
+ * `min` and `max` are now numbers instead of single-element arrays for non-`ARRAY` properties
+ * Changes to property table
+ * Removed `offsetBufferViews`, replaced with `arrayOffsetBufferView` and `stringOffsetBufferView`
+ * Removed `blobByteLength`
+ * Removed `stringByteLength`
+ * Removed `name` and `description`
+ * Removed `elementCount` and redefined `count` to mean the element count
+ * Added optional `semantic` property
+ * Changes to feature ID attribute
+ * Removed `vertexStride` and `instanceStride`
+ * Added `divisor` for incrementing feature IDs at fixed intervals, e.g. per-triangle or per-quad
+ * Changes to `EXT_feature_metadata` object
+ * Removed `classes` dictionary. Classes and enums are now contained in the `schema` object.
+ * Added `schema` and `schemaUri`. The schema object contains class and enum definitions. `schemaUri` refers to an external schema JSON file. `schema` and `schemaUri` are mutually exclusive.
+ * Added optional `statistics` object which provides aggregate information about select properties within the model
+ * Other changes
+ * Added `EXT_feature_metadata` extension to the [`EXT_mesh_gpu_instancing`](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_mesh_gpu_instancing) extension for assigning metadata to instances
+* **Version 2.0.0** September 2021
+ * Renamed extension from `EXT_feature_metadata` to `EXT_mesh_features`
+ * Renamed `constant` to `offset`, and `divisor` to `repeat`
+ * Removed `statistics` specification, to be considered as a future extension
+ * Renamed `featureTable` → `propertyTable` and `featureTexture` → `propertyTexture`
+ * Removed `featureIdAttributes` and `featureIdTextures`, replaced with `featureIds`
+ * Removed string ID references to property tables and textures, replaced with integer IDs
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/building-components.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/building-components.png
new file mode 100644
index 0000000000..a6b959f195
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/building-components.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/composite-example.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/composite-example.png
new file mode 100644
index 0000000000..9246436be1
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/composite-example.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-id-texture.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-id-texture.png
new file mode 100644
index 0000000000..09610050df
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-id-texture.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-table-buildings.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-table-buildings.png
new file mode 100644
index 0000000000..ee170d623e
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-table-buildings.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-table.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-table.png
new file mode 100644
index 0000000000..ffc3cefb7d
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-table.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-texture.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-texture.png
new file mode 100644
index 0000000000..e1a3f2d81a
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/feature-texture.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/implicit-feature-ids.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/implicit-feature-ids.png
new file mode 100644
index 0000000000..da6b987e4e
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/implicit-feature-ids.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/material-classification.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/material-classification.png
new file mode 100644
index 0000000000..7b0e150d8e
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/material-classification.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/metadata-access.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/metadata-access.png
new file mode 100644
index 0000000000..b7c043cb16
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/metadata-access.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/multi-instance-metadata.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/multi-instance-metadata.png
new file mode 100644
index 0000000000..dcb13356be
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/multi-instance-metadata.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/per-node-metadata.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/per-node-metadata.png
new file mode 100644
index 0000000000..23c5bfc502
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/per-node-metadata.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/per-triangle-metadata.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/per-triangle-metadata.png
new file mode 100644
index 0000000000..666a7cbe53
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/per-triangle-metadata.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/per-vertex-metadata.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/per-vertex-metadata.png
new file mode 100644
index 0000000000..7683638e78
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/per-vertex-metadata.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/placemarks.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/placemarks.png
new file mode 100644
index 0000000000..eb39992a49
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/placemarks.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/point-cloud-layers.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/point-cloud-layers.png
new file mode 100644
index 0000000000..c2c61c3ad3
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/point-cloud-layers.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/figures/point-features.png b/extensions/2.0/Vendor/EXT_mesh_features/figures/point-features.png
new file mode 100644
index 0000000000..b22d400836
Binary files /dev/null and b/extensions/2.0/Vendor/EXT_mesh_features/figures/point-features.png differ
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/class.property.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/class.property.schema.json
new file mode 100644
index 0000000000..eb81480f66
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/class.property.schema.json
@@ -0,0 +1,108 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Class property",
+ "type": "object",
+ "description": "A class property.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The name of the property, e.g. for display purposes."
+ },
+ "description": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The description of the property."
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "SINGLE",
+ "VEC2",
+ "VEC3",
+ "VEC4",
+ "MAT2",
+ "MAT3",
+ "MAT4",
+ "ARRAY"
+ ],
+ "default": "SINGLE",
+ "description": "Element type represented by each property value. `VECN` is a vector with `N` components. `MATN` is an `N ⨉ N` matrix. `ARRAY` is fixed-length when `componentCount` is defined, and is variable-length otherwise."
+ },
+ "enumType": {
+ "type": "string",
+ "description": "Enum ID as declared in the `enums` dictionary. Required when `componentType` is `ENUM`."
+ },
+ "componentType": {
+ "enum": [
+ "INT8",
+ "UINT8",
+ "INT16",
+ "UINT16",
+ "INT32",
+ "UINT32",
+ "INT64",
+ "UINT64",
+ "FLOAT32",
+ "FLOAT64",
+ "BOOLEAN",
+ "STRING",
+ "ENUM"
+ ],
+ "description": "Data type of an element's components. When `type` is `SINGLE`, then `componentType` is also the data type of the element. When `componentType` is `ENUM`, `enumType` is required."
+ },
+ "componentCount": {
+ "type": "integer",
+ "minimum": 2,
+ "description": "Number of components per element for fixed-length `ARRAY` elements. Always undefined for variable-length `ARRAY` and all other element types."
+ },
+ "normalized": {
+ "type": "boolean",
+ "description": "Specifies whether integer values are normalized. This applies both when `type` is an integer type, or when `type` is `ARRAY` with a `componentType` that is an integer type. For unsigned integer types, values are normalized between `[0.0, 1.0]`. For signed integer types, values are normalized between `[-1.0, 1.0]`. For all other types, this property is ignored.",
+ "default": false
+ },
+ "max": {
+ "oneOf": [
+ {"type": "number"},
+ {"type": "array", "items": {"type": "number"}, "minItems": 1}
+ ],
+ "description": "Maximum allowed value for the property. Only applicable for single-value numeric types, fixed-length arrays of numeric types, and `VECN` types. For single-value numeric types this is a single number. For fixed-length arrays and `VECN`, the maximum is an array with the same number of elements. The `normalized` property has no effect on the maximum, which always contains integer values."
+ },
+ "min": {
+ "oneOf": [
+ {"type": "number"},
+ {"type": "array", "items": {"type": "number"}, "minItems": 1}
+ ],
+ "description": "Minimum allowed value for the property. Only applicable for single-value numeric types, fixed-length arrays of numeric types, and `VECN` types. For single-value numeric types this is a single number. For fixed-length arrays and `VECN`, the minimum is an array with the same number of elements. The `normalized` property has no effect on the minimum, which always contains integer values."
+ },
+ "required": {
+ "type": "boolean",
+ "description": "If required, the property must be present for every feature of its class. If not required, individual features may include `noData` values, or the entire property may be omitted from a property table or texture. As a result, `noData` has no effect on a required property. Client implementations may use required properties to make performance optimizations.",
+ "default": false
+ },
+ "noData": {
+ "oneOf": [
+ {"type": "number"},
+ {"type": "string"},
+ {"type": "array", "items": {"type": "number"}, "minItems": 1},
+ {"type": "array", "items": {"type": "string"}, "minItems": 1}
+ ],
+ "description": "A `noData` value represents missing data — also known as a sentinel value — wherever it appears. If omitted (excluding variable-length `ARRAY` properties), property values exist for all features, and the property is required in property tables or textures instantiating the class. For variable-length `ARRAY` elements, `noData` is implicitly `[]` and the property is never required; an additional `noData` array, such as `[\"UNSPECIFIED\"]`, may be provided if necessary. For fixed-length `ARRAY` properties, `noData` must be an array of length `componentCount`. For `VECN` properties, `noData` must be an array of length `N`. For `MATN` propperties, `noData` must be an array of length `N²`. `BOOLEAN` properties may not specify `noData` values. `ENUM` `noData` values must be a valid item name, not an integer value."
+ },
+ "semantic": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An identifier that describes how this property should be interpreted. The semantic cannot be used by other properties in the class."
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "dependencies": {
+ "componentCount": [
+ "type"
+ ]
+ },
+ "required": [
+ "componentType"
+ ]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/class.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/class.schema.json
new file mode 100644
index 0000000000..e8ee28efd3
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/class.schema.json
@@ -0,0 +1,28 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Class",
+ "type": "object",
+ "description": "A class containing a set of properties.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The name of the class, e.g. for display purposes."
+ },
+ "description": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The description of the class."
+ },
+ "properties": {
+ "type": "object",
+ "description": "A dictionary, where each key is a property ID and each value is an object defining the property.",
+ "minProperties": 1,
+ "additionalProperties": {
+ "$ref": "class.property.schema.json"
+ }
+ },
+ "extensions": {},
+ "extras": {}
+ }
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/enum.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/enum.schema.json
new file mode 100644
index 0000000000..67691e88a0
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/enum.schema.json
@@ -0,0 +1,46 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Enum",
+ "type": "object",
+ "description": "An object defining the values of an enum.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The name of the enum, e.g. for display purposes."
+ },
+ "description": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The description of the enum."
+ },
+ "valueType": {
+ "type": "string",
+ "default": "UINT16",
+ "enum": [
+ "INT8",
+ "UINT8",
+ "INT16",
+ "UINT16",
+ "INT32",
+ "UINT32",
+ "INT64",
+ "UINT64"
+ ],
+ "description": "The type of the integer enum value."
+ },
+ "values": {
+ "type": "array",
+ "description": "An array of enum values. Duplicate names or duplicate integer values are not allowed.",
+ "items": {
+ "$ref": "enum.value.schema.json"
+ },
+ "minItems": 1
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "required": [
+ "values"
+ ]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/enum.value.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/enum.value.schema.json
new file mode 100644
index 0000000000..a25cf23688
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/enum.value.schema.json
@@ -0,0 +1,28 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Enum value",
+ "type": "object",
+ "description": "An enum value.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The name of the enum value."
+ },
+ "description": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The description of the enum value."
+ },
+ "value": {
+ "type": "integer",
+ "description": "The integer enum value."
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "required": [
+ "name",
+ "value"
+ ]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/featureIdAttribute.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/featureIdAttribute.schema.json
new file mode 100644
index 0000000000..0df895704a
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/featureIdAttribute.schema.json
@@ -0,0 +1,42 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Feature IDs",
+ "type": "object",
+ "description": "Feature IDs to be used as indices to property arrays in the property table.",
+ "properties": {
+ "attribute": {
+ "type": "string",
+ "pattern": "^FEATURE_ID_([1-9]\\d*|0)$",
+ "description": "The name of the attribute containing feature IDs."
+ },
+ "offset": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0,
+ "description": "Initial value for an implicit feature ID range."
+ },
+ "repeat": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Number of vertices for which to repeat each feature ID before incrementing the ID by 1. If `repeat` is undefined, the feature ID for all vertices is `offset`."
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "not": {
+ "anyOf": [
+ {
+ "required": [
+ "attribute",
+ "offset"
+ ]
+ },
+ {
+ "required": [
+ "attribute",
+ "repeat"
+ ]
+ }
+ ]
+ }
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/featureIdTexture.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/featureIdTexture.schema.json
new file mode 100644
index 0000000000..0f7d1b96f3
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/featureIdTexture.schema.json
@@ -0,0 +1,26 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Feature ID Texture",
+ "type": "object",
+ "allOf": [ { "$ref": "textureInfo.schema.json" } ],
+ "description": "An object describing a texture used for storing per-texel feature IDs.",
+ "properties": {
+ "index": { },
+ "texCoord": { },
+ "propertyTable": {
+ "type": "string",
+ "description": "The ID of the property table in the model's root `EXT_mesh_features.propertyTables` dictionary."
+ },
+ "channel": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Single channel index storing per-texel feature IDs."
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "required": [
+ "propertyTable",
+ "channel"
+ ]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/gltf.EXT_feature_metadata.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/gltf.EXT_feature_metadata.schema.json
new file mode 100644
index 0000000000..a88b5e235c
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/gltf.EXT_feature_metadata.schema.json
@@ -0,0 +1,35 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "EXT_mesh_features glTF extension",
+ "type": "object",
+ "description": "glTF extension that assigns metadata to features in a model.",
+ "properties": {
+ "schema": {
+ "allOf": [ { "$ref": "schema.schema.json" } ],
+ "description": "An object defining classes and enums."
+ },
+ "schemaUri": {
+ "type": "string",
+ "description": "A uri to an external schema file.",
+ "format": "uriref"
+ },
+ "propertyTables": {
+ "type": "object",
+ "description": "A dictionary, where each key is a property table ID and each value is an object defining the property table.",
+ "minProperties": 1,
+ "additionalProperties": {
+ "$ref": "propertyTable.schema.json"
+ }
+ },
+ "propertyTextures": {
+ "type": "object",
+ "description": "A dictionary, where each key is a property texture ID and each value is an object defining the property texture.",
+ "minProperties": 1,
+ "additionalProperties": {
+ "$ref": "propertyTexture.schema.json"
+ }
+ },
+ "extensions": {},
+ "extras": {}
+ }
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/node.EXT_feature_metadata.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/node.EXT_feature_metadata.schema.json
new file mode 100644
index 0000000000..0aa04236a6
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/node.EXT_feature_metadata.schema.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "EXT_mesh_features extension for EXT_mesh_gpu_instancing",
+ "type": "object",
+ "description": "An object describing per-instance feature IDs to be used as indices to property arrays in the property table.",
+ "properties": {
+ "featureIds": {
+ "type": "array",
+ "description": "",
+ "items": {"$ref": "featureIdAttribute.schema.json"},
+ "minItems": 1
+ },
+ "propertyTables": {
+ "type": "array",
+ "description": "An array of IDs of property tables from the root `EXT_mesh_features` object.",
+ "items": {
+ "allOf": [ {"$ref": "glTFid.schema.json" } ]
+ },
+ "minItems": 1
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "required": ["featureIds"]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/primitive.EXT_feature_metadata.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/primitive.EXT_feature_metadata.schema.json
new file mode 100644
index 0000000000..e0f3e6670f
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/primitive.EXT_feature_metadata.schema.json
@@ -0,0 +1,50 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "EXT_mesh_features glTF Primitive extension",
+ "type": "object",
+ "description": "`EXT_mesh_features extension` for a primitive in a glTF model, to associate it with the root `EXT_mesh_features` object.",
+ "properties": {
+ "featureIds": {
+ "type": "array",
+ "description": "",
+ "items": {
+ "oneOf": [
+ {"$ref": "featureIdAttribute.schema.json"},
+ {"$ref": "featureIdTexture.schema.json"}
+ ]
+ },
+ "minItems": 1
+ },
+ "propertyTables": {
+ "type": "array",
+ "description": "An array of IDs of property tables from the root `EXT_mesh_features` object.",
+ "items": {
+ "allOf": [ {"$ref": "glTFid.schema.json" } ]
+ },
+ "minItems": 1
+ },
+ "propertyTextures": {
+ "type": "array",
+ "description": "An array of IDs of property textures from the root `EXT_mesh_features` object.",
+ "items": {
+ "allOf": [ {"$ref": "glTFid.schema.json" } ]
+ },
+ "minItems": 1
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "anyOf": [
+ {
+ "required": [
+ "featureIds",
+ "propertyTables"
+ ]
+ },
+ {
+ "required": [
+ "propertyTextures"
+ ]
+ }
+ ]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTable.property.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTable.property.schema.json
new file mode 100644
index 0000000000..e445747d2b
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTable.property.schema.json
@@ -0,0 +1,36 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Property Table Property",
+ "type": "object",
+ "description": "An array of binary property values.",
+ "properties": {
+ "bufferView": {
+ "allOf": [ { "$ref": "glTFid.schema.json" } ],
+ "description": "The index of the buffer view containing property values. The data type of property values is determined by the property definition: When `type` is `BOOLEAN` values are packed into a bitfield. When `type` is `STRING` values are stored as byte sequences and decoded as UTF-8 strings. When `type` is a numeric type values are stored as the provided `type`. When `type` is `ENUM` values are stored as the enum's `valueType`. Each enum value in the buffer must match one of the allowed values in the enum definition. When `type` is `ARRAY` elements are packed tightly together and the data type is based on the `componentType` following the same rules as above. `arrayOffsetBufferView` is required for variable-size arrays and `stringOffsetBufferView` is required for strings (for variable-length arrays of strings, both are required). The buffer view `byteOffset` must be aligned to a multiple of 8 bytes. If the buffer view's `buffer` is the GLB-stored `BIN` chunk, the byte offset is measured relative to the beginning of the GLB. Otherwise, it is measured relative to the beginning of the buffer."
+ },
+ "offsetType": {
+ "type": "string",
+ "default": "UINT32",
+ "enum": [
+ "UINT8",
+ "UINT16",
+ "UINT32",
+ "UINT64"
+ ],
+ "description": "The type of values in `arrayOffsetBufferView` and `stringOffsetBufferView`."
+ },
+ "arrayOffsetBufferView": {
+ "allOf": [ { "$ref": "glTFid.schema.json" } ],
+ "description": "The index of the buffer view containing offsets for variable-length arrays. The number of offsets is equal to the property table `count` plus one. The offsets represent the start positions of each array, with the last offset representing the position after the last array. The array length is computed using the difference between the current offset and the subsequent offset. If `componentType` is `STRING` the offsets index into the string offsets array (stored in `stringOffsetBufferView`), otherwise they index into the property array (stored in `bufferView`). The data type of these offsets is determined by `offsetType`. The buffer view `byteOffset` must be aligned to a multiple of 8 bytes in the same manner as the main `bufferView`"
+ },
+ "stringOffsetBufferView": {
+ "allOf": [ { "$ref": "glTFid.schema.json" } ],
+ "description": "The index of the buffer view containing offsets for strings. The number of offsets is equal to the number of string components plus one. The offsets represent the byte offsets of each string in the main `bufferView`, with the last offset representing the byte offset after the last string. The string byte length is computed using the difference between the current offset and the subsequent offset. The data type of these offsets is determined by `offsetType`. The buffer view `byteOffset` must be aligned to a multiple of 8 bytes in the same manner as the main `bufferView`."
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "required": [
+ "bufferView"
+ ]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTable.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTable.schema.json
new file mode 100644
index 0000000000..b2e6ddc34b
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTable.schema.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Property Table",
+ "type": "object",
+ "description": "Features conforming to a class, organized as property values stored in columnar arrays.",
+ "properties": {
+ "class": {
+ "type": "string",
+ "description": "The class that property values conform to. The value must be a class ID declared in the `classes` dictionary."
+ },
+ "count": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "The number of features, as well as the number of elements in each property array."
+ },
+ "properties": {
+ "type": "object",
+ "description": "A dictionary, where each key corresponds to a property ID in the class' `properties` dictionary and each value is an object describing where property values are stored. Optional properties may be excluded from this dictionary.",
+ "minProperties": 1,
+ "additionalProperties": {
+ "$ref": "propertyTable.property.schema.json"
+ }
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "required": [
+ "count"
+ ]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTexture.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTexture.schema.json
new file mode 100644
index 0000000000..e4efccaee5
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/propertyTexture.schema.json
@@ -0,0 +1,34 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "title": "Property Texture",
+ "type": "object",
+ "allOf": [ { "$ref": "textureInfo.schema.json" } ],
+ "description": "Features conforming to a class, organized as property values stored in texture channels.",
+ "properties": {
+ "index": { },
+ "texCoord": { },
+ "class": {
+ "type": "string",
+ "description": "The class this property texture conforms to. The value must be a class ID declared in the `classes` dictionary."
+ },
+ "properties": {
+ "type": "object",
+ "description": "A dictionary, where each key corresponds to a property ID in the class' `properties` dictionary and each value describes the texture channels containing property values.",
+ "minProperties": 1,
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "description": "Texture channels containing property values, identified by index."
+ }
+ },
+ "extensions": {},
+ "extras": {}
+ },
+ "required": [
+ "class",
+ "properties"
+ ]
+}
diff --git a/extensions/2.0/Vendor/EXT_mesh_features/schema/schema.schema.json b/extensions/2.0/Vendor/EXT_mesh_features/schema/schema.schema.json
new file mode 100644
index 0000000000..aee0e9c77a
--- /dev/null
+++ b/extensions/2.0/Vendor/EXT_mesh_features/schema/schema.schema.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "https://json-schema.org/draft-04/schema",
+ "title": "Schema",
+ "type": "object",
+ "description": "An object defining classes and enums.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The name of the schema."
+ },
+ "description": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The description of the schema."
+ },
+ "version": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Application-specific version of the schema."
+ },
+ "classes": {
+ "type": "object",
+ "description": "A dictionary, where each key is a class ID and each value is an object defining the class.",
+ "minProperties": 1,
+ "additionalProperties": {
+ "$ref": "class.schema.json"
+ }
+ },
+ "enums": {
+ "type": "object",
+ "description": "A dictionary, where each key is an enum ID and each value is an object defining the values for the enum.",
+ "minProperties": 1,
+ "additionalProperties": {
+ "$ref": "enum.schema.json"
+ }
+ },
+ "extensions": {},
+ "extras": {}
+ }
+}
\ No newline at end of file