An example that shows how to combine different features of the EXT_structural_metadata
and 3D Tiles.
The example uses a single metadata schema, as defined in the 3D Metadata Specification. The schema is stored in a MetadataSchema.json
file, and defines a metadata class with two properties:
- an
intensity
property, which is a single floating point value - a
classification
property, which is an enum withMediumVegetation
andBuildings
as its values
This schema file is referred to by glTF assets that use the EXT_structural_metadata
extension, and by the 3D Tiles tileset that contains these glTF assets.
The glTF assets are simple point clouds, with property attributes that contain the metadata values for the schema: Each point is assigned an intensity
and a classification
value.
The 3D Tiles tileset contains metadata statistics for the metadata from the glTF assets. These statistics contain, for example, the minimum and maximum intensity
value, and the number of occurences for each classification
value.
The following sandcastle can be used to render this sample, and allows selecting different custom shaders for visualizing the metadata:
const viewer = new Cesium.Viewer("cesiumContainer");
// Load the tileset from a local server
const tileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: `http://localhost:8003/glTF/EXT_structural_metadata/PropertyAttributesPointCloud//tileset.json`,
debugShowBoundingVolume: true,
})
);
// Move the tileset to a certain position on the globe,
// and zoom the viewer to the tileset
tileset.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(-75.152325, 39.94704, 0)
);
const offset = new Cesium.HeadingPitchRange(
Cesium.Math.toRadians(-22.5),
Cesium.Math.toRadians(-22.5),
32.0
);
viewer.zoomTo(tileset, offset);
// The dictionary of shaders that can be selected from the sandcastle menu:
const shaders = {
// No custom shader, for default rendering
NO_SHADER: undefined,
// The shader that uses the `intensity` value from the metadata
// and uses this as a (grayscale) color for the rendered points
INTENSITY_SHADER: new Cesium.CustomShader({
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material)
{
float intensity = fsInput.metadata.intensity;
material.diffuse = vec3(intensity);
}
`,
}),
// The shader that uses the `classification` value from the metadata
// and uses this to select a color for rendering the points.
// NOTE: The classification attribute is accessed in the vertex
// shader here. When it is accessed in the fragment shader, it
// may not have exactly the expected value. This is tracked in
// https://github.com/CesiumGS/cesium/issues/10699
CLASSIFICATION_SHADER: new Cesium.CustomShader({
varyings: {
v_color: Cesium.VaryingType.VEC3,
},
vertexShaderText: `
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
int classification = int(vsInput.attributes.classification);
vec3 color = vec3(1);
if (classification == 0) {
color = vec3(0,0.5,0);
}
else if (classification == 1) {
color = vec3(0.5,0.5,0.5);
}
v_color = color;
}`,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material)
{
material.diffuse = v_color;
}
`,
}),
};
// The Sandcastle UI setup: Create a menu for selecting the custom shaders
Sandcastle.addToolbarMenu([
{
text: "Default View",
onselect: function () {
tileset.customShader = shaders.NO_SHADER;
},
},
{
text: "Intensity",
onselect: function () {
tileset.customShader = shaders.INTENSITY_SHADER;
},
},
{
text: "Classification",
onselect: function () {
tileset.customShader = shaders.CLASSIFICATION_SHADER;
},
},
]);