Test gltf examples for 3D tiles 1.1

I noticed that many tilesets and examples still use legacy formats like b3dm which are deprecated with 3D Tiles v. 1.1. In an effort to start collecting more examples which exclusively uses glTF, I found that @Marco13’s great 3d-tiles-tools includes an upgrade tool to v. 1.1 and comes with a number of test tilesets. Please find those tests converted to v. 1.1 here:

Hopefully this can be useful for others.

A bit more context, for others who might just stumble over this: As mentioned in the README.md of the test data directory: The input data for these tests has been taken from the specs/unit tests data of CesiumJS, which contains many more test tilesets for 3D Tiles 1.0.

The output data (i.e. the same data sets, converted to 3D Tiles 1.1) are currently not checked in the 3d-tiles-tools repository. They are only generated temporarily, when running the tests - in particular, the tests for the upgrade function of the 3D Tiles Tools.

But indeed, these examples might be useful for people who want to develop a 3D Tiles renderer, and are looking for different flavors of “simple” 3D Tiles 1.1 data sets.

1 Like

Thanks. I may actually add more conversions. Some may not be supported by tools:

EastNorthUpContent already v.1.1 but add for completeness
GeoJson not handled by 3d-tiles-tools upgrade
Geometry not handled by 3d-tiles-tools upgrade
GltfContent trivial but add
GltfContentWithCopyright/glTF trivial but add
GltfContentWithRepeatedCopyrights/glTF trivial but add
Hierarchy add but uncommon
Implicit already v.1.1 but b3dm
Metadata already v.1.1 but b3dm
MultipleContents already v.1.1 but b3dm et al.
Tilesets add
Vector vctr not handled
Voxel already v.1.1

There probably are different ways of how this could be structured and offered. Eventually, there may be an overlap to 3d-tiles-samples, which right now, focusses on “hand-crafted” test cases. (One could say that these are less “unit tests”, but a bit more “integration tests”).

(There also is an old project, 3d-tiles-samples-generator, which was once created in order to create many of the CesiumJS spec data sets…)

Regarding the examples that you listed:

Some of them could be upgraded (e.g. the ones that are using B3DM, and which could use glTF instead).

Things like GeoJSON and VCTR are indeed not supported by the 3D Tiles Tools. One could consider some form of handling them. But VCTR is not widely used, and may therefore not warrant dedicated development effort for an “upgrade” functionality. And GeoJSON is potentially pretty complex, and might better be tackled as some “GeoJSON-to-glTF” library, which then could be pulled in as a dependency.

For the (Batch Table) Hierarchy, it could be interesting to look for some generic solution about how this functionality could be mapped to the new metadata extensions. But similar to VCTR, this was not widely adopted, and there probably isn’t much actual demand for automatically upgrading that to glTF…

Thanks for the pointers.

3d-tiles-samples 1.1
has v.1.1 only using glTF

3d-tiles-samples glTF
has v.1.1 only using glTF with glTF extensions.

3d-tiles-samples 1.0
has additional conversion 1.0 targets which may not be covered elsewhere:

I batch converted most listed examples. The conversions are available in the output* directories here:

Some failed, see below for a complete list. These are probably all expected.
These are not necessarily intended for tools tests and there was no actual testing if the completed conversions were successful and actually work with Cesium or another viewer.

Direct access may work though https://raw.githubusercontent.com as in:

https://raw.githubusercontent.com/andreasplesch/3d-tiles-tools/refs/heads/gltf_examples/specs/data/migration/output/Batched/BatchedAnimated/tileset.json

or similar services.

I may collect those in a dedicated repo, along with other v1.1 glTF examples since this is not directly related 3d-tiles-tools development.

Pointers to other examples welcome.

List of incomplete upgrades:

