Unable to load b3dm tileset to scene

You mentioned earlier

The initial model was in glb format - it is just a simple tree.

and you created a B3DM file from that. It may be worth mentioning that when you use 3D Tiles 1.1 (instead of 1.0), then you can also use .GLB files directly. So you could create the corresponding tileset.json like this:

{
  "asset": {
    "version": "1.1"          // When you use "1.1" here....
  },
...
    "content": {
      "uri": "model.glb"      // ... then you can use the GLB file here
    },
...
  }
}

Beyond that, there are different tools for dealing with B3DM data, but I’m not aware of any tool that can directly compute the bounding box of a B3DM. One … solution (although a bit cumbersome) is

  • Extract the .GLB file from the B3DM, e.g. with the 3d-tiles-tools b3dmToGlb command
    • (You don’t have to do this, because you already have the GLB file!)
  • Drop the GLB file into https://gltf.report/
  • Select the “Metadata” tab

This will show be bounding box, as in the lower right of this screenshot:

When you have this bounding box, with its (min,max) points, then you still have to convert this into the boundingVolume.box representation of 3D Tiles. There, you need the (center,halfAxes) representation (because it can not only represent an Axis-Aligned bounding box, but also an Oriented bounding box). The conversion from the (min,max) representation into the representation that is used for 3D Tiles is… simple, but … currently, also has to be done manually. The computation is shown, for example, in this code snippet.

All this is indeed a bit cumbersome. I think that some of this could be simplified. One idea would be to add this information as part of the output of the analyze command of the 3D Tiles Tools.

I opened Extend `analyze` command to include bounding volume information · Issue #59 · CesiumGS/3d-tiles-tools · GitHub for this. This could be a low-hanging fruit, be implemented with reasonable effort, and might be useful for various sorts of analysis and debugging.


I guess, my main goal is not to position the model at runtime […] I mean to say, that I need the position to be hard coded inside tileset.json file.

… it seems to work exactly like it should. At the same time the result looks very strange now.

This looks like … the transform matrix is wrong.

One way of determining the right matrix could be:

  • Create the transform with the eastNorthUpToFixedFrame function (for a given position)
  • Print this as a flat array to the console

For example, the output of this

const transform = Cesium.Transforms.eastNorthUpToFixedFrame(
  Cesium.Cartesian3.fromDegrees(43.970149521784, 56.260414816738106, 0)
);
console.log(Cesium.Matrix4.pack(transform, new Array(16), 0));

will be

-0.6942835079850745,0.7197016121559956,0,0,-0.5984826914710163,-0.5773457436868751,0.5554190852466787,0,0.399736011074243,0.3856183109069252,0.831570586146325,0,2555492.883786797,2465239.113014277,5280601.728445846,1

And you can just copy+paste this into the transform array of the root tile.

The final tileset.json should then be

{
  "asset": {
    "version": "1.1"
  },
  "geometricError": 4096,
  "root": {
    "transform": [
        -0.6942835079850745,0.7197016121559956,0,0,
        -0.5984826914710163,-0.5773457436868751,0.5554190852466787,0,
        0.399736011074243,0.3856183109069252,0.831570586146325,0,
        2555492.883786797,2465239.113014277,5280601.728445846,1
    ],
    "boundingVolume": {
      "box": [
        0.8377834740791688,
        0.38224225730407735,
        7.952663400546863,
        7.760191485177515,
        0,
        0,
        0,
        -7.9996707314338495,
        0,
        0,
        0,
        8.4149664158071
      ]
    },
    "geometricError": 512,
    "content": {
      "uri": "model.b3dm"
    },
    "refine": "ADD"
  }
}

This can be loaded with this sandcastle:

const viewer = new Cesium.Viewer("cesiumContainer");

// Create the tileset in the viewer
const tileset = viewer.scene.primitives.add(
  await Cesium.Cesium3DTileset.fromUrl(
    "http://localhost:8003/tileset.json", {
    debugShowBoundingVolume: true,
  })
);

// Zoom to the tileset, with a small offset so that
// it is fully visible
const offset = new Cesium.HeadingPitchRange(
  Cesium.Math.toRadians(-22.5),
  Cesium.Math.toRadians(-22.5),
  60.0
);
viewer.zoomTo(tileset, offset);

And it will display the tree at the same location as before, but without setting the modelMatrix at runtime.

1 Like