diff --git a/glTF/GpuInstancesMetadata/GpuInstancesMetadata.gltf b/glTF/GpuInstancesMetadata/GpuInstancesMetadata.gltf new file mode 100644 index 0000000..20d976e --- /dev/null +++ b/glTF/GpuInstancesMetadata/GpuInstancesMetadata.gltf @@ -0,0 +1,178 @@ +{ + "extensions" : { + "EXT_structural_metadata" : { + "schema" : { + "classes" : { + "exampleMetadataClass" : { + "name" : "Example metadata class", + "description" : "An example metadata class", + "properties" : { + "example_STRING" : { + "name" : "Example STRING property", + "description" : "An example property, with component type STRING", + "type" : "STRING" + } + } + } + } + }, + "propertyTables" : [ { + "name" : "Example property table", + "class" : "exampleMetadataClass", + "count" : 10, + "properties" : { + "example_STRING" : { + "values" : 7, + "stringOffsets" : 8 + } + } + } ] + } + }, + "extensionsUsed" : [ "EXT_structural_metadata", "EXT_mesh_gpu_instancing", "EXT_instance_features" ], + "accessors" : [ { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5125, + "count" : 36, + "type" : "SCALAR", + "max" : [ 23 ], + "min" : [ 0 ] + }, { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 24, + "type" : "VEC3", + "max" : [ 1.0, 1.0, 1.0 ], + "min" : [ 0.0, 0.0, 0.0 ] + }, { + "bufferView" : 2, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 24, + "type" : "VEC3", + "max" : [ 1.0, 1.0, 1.0 ], + "min" : [ -1.0, -1.0, -1.0 ] + }, { + "bufferView" : 3, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 10, + "type" : "VEC3", + "max" : [ 10.0, 10.0, 10.0 ], + "min" : [ 0.0, 0.0, 0.0 ] + }, { + "bufferView" : 4, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 10, + "type" : "VEC4", + "max" : [ 0.733, 0.462, 0.191, 1.0 ], + "min" : [ 0.0, 0.0, 0.0, 0.462 ] + }, { + "bufferView" : 5, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 10, + "type" : "VEC3", + "max" : [ 2.0, 2.0, 2.0 ], + "min" : [ 1.0, 1.0, 1.0 ] + }, { + "bufferView" : 6, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 10, + "type" : "SCALAR", + "max" : [ 9 ], + "min" : [ 0 ] + } ], + "asset" : { + "generator" : "JglTF from https://github.com/javagl/JglTF", + "version" : "2.0" + }, + "buffers" : [ { + "uri" : "data:application/gltf-buffer;base64,AAAAAAIAAAABAAAAAAAAAAMAAAACAAAABAAAAAYAAAAFAAAABAAAAAcAAAAGAAAACAAAAAoAAAAJAAAACAAAAAsAAAAKAAAADAAAAA4AAAANAAAADAAAAA8AAAAOAAAAEAAAABIAAAARAAAAEAAAABMAAAASAAAAFAAAABYAAAAVAAAAFAAAABcAAAAWAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAACAPwAAgD8AAIA/AAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAA", + "byteLength" : 720 + }, { + "uri" : "data:application/gltf-buffer;base64,AAAAAAAAAAAAAAAA5DiOP+Q4jj/kOI4/5DgOQOQ4DkDkOA5AVlVVQFZVVUBWVVVA5DiOQOQ4jkDkOI5AHcexQB3HsUAdx7FAVlXVQFZV1UBWVdVAjuP4QI7j+ECO4/hA5DgOQeQ4DkHkOA5BAAAgQQAAIEEAACBBAAAAAAAAAAAAAAAAAACAP92ZzD0Q9YA9B0HVPHcffj/QGUs+AAMAPrywUz3rhHg/HXaWPuWqPT4f05w9Y0VvP3UqxT6+ing+IIHNPZiDYj+d+vA+w+KXPqEr+z1ub1I/DaEMP/RFsT6bkxI+REU/P9m0Hj+hD8g+H2slPgpNKT/WdC4/P+rbPqHVNT462RA/46U7P0SL7D6BlUM+RIvsPgAAgD8AAIA/AACAP+Q4jj/kOI4/5DiOP8dxnD/HcZw/x3GcP6uqqj+rqqo/q6qqP47juD+O47g/juO4P3Icxz9yHMc/chzHP1ZV1T9WVdU/VlXVPzmO4z85juM/OY7jPxzH8T8cx/E/HMfxPwAAAEAAAABAAAAAQAkACAAHAAYABQAEAAMAAgABAAAA", + "byteLength" : 420 + }, { + "uri" : "data:application/gltf-buffer;base64,emVyb29uZXR3b3RocmVlZm91cmZpdmVzaXhzZXZlbmVpZ2h0bmluZQAAAAAEAAAABwAAAAoAAAAPAAAAEwAAABcAAAAaAAAAHwAAACQAAAAoAAAA", + "byteLength" : 84 + } ], + "bufferViews" : [ { + "buffer" : 0, + "byteOffset" : 0, + "byteLength" : 144, + "target" : 34963 + }, { + "buffer" : 0, + "byteOffset" : 144, + "byteLength" : 288, + "target" : 34962 + }, { + "buffer" : 0, + "byteOffset" : 432, + "byteLength" : 288, + "target" : 34962 + }, { + "buffer" : 1, + "byteOffset" : 0, + "byteLength" : 120 + }, { + "buffer" : 1, + "byteOffset" : 120, + "byteLength" : 160 + }, { + "buffer" : 1, + "byteOffset" : 280, + "byteLength" : 120 + }, { + "buffer" : 1, + "byteOffset" : 400, + "byteLength" : 20 + }, { + "buffer" : 2, + "byteOffset" : 0, + "byteLength" : 40 + }, { + "buffer" : 2, + "byteOffset" : 40, + "byteLength" : 44 + } ], + "meshes" : [ { + "primitives" : [ { + "attributes" : { + "POSITION" : 1, + "NORMAL" : 2 + }, + "indices" : 0, + "mode" : 4 + } ] + } ], + "nodes" : [ { + "extensions" : { + "EXT_mesh_gpu_instancing" : { + "attributes" : { + "TRANSLATION" : 3, + "ROTATION" : 4, + "SCALE" : 5, + "_FEATURE_ID_0" : 6 + } + }, + "EXT_instance_features" : { + "featureIds" : [ { + "featureCount" : 10, + "attribute" : 0, + "propertyTable" : 0 + } ] + } + }, + "mesh" : 0 + } ], + "scene" : 0, + "scenes" : [ { + "nodes" : [ 0 ] + } ] +} \ No newline at end of file diff --git a/glTF/GpuInstancesMetadata/README.md b/glTF/GpuInstancesMetadata/README.md new file mode 100644 index 0000000..ce2af6b --- /dev/null +++ b/glTF/GpuInstancesMetadata/README.md @@ -0,0 +1,112 @@ +# Metadata for GPU instances + +An example showing how to assign metadata to GPU instances. + +The example combines three different extensions: + +- It uses `EXT_mesh_gpu_instancing` to create 10 GPU-based instances +- It uses `EXT_instance_features` to assign feature IDs to these instances +- It uses `EXT_structural_metadata` to define a property table with 10 rows, which can be looked up based on the feature IDs. + +## Screenshot + +![Image](screenshot/GpuInstancesMetadata.gif) + +## Example Sandcastle + +```JavaScript +const viewer = new Cesium.Viewer("cesiumContainer"); + +// Create the tileset, and move it to a certain position on the globe +const tileset = viewer.scene.primitives.add( + new Cesium.Cesium3DTileset({ + url: `http://localhost:8003/glTF/GpuInstanceMetadata/tileset.json`, + debugShowBoundingVolume: true, + }) +); +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), + 40.0 +); +viewer.zoomTo(tileset, offset); + +// Create an HTML element that will serve as the +// tooltip that displays the feature information +function createTooltip() { + const tooltip = document.createElement("div"); + viewer.container.appendChild(tooltip); + tooltip.style.backgroundColor = "black"; + tooltip.style.position = "absolute"; + tooltip.style.left = "0"; + tooltip.style.top = "0"; + tooltip.style.padding = "14px"; + tooltip.style["pointer-events"] = "none"; + tooltip.style["block-size"] = "fit-content"; + return tooltip; +} +const tooltip = createTooltip(); + +// Show the given HTML content in the tooltip +// at the given screen position +function showTooltip(screenX, screenY, htmlContent) { + tooltip.style.display = "block"; + tooltip.style.left = `${screenX}px`; + tooltip.style.top = `${screenY}px`; + tooltip.innerHTML = htmlContent; +} + +// Create an HTML string that contains information +// about the given feature, under the given title +function createFeatureHtml(title, feature) { + if (!Cesium.defined(feature)) { + return `(No ${title})
`; + } + const propertyKeys = feature.getPropertyIds(); + if (!Cesium.defined(propertyKeys)) { + return `(No properties for ${title})
`; + } + let html = `${title}:
`; + for (let i = 0; i < propertyKeys.length; i++) { + const propertyKey = propertyKeys[i]; + const propertyValue = feature.getProperty(propertyKey); + html += `  ${propertyKey} : ${propertyValue}
`; + } + return html; +} + +// Given an object that was obtained via Scene#pick: If it is +// a Cesium3DTileFeature, then it is returned. +// Otherwise, 'undefined' is returned. +function obtainFeature(picked) { + if (!Cesium.defined(picked)) { + return undefined; + } + const isFeature = picked instanceof Cesium.Cesium3DTileFeature; + if (!isFeature) { + return undefined; + } + return picked; +} + +// Install the handler that will perform picking when the +// mouse is moved, and update the label entity when the +// mouse is over a Cesium3DTileFeature +const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); +handler.setInputAction(function (movement) { + let tooltipText = ""; + const picked = viewer.scene.pick(movement.endPosition); + const feature = obtainFeature(picked); + tooltipText += createFeatureHtml("Feature", feature); + const screenX = movement.endPosition.x; + const screenY = movement.endPosition.y; + showTooltip(screenX, screenY, tooltipText); +}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); +``` + +## License + +[CC0](https://creativecommons.org/share-your-work/public-domain/cc0/) diff --git a/glTF/GpuInstancesMetadata/screenshot/GpuInstancesMetadata.gif b/glTF/GpuInstancesMetadata/screenshot/GpuInstancesMetadata.gif new file mode 100644 index 0000000..d183b4d Binary files /dev/null and b/glTF/GpuInstancesMetadata/screenshot/GpuInstancesMetadata.gif differ diff --git a/glTF/GpuInstancesMetadata/tileset.json b/glTF/GpuInstancesMetadata/tileset.json new file mode 100644 index 0000000..552ccdf --- /dev/null +++ b/glTF/GpuInstancesMetadata/tileset.json @@ -0,0 +1,20 @@ +{ + "asset" : { + "version" : "1.1" + }, + "geometricError" : 100.0, + "root" : { + "content" : { + "uri" : "GpuInstancesMetadata.gltf" + }, + "boundingVolume" : { + "box" : [ + 6.707386, -5.8532143, 5.8532143, + 6.707386, 0.0, 0.0, + 0.0, -5.8532143, 0.0, + 0.0, 0.0, 5.8532143 + ] + }, + "geometricError" : 0.0 + } +} \ No newline at end of file diff --git a/glTF/README.md b/glTF/README.md index e91817e..447f493 100644 --- a/glTF/README.md +++ b/glTF/README.md @@ -1,15 +1,27 @@ # Samples for glTF extensions +The following is a list of samples for different glTF extensions that are supported by Cesium. Each directory contains a dedicated `.gltf` file that contains the actual glTF asset. Additionally, each directory also contains a simple `tileset.json` file that is a [3D Tiles](https://github.com/CesiumGS/3d-tiles) tileset which just contains the respective glTF asset as its only content. These tilesets can be viewed in CesiumJS, by hosting the base directory of this repository on a local server. + +### `EXT_mesh_features` + The [`EXT_mesh_features`](https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_mesh_features) extension is a glTF 2.0 extension that allows identifying geometry or subcomponents of geometry in glTF 2.0 assets as individual 'features', by associating them with a feature ID. +The sandcastle code for viewing the `EXT_mesh_features` samples is shown in [glTF-Mesh-Features-Samples-Sandcastle.js](glTF-Mesh-Features-Samples-Sandcastle.js) + | Sample | Screenshot | |:---|:--:| | [`FeatureIdAttribute`](EXT_mesh_features/FeatureIdAttribute/)
Uses an attribute of a mesh primitive to assign feature IDs to vertices | | [`FeatureIdTexture`](EXT_mesh_features/FeatureIdTexture/)
Uses a feature ID texture to assign feature IDs to texels on the surface of the geometry | + +### `EXT_structural_metadata` + The [`EXT_structural_metadata`](https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata) extension is a glTF 2.0 extension that allows storing structured metadata in glTF 2.0 assets in the form of _property tables_. Together with the [`EXT_mesh_features`](https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_mesh_features) extension, the metadata can be looked up in these tables, using the feature IDs. +The sandcastle code for viewing the `EXT_structural_metadata` samples is shown in [glTF-Structural-Metadata-Samples-Sandcastle.js](glTF-Structural-Metadata-Samples-Sandcastle.js) + + | Sample | Screenshot | |:---|:--:| | [`FeatureIdAttributeAndPropertyTable`](EXT_structural_metadata/FeatureIdAttributeAndPropertyTable/)
Vertices that are associated with properties that are stored in a property table | @@ -20,12 +32,10 @@ The [`EXT_structural_metadata`](https://github.com/CesiumGS/glTF/tree/3d-tiles-n | [`ComplexTypes`](EXT_structural_metadata/ComplexTypes/)
Features that contain properties with more complex types | | [`SimplePropertyTexture`](EXT_structural_metadata/SimplePropertyTexture/)
Properties that are stored in a texture | -Each directory contains a dedicated `.gltf` file that contains the actual glTF asset. Additionally, each directory also contains a simple `tileset.json` file that is a [3D Tiles](https://github.com/CesiumGS/3d-tiles) tileset which just contains the respective glTF asset as its only content. These tilesets can be viewed in CesiumJS, by hosting the base directory of this repository on a local server, and using the following Cesium Sandcastle code: - -## Common Sandcastle Code -The sandcastle code for viewing the `EXT_mesh_features` samples is shown in [glTF-Mesh-Features-Samples-Sandcastle.js](glTF-Mesh-Features-Samples-Sandcastle.js) - -The sandcastle code for viewing the `EXT_structural_metadata` samples is shown in [glTF-Structural-Metadata-Samples-Sandcastle.js](glTF-Structural-Metadata-Samples-Sandcastle.js) +### Other glTF extensions +| Sample | Screenshot | +|:---|:--:| +| [`GpuInstancesMetadata`](GpuInstancesMetadata/)
An example that uses `EXT_mesh_gpu_instancing` to create GPU instances that are associated with feature IDs, which are used for looking up metadata in a property table |