converting ./Voxel/VoxelCylinder3DTiles/tileset.json
[17:28:23.842] ERROR (CLI): contentAvailabilities is not iterable
    err: {
      "type": "TypeError",
      "message": "contentAvailabilities is not iterable",
      "stack":
          TypeError: contentAvailabilities is not iterable
              at Function.create (/workspaces/3d-tiles-tools/src/tilesets/implicitTiling/SubtreeInfos.ts:110:41)
..
converting ./Voxel/VoxelBox3DTiles/tileset.json
[17:28:41.606] ERROR (CLI): contentAvailabilities is not iterable
    err: {
      "type": "TypeError",
      "message": "contentAvailabilities is not iterable",
      "stack":
          TypeError: contentAvailabilities is not iterable
              at Function.create (/workspaces/3d-tiles-tools/src/tilesets/implicitTiling/SubtreeInfos.ts:110:41)
...
converting ./Voxel/VoxelEllipsoid3DTiles/tileset.json
[17:28:50.512] ERROR (CLI): contentAvailabilities is not iterable
    err: {
      "type": "TypeError",
      "message": "contentAvailabilities is not iterable",
      "stack":
          TypeError: contentAvailabilities is not iterable
              at Function.create (/workspaces/3d-tiles-tools/src/tilesets/implicitTiling/SubtreeInfos.ts:110:41)
...
converting ./TilesetWithTreeBillboards/tileset.json
[17:41:24.482] ERROR (upgrade): Failed to upgrade tree_billboard.i3dm: Error: Missing required extension, "KHR_techniques_webgl".

---

converting ./Implicit/ImplicitTilesetWithJsonSubtree/tileset_1.0.json
[17:49:33.654] WARN (tilesetProcessing): No input found for content/{level}/{x}/{y}.b3dm
[17:49:33.657] WARN (tilesetProcessing): No content/{level}/{x}/{y}.b3dm found in input
[17:49:33.668] INFO (CLI): Total: 18.566 ms

converting ./Implicit/ImplicitChildTile/tileset_1.0.json
[17:49:41.982] WARN (tilesetProcessing): No input found for content/{level}/{x}/{y}.b3dm
[17:49:41.983] WARN (tilesetProcessing): No content/{level}/{x}/{y}.b3dm found in input
[17:49:41.985] INFO (CLI): Total: 11.286 ms

converting ./Implicit/ImplicitTileset/tileset_1.0.json
[17:49:58.335] WARN (tilesetProcessing): No input found for content/{level}/{x}/{y}.b3dm
[17:49:58.335] WARN (tilesetProcessing): No content/{level}/{x}/{y}.b3dm found in input
[17:49:58.343] INFO (CLI): Total: 14.511 ms

converting ./Implicit/ImplicitRootTile/tileset_1.0.json
[17:50:06.658] WARN (tilesetProcessing): No input found for content/{level}/{x}/{y}.b3dm
[17:50:06.660] WARN (tilesetProcessing): No content/{level}/{x}/{y}.b3dm found in input

converting ./Metadata/ImplicitTileMetadata/tileset_1.0.json
[17:50:49.811] WARN (tilesetProcessing): No input found for content/{level}/{x}/{y}.b3dm
[17:50:49.812] WARN (tilesetProcessing): No content/{level}/{x}/{y}.b3dm found in input
[17:50:49.824] INFO (CLI): Total: 18.637 ms

converting ./Metadata/ImplicitSubtreeMetadata/tileset_1.0.json
[17:51:32.078] WARN (tilesetProcessing): No input found for content/{level}/{x}/{y}.b3dm
[17:51:32.079] WARN (tilesetProcessing): No content/{level}/{x}/{y}.b3dm found in input

converting ./Metadata/ImplicitContentMetadata/tileset_1.0.json
[17:52:23.947] WARN (tilesetProcessing): No input found for content/{level}/{x}/{y}.b3dm
[17:52:23.947] WARN (tilesetProcessing): No content/{level}/{x}/{y}.b3dm found in input

---

converting ./Implicit/ImplicitChildTile/tileset_1.1.json
[17:56:09.001] ERROR (CLI): Could not resolve subtree URI subtrees/0/0/0.subtree that was created from template URI subtrees/{level}/{x}/{y}.subtree for coordinates (level 0, (0,0))
    err: {
      "type": "ImplicitTilingError",
      "message": "Could not resolve subtree URI subtrees/0/0/0.subtree that was created from template URI subtrees/{level}/{x}/{y}.subtree for coordinates (level 0, (0,0))",
      "stack":
          Error: Could not resolve subtree URI subtrees/0/0/0.subtree that was created from template URI subtrees/{level}/{x}/{y}.subtree for coordinates (level 0, (0,0))
              at Function.resolve (/workspaces/3d-tiles-tools/src/tilesets/traversal/SubtreeModels.ts:74:13)
     ...
converting ./Implicit/ImplicitMultipleContents/tileset_1.1.json
[17:56:17.260] ERROR (CLI): The root of the implicit tileset did not define a template URI
    err: {
      "type": "ImplicitTilingError",
      "message": "The root of the implicit tileset did not define a template URI",
      "stack":
          Error: The root of the implicit tileset did not define a template URI
              at ImplicitTraversedTile.getRawContents (/workspaces/3d-tiles-tools/src/tilesets/traversal/ImplicitTraversedTile.ts:362:17)
...
converting ./Implicit/ImplicitRootTile/tileset_1.1.json
[17:56:35.712] ERROR (CLI): Could not resolve subtree URI subtrees/0/0/0/0.subtree that was created from template URI subtrees/{level}/{x}/{y}/{z}.subtree for coordinates (level 0, (0,0,0))
    err: {
      "type": "ImplicitTilingError",
      "message": "Could not resolve subtree URI subtrees/0/0/0/0.subtree that was created from template URI subtrees/{level}/{x}/{y}/{z}.subtree for coordinates (level 0, (0,0,0))",
      "stack":
          Error: Could not resolve subtree URI subtrees/0/0/0/0.subtree that was created from template URI subtrees/{level}/{x}/{y}/{z}.subtree for coordinates (level 0, (0,0,0))
              at Function.resolve (/workspaces/3d-tiles-tools/src/tilesets/traversal/SubtreeModels.ts:74:13)
             ...

converting ./Metadata/ImplicitHeightAndSphereSemantics/tileset_1.1.json
[17:56:53.117] ERROR (CLI): The root of the implicit tileset did not define a template URI
    err: {
      "type": "ImplicitTilingError",
      "message": "The root of the implicit tileset did not define a template URI",
      "stack":
          Error: The root of the implicit tileset did not define a template URI
              at ImplicitTraversedTile.getRawContents (/workspaces/3d-tiles-tools/src/tilesets/traversal/ImplicitTraversedTile.ts:362:17)
...
converting ./Metadata/ImplicitHeightAndRegionSemantics/tileset_1.1.json
[17:59:03.638] ERROR (CLI): The root of the implicit tileset did not define a template URI
    err: {
      "type": "ImplicitTilingError",
      "message": "The root of the implicit tileset did not define a template URI",
      "stack":
          Error: The root of the implicit tileset did not define a template URI
              at ImplicitTraversedTile.getRawContents (/workspaces/3d-tiles-tools/src/tilesets/traversal/ImplicitTraversedTile.ts:362:17)
           ...
converting ./Metadata/ImplicitGroupMetadata/tileset_1.1.json
[17:59:11.852] ERROR (CLI): The root of the implicit tileset did not define a template URI
    err: {
      "type": "ImplicitTilingError",
      "message": "The root of the implicit tileset did not define a template URI",
      "stack":
          Error: The root of the implicit tileset did not define a template URI
              at ImplicitTraversedTile.getRawContents (/workspaces/3d-tiles-tools/src/tilesets/traversal/ImplicitTraversedTile.ts:362:17)
        ...
converting ./Metadata/ImplicitMultipleContentsWithMetadata/tileset_1.1.json
[17:59:20.201] ERROR (CLI): The root of the implicit tileset did not define a template URI
    err: {
      "type": "ImplicitTilingError",
      "message": "The root of the implicit tileset did not define a template URI",
      "stack":
          Error: The root of the implicit tileset did not define a template URI
              at ImplicitTraversedTile.getRawContents (/workspaces/3d-tiles-tools/src/tilesets/traversal/ImplicitTraversedTile.ts:362:17)
     ...

         

Thanks for trying this out. Quickly looking over that, and the “categories” of the errors:

“contentAvailabilities is not iterable”:

This is caused by what appears to be some legacy test data: The contentAvailability was changed to be an array (to support multiple contents). CesiumJS still supports the legacy version. Now… there ave different levels of “legacy-ness” :grimacing: : It claims to be 3D Tiles 1.1, but a legacy version of that, and it’s debatable in how far the upgrade is supposed to handle that. I opened Voxel Spec data uses legacy 3D Tiles 1.1 representation · Issue #12596 · CesiumGS/cesium · GitHub , rather as a note/TODO for myself.

Error: Missing required extension, “KHR_techniques_webgl”:

This is coming from glTF-Transform, when trying to load the glTF data from that I3DM. I think that this extension is not widely used, and certainly something that cannot be upgraded generically and automatically (we’re talking about an extension with inlined GLSL shader code here…). But maybe upgrading the given I3DM manually could be doable…

The “No input…” ones for “tileset_1.0.json”:

I’d say that these are anticipated: These 1.0-tilesets are using the set of extensions that had been summarized under the name “3D Tiles Next”. They have been extensions for 3D Tiles 1.0 that served the purpose of being “preview features” for what ended up as part of the core functionality of 3D Tiles 1.1. (One could consider an update path for that, and it would probably not be terribly difficult, but … would cause a bit of “clutter”, and may not be important, given that tilesets with these extensions have only been created in a short period of time, as previews for the 1.1 functionality).

Could not resolve subtree URI subtrees/0/0/0.subtree:

This is anticipated. The file is not there :slight_smile: This seems to be for a very low-level spec in CesiumJS that only cares about the JSON part.

The root of the implicit tileset did not define a template URI

This actually looks like a bug in the tools. I opened Implicit tilesets with multiple contents may not be supported · Issue #179 · CesiumGS/3d-tiles-tools · GitHub for now, and will have to check that.

Is the tree_billboard.i3dm used in a figure for the 3D Tiles spec/documentation ? If so, it may be worthwhile updating the glTF.

Non-existence is hard to prove, but I’m reasonably sure that this I3DM is used nowhere in the specification. The glTF uses the KHR_techniques_webgl extension, which was never ratified and is now an “Archived Draft”. I’d have to check some details, assume that the custom GLSL code was used for implementing the “billboarding effect” (i.e. the plane always facing the viewer). If this is the case, then there wouldn’t be a way to “emulate” that with glTF 2.0. (There are considerations for “billboarding effects” in various forms, but nothing settled)

glTF 1.0 had explicit shaders, so this was probably a compatibility extension for glTF 2.0.

The example references duck0FS.glsl and duck0VS.glsl shaders which were not kept, in the main branch. So there is no way to render this glTF.

Agreed, no need to think about this example, it is obsolete.

Yes, back during the transition from glTF 1.0 (with shaders) to glTF 2.0 (with PBR), the idea was roughly to pull out the shader-related functionality into an extension, to have some sort of “migration path/backward compatibility”. But 2.0 gained so much more traction than 1.0 that nowadays, glTF 1.0 can hardly be found anywhere.
(Except for some old B3DM files from early adopters … this is what the upgrade is all about :slight_smile: )

I don’t know whether the duck0... files had ever been part of the spec repo. In doubt, they can be found at glTF-Sample-Models/1.0/Duck/glTF at main · KhronosGroup/glTF-Sample-Models · GitHub , but it’s not even clear whether the JSON in the extension description really “matches” these shaders, or whether that was just for illustration.

The tree_billboard.i3dm refers to some treeBillboard0FS/VS, and I could probably extract them with a bit of manual twiddling, but without a way of emulating that in glTF 2.0, this would probably not be sooo useful.

I tried some fiddling until it occurred to me to just run strings on the embedded glb:

fragment shader (has just diffuse/base color from texture, no lighting)

precision highp float;
varying vec2 v_texcoord0;
uniform sampler2D u_diffuse;
void main(void) {
    gl_FragColor = texture2D(u_diffuse, v_texcoord0);

vertex shader (has just position)

precision highp float;
attribute vec3 a_position;
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
attribute vec2 a_texcoord0;
varying vec2 v_texcoord0;
void main(void) {
    // Billboard code. Remove all rotation and scaling from the modelView matrix
    mat4 modelViewMatrix = mat4(1.0);
    modelViewMatrix[3] = u_modelViewMatrix[3];
    vec4 position = modelViewMatrix * vec4(a_position, 1.0);
    gl_Position = u_projectionMatrix * position;
    v_texcoord0 = a_texcoord0;

It has the billboarding by only keeping the translation column [3] of the passed modelview matrix. I think it should also keep the scaling but the trees apparently do not have their own transform matrix. I guess glTF does not have billboarding
Anyways, just for completeness.