Gltf feature extensions support in Cesium, EXT_mesh_features

I am working on custom 3d tiles using CesiumJS, my tileset.json can already loaded to cesium. I am using 3d-tiles-tools to convert the gltf to glb and tileset.json. My model is the power line which is drawn by 11 cartesian coordinates.

I want to use the 3d tiles style to change the color of the tileset.

To my understanding, I could embed the metadata using the EXT_mesh_features to make those metadata pointing to relevant mesh in gltf.

The issue I had is :
1. it seems it couldn’t recognize as 3d tiles when I use the mouse event to console log it
2. the undefined in the 3d tiles style applies, I guess it is not recognize any of the metadata.

Please see the sandcastle example, files can also download to view from here: files

The following is how I use the 3d tiles style

const styleByVoltage = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ["${Voltage} === undefined", "color('yellow')"], // Show tiles where Voltage is 240 or higher
            ["${Voltage} > 1200", "color('red')"], // Show tiles where Voltage is 240 or higher
            ["true", "color('blue')"], // Hide all other tiles
        ],
    },
});

I think it might also related in github, cesium community.

It may be necessary to provide a bit more context and information about the goals.


You mentioned metadata and the EXT_mesh_features extension. But the EXT_mesh_features extension does not allow you to assign metadata directly. It only allows you to assign IDs (identifiers) to subcomponents of a glTF asset. For example, in the FeatureIdAttribute example of the 3D Tiles Samples, you have one glTF asset with four mesh primitives, and each mesh primitive receives its own ID.

(You can later use this ID to look up metadata, maybe in a local database or so. But the IDs themself are not really “metadata” in the broader sense)


The extension that is more related to metadata is the EXT_structural_metadata extension. This one allows you to assign (arbitrary) metadata to subcomponents of a glTF asset. For example, in the FeatureIdAttributeAndPropertyTable example of the 3D Tiles Samples, you have one glTF asset with four mesh primitives, and each mesh primitive receives its own (structured) metadata.


But it’s not clear whether you even need or want the glTF metadata extensions at all. When you mention 3D Tiles and styling and the goal to show/hide tiles, then I’ll have to ask:

To which elements exactly do you want to assign the metadata?

If you want to assign metadata to a tile (i.e. one glTF asset as a whole), then you may not even need the glTF extensions. You can just assign metadata to the tile itself (or the tile content). This is demonstated in the MetadataGranularities example of the 3D Tiles samples.

(The glTF extensions are only necessary when you want to assign metadata to subcomponents of a glTF. For example, when you have one glTF asset that represents a house, and you want to assign metadata to parts of this house, like the door or the roof…)

Thanks for the reply. My task is to create 3d tiles for power line network, the data is 11 points coordinates of a power line. A set of power line is called a bay. So different bay may have different voltage, I need to be able to color it differently for different voltage or toggle show/hide.

To be more specific of my status, I am creating the gltf code for each tile at certain level e.g. level 17. So each tile may have multiple power lines with different voltages, and every power line of a tile is store at the mesh part. The next step I want to embed the metadata into it, so I could use 3d tiles style to color it or show/hide it.

For the EXT_mesh_features, I would like to confirm if this approach works. In the gltf using EXT_mesh_features to assign featureId to it then use EXT_structual_metadata to make featureId pointing to the corresponding metadata(property table), then Cesium could use 3d style to do the color or show/hide feature.

Thanks again, and if you have any ideas/comment please share with me.

For the EXT_mesh_features, I would like to confirm if this approach works. In the gltf using EXT_mesh_features to assign featureId to it then use EXT_structual_metadata to make featureId pointing to the corresponding metadata(property table), then Cesium could use 3d style to do the color or show/hide feature.

This should technically be possible, yes, but I have to admit that I don’t have an example of using the glTF metadata for styling. (I could try to allocate some time to create one or provide further details, if necessary)

