Best practices for tileset and glTF structure and embedding metadata

Usually, models of buildings tend to be “relatively simple” in terms of complexity of the geometry (iff they are created with a CAD/editing program, and not from some high-res point cloud scan or so!). When there are some high-resolution textures, or some complex interiors (chairs, tables…), then this may bloat the data quickly, but … for example, each of the houses in the MetadataGranularities sample is in the order of 50KB. If this complexity becomes an issue, one could think about different forms of LOD (or even “application-specific logic” for showing/hiding certain parts of the data).

When exporting from Blender there is an option to export the assigned metadata within the glTF.

I don’t know much of the relevant background here (e.g. details of Blender, Shapefiles, the specific Plugin, and the steps for transporting that data into glTF). When you say that this becomes “metadata within the glTF”, then I have to ask specifically: This is the information that is currently stored in the extras, right?

So roughly speaking something along the lines of: Loop threw the glTF; get the metadata; create a tileset; store the metadata in the tileset; clean up the glTF

Something like this could be possible relatively easily, with 3d-tiles-tools and glTF-Transform. This would involve potentially highly specific custom code (that, in the case of the 3d-tiles-tools, will have to use elements that are not a “public API”). But that could be OK to get a better idea for the “best” approach for all this.

This is because we only need the relevant IDs to query the detailed and up-to-date data from our backend plus information which object is on which floor.

When the main goal is to have “identifiable things” in the tileset, then a pragmatic “ID string” (that is used for looking up the additional data) could indeed be the easiest solution.

After (hopefully) clarifying your questions, would you consider the above or a similar approach as fitting for our use case?

From what you said until now, this does sound like a viable approach. And as you already figured out: The MetadataGranuarities sample may provide some inspiration and some possible example structures here, because … it might, in fact, be very close to what you’re trying to do, even though it’s only a very simple example for demonstrating some options for assigning metadata in general.

To emphasize this again: There are some degrees of freedom for the exact structure. Basically:

How will the ‘real-world’ structure of “compus/buildings/rooms” be mapped to the structure of “tileset/tile/content” (and their metadata)?

And I can not give specific recommendations here, because there are still some unknowns. But I think that you are aware of some of the degrees of freedom and the options now, and maybe a “good” solution can be found by trying out some options (unless “The Deadline” is ‘tomorrow’ - then you’d just “quickly try to make something that works” :wink: )

The next questions already refer to some of these options, more specifically:

Do child tilesets inherit the schema of the parent tileset, so we’d only need to define a schema in the ‘master’ tileset? Or if not, can a tileset’s schema be imported or does it have to be explicitly written in every tileset using it?

They do not automatically inherit the schema. But the schema can either be given directly in the schema property of a tileset, or referred to by the schemaUri property of a tileset. So you could store the schema only once, in a schema.json, and then refer to this file, from each tileset, by just saying schemaUri: "schema.json" in each tileset.

An aside: The schema itself will probably be relatively simple. From what you said until now, it could probably just be something like

{
  "id": "CAMPUS_SCHEMA",
  "classes" : {
    "campusElement" : {
      "properties" : {
        "id" : {
          "type" : "STRING"
        },
        "floor" : {
          "type" : "SCALAR",
          "componentType" : "INT8"
        }
      }
    }
  }
}

Each “metadata entity” (in a tileset, tile, or content) could then just be

"metadata" : {
  "class" : "campusElement",
  "properties" : {
    "id" : "ABC-123-XYZ,
    "floor" : 2
  }
}

I found the samples repo, which is very helpful! But I can not get the MetadataGranularities sample to work. Since the picked variable in line 67 yields undefined. Do you see what the problem is?

I just tried it out, with the example sandcastle that is given in the README.md of this sample, and it seemed to work for me. The picked variable will be undefined when the mouse is not hovering over anything that can be ‘picked’. The subsequent lines already anticipate that. The ? question marks in
const tileMetadata = picked?.content?.tile?.metadata;
are optional chaining, which means that this line is equivalent to

let tileMetadata = undefined;
if (picked !== undefined) {
  if (picked.content !== undefined) {
    if (picked.content.tile !== undefined) {
      tileMetadata = picked.content.tile.metadata;
    }
  }
}

in a more concise form.

Also in the tileset sometimes ‘contents’ instead of ‘content’ is used, but I think the latter is correct?

Both is correct. A tile may have a single content object, or a contents array, to refer to multiple contents.

And some children have no content property at all.

Some tiles/children may not have content for various reasons - for example, when the tile only serves as a “node” to represent a hierarchical structure, like (pseudocode)

buildingTile {
    // This "building tile" ITSELF does not have "content".
    // It only combines the "rooms", where each "room" has a content:
    children: [
        roomTile.content.uri = "roomA.glb",
        roomTile.content.uri = "roomB.glb",
        roomTile.content.uri = "roomC.glb",
    }
}

Is metadata a property of content or a ‘standalone’ property?

I’m not sure what ‘standalone’ means here. But…

The idea is exactly to be able to define metadata with different granularities - from coarse-grained (for the whole tileset) down to fine-grained (for each content).


Edit: You mentioned that it should be possible to show/hide certain elements (based on the user interaction). There was a question at How to filter 3D tiles by group defined in 3DTILES_metadata Extension or 3dtiles 1.1? - #2 by Marco13 that contains an example of how to show/hide elements based on metadata. But a strong disclaimer: The approach that is presented in this sandcastle might not be the best solution in your case (depending on the actual, final data structures and the desired user interaction). It will not scale very well when there are, for example, many different conditions for whether an element should be rendered or not. An alternative could be to apply the styling by accessing metadata properties directly in the Cesium3DTileStyle. But it might still be worth a look…

1 Like