Problems importing 3D models

Hi there,

did anyone already face problems with glb importing as 3D Models?

I create my glb file in Python through pyvista/vtk/pygltflib. However, when I import it in Cesium Ion, the only option that seems to work is 3D Models (import as 3D tiles).


Also, when importing as 3D Models (import as 3D tiles) to Cesium Ion, it does not come with any orientation, and thus I cannot try it in SandCastle, because it simply does not work.

An example of a glb file is here.
model_MAG_IGRF_grid_v0_0_3_1_try02_ravel_C.glb (40.6 KB)

And why do I want to import it as 3D Models?

  1. Because the model comes in an upward orientation instead of its original one (horizontal, as a map) as 3D Models (import as 3D tiles). And when we try to rotate it in Cesium Ion, it gets the wrong position. And positioning is crucial for our case since we are working with accurate georeferenced data.
  2. Also, we are having trouble rotating the 3D Models (import as 3D tiles), which is a 3DTileset. The origin of the model (as depicted in the Cesium Ion Editor is not centered at the model but at its edge.
  3. And we need to do that without Cesium Ion editor, through an automated process (lines of codes, therefore).

In an attempt to rotate this model, I adapted this example to adhere to rotation, not only translation.

The complete code is below.

var viewer = new Cesium.Viewer("cesiumContainer", {
  shadows: true,

viewer.scene.globe.depthTestAgainstTerrain = true;

var viewModel = {
  height: 0,


var toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);

var tileset = new Cesium.Cesium3DTileset({
  url: "../SampleData/Cesium3DTiles/Tilesets/Tileset/tileset.json",

  .then(function (tileset) {
      new Cesium.HeadingPitchRange(
        tileset.boundingSphere.radius * 2.0
  .otherwise(function (error) {

  .getObservable(viewModel, "height")
  .subscribe(function (height) {
    height = Number(height);
    if (isNaN(height)) {

    var cartographic = Cesium.Cartographic.fromCartesian(
    var surface = Cesium.Cartesian3.fromRadians(
    var offset = Cesium.Cartesian3.fromRadians(
    var translation = Cesium.Cartesian3.subtract(
      new Cesium.Cartesian3()
    var rotation = Cesium.Matrix3.fromRotationY(
      new Cesium.Matrix3()
    // tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
    tileset.modelMatrix = Cesium.Matrix4.fromRotationTranslation(rotation,translation);

  • I added var rotation = Cesium.Matrix3.fromRotationY - but could be X or Z: none worked for angle values different than 0.
  • I changed
    tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
    tileset.modelMatrix = Cesium.Matrix4.fromRotationTranslation(rotation,translation);
    to make sense.

The model simply vanishes.

Hey @leomiquelutti,

The easiest way to do this would be to upload your model using the REST API and pass in the longitude, latitude, and height for the origin of your 3D model. This will (1) make it appear in exactly the right location, and (2) when you rotate it with the Cesium ion tool it should rotate from the correct origin.

The REST API tutorial here describes how to set this up and has a link to a full example: The example uploads a CityGML, yours would be a type “3D_MODEL” which allows you to pass a “position”.

Hi @omar thanks for the answer.

Is it possible to test it from Sandcastle?

The method I suggested is done at upload time, not at runtime. So you’ll need to run it as a NodeJS script locally (or use anything to call the REST API, like Python etc)

Hi @omar,

we did uploaded our models thorugh the REST API. Thanks for the tip!

However, we could not place them correctly. They changed coordinates after importing. The coordinates in Cesium Ion Editor are different than the one we defined during the importing process. And we did use EPSG:4326 CRS. Any ideas?

@leomiquelutti can you share the asset ID so we can look into it?

Hi @omar,

it can be both 150867 or 150858. Thanks! :raised_hands:t2:

Hi @omar,

did you have the chance to look at our models? Any news?

Hi @leomiquelutti,

I had a look to the model and it seems all the vertices are in UTM coordinates. Cesium ion expects models to be in local coordinates ( So you’ll need to regenerate the models using local coords or unprojecting those positions.

To get the model to appear at those UTM positions if you were using Cesiumjs you would need to convert them to lat/lon/height. And then, to position something directly in the globe:

Cartesian3.fromDegrees(lat, lon, height)

Hope it helps.

P.S: While reviewing this we noticed that using local coordinates is not explicitely said in the BIM/CAD import documentation (, so thank you for raising this issue, as it helps to improve our documentation.

Hi @jtorres,

thanks for the help. Could you please show me how did you notice this? Where/what are those coordinates values from my model? I have been a hard time trying to track in my code (with strong 3rd-party dependency) how these values are set.

Hi @leomiquelutti,

I just converted to OBJ to be able to inspect visually the value of each vertex. But you can do the same by exporting to gltf and check min/max for position accessor or export to other text formats. Also you could import in blender to check where are the vertex positions.

Hope it helps

1 Like