One important aspect of my question was related to the granularity of the metadata that you need. The glTF feature ID- and metadata extensions are really intended for fine-grained metadata. For example, when you have a glTF with hundreds of mesh primitives, and want to identify each of them. Generating that data may be more effort than just putting the metadata into the tileset JSON.

For example: When you have tow ‘bays’/power lines, which are relatively simple geometry data, then you can just store each ‘bay’ in one glTF asset, and refer to multiple glTF assets in each tile, and associate each content with metadata:

  "root" : {
    "contents" : [ {
      "uri" : "bayA.glb"
      "metadata" : {
        "class" : "powerLineMetadataClass",
        "properties" : {
          "voltage" : 1234
        }
      }
    }, {
      "uri" : "bayB.glb"
      "metadata" : {
        "class" : "powerLineMetadataClass",
        "properties" : {
          "voltage" : 2345
        }
      }
    } ],
...

This might be easier to handle than combining the data of multiple ‘bays’ in one glTF file and differentiating them with different feature IDs.

But note that this is an engineering question with various trade-offs, and I can not give any “recommentations” here (without knowing many details and the exact requirements of the application). I’m just mentioning this to make sure that you have all the options on the radar when making a decision.

Thanks for the help, it seems that storing metadata in the tileset will be an easier way to achieve it, I will give it a try.

I still have issue with using 3D Tiles Style. Here is the full code sandcastle example

The issue is the tileset is loaded shown blue color, which didn’t read the metadata of the tileset.

I have referred to tileset metadata github for the structure.
This is my tileset.json

{
    "asset": {
        "version": "1.1"
    },
    "schema": {
        "id": "MetadataGranularitiesSchema",
        "classes": {
            "tileMetadataClass": {
                "name": "Example group metadata class",
                "description": "An example metadata class for tile content groups",
                "properties": {
                    "Voltage": {
                        "description": "The voltage level of the tile",
                        "type": "SCALAR",
                        "componentType": "UINT16"
                    },
                    "Bay_ID": {
                        "description": "The bay ID of the tile",
                        "type": "SCALAR",
                        "componentType": "UINT16"
                    }
                }
            }
        }
    },
    "geometricError": 4096,
    "root": {
        "transform": [
            0.999999998880564, 0.000033309074011000916, 0.00003360622448067563,
            0, -0.00003330879588167579, 0.999999999411011,
            -0.000008276648995997338, 0, -0.00003360650014849753,
            0.000008275529603918308, 0.9999999994010598, 0, -3940390.342907967,
            2528030.3842752655, -4317194.989552261, 1
        ],
        "boundingVolume": {
            "box": [
                19.497575283050537, 130.0726203918457, 45.48931884765625,
                6.415228366851807, 0, 0, 0, -5.727855682373047, 0, 0, 0,
                23.33812713623047
            ]
        },
        "geometricError": 512,
        "refine": "ADD",
        "contents": [
            {
                "uri": "48353.glb",
                "metadata": {
                    "class": "tileMetadataClass",
                    "properties": {
                        "Voltage": 1245,
                        "Bay_ID": 1111
                    }
                }
            }
        ]
    }
}

This is how I loaded in Cesium. P.S.: tried "${tileMetadataClass.Voltage} === 1245" and "${Voltage} === 1245" for the condition

// Define a styling function
const styleByVoltage = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ["${tileMetadataClass.Voltage} === 1245", "color('red')"],
            ["${Bay_ID} === 1111", "color('red')"], 
            ["true", "color('blue')"],
        ],
    },
});

async function staticTilesetLoading() {
    try {
        const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(2418517);
        viewer.scene.primitives.add(tileset);
        tileset.style = styleByVoltage;
        viewer.zoomTo(tileset);
    } catch (error) {
        console.error("Error loading tileset:", error);
    }
}

staticTilesetLoading();

Sorry, it looks like styling based on metadata currently has some limitations. More specifically, it looks like a bug in CesiumJS. I opened Styling based on metadata is not applied · Issue #11758 · CesiumGS/cesium · GitHub to keep track of this.