# How to set tileset.json transform correctly?

**URL:** <https://community.cesium.com/t/how-to-set-tileset-json-transform-correctly/44887>\
**Category:** 3D Tiles\
**Created:** [January 19, 2026, 5:06pm UTC](https://community.cesium.com/t/how-to-set-tileset-json-transform-correctly/44887 "2026-01-19T17:06:46Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Denis.Biguenet](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/denis.biguenet/32/28173_2.png) [@Denis.Biguenet](https://community.cesium.com/u/Denis.Biguenet)\
**Post date:** [January 19, 2026, 5:06pm UTC](https://community.cesium.com/t/how-to-set-tileset-json-transform-correctly/44887/1 "2026-01-19T17:06:46Z")

</div>

Hi everyone,

I’m facing some difficulties to create 3D tiles from another file format.

What i’m trying to achieve :

I have a collection of photos and a json file describing the position and orientations of the camera for each photo. The goal is to convert the json into 3d tiles where each photo is represented by a geometry (roughly a pyramid)

What I have done so far :

tileset.json, gltf and bin files are generated from the json file. These files describe a pyramid and its instances, each pyramid has a translation and a rotation and the vertices coordinates are expressed in a local system (the center of the dataset).

What I don’t understand :

I’m really confused about what I should set in the root “transform”. It seems obvious the translation part should be the center of the dataset in ECEF, but what about the rotation?

Here is what I see when I open the tileset file with CesiumJS :

 ![Screenshot 2026-01-19 174713](https://global.discourse-cdn.com/cesium/original/3X/d/e/de90479438668cc4a45e72f6d77b8b2dbf654896.jpeg)

 ![Screenshot 2026-01-19 175102](https://global.discourse-cdn.com/cesium/original/3X/6/5/6526634ad2ca90cd0347dade05f514546a75b186.jpeg)

The geometries should be parallel to the ground

Expected positions :

 ![Screenshot 2026-01-19 175237](https://global.discourse-cdn.com/cesium/original/3X/2/f/2f80cf29ccff6c4049cd0987ef02917f86a3e9b2.jpeg)

I have tried to use eastNorthUpToFixedFrame function from CesiumNative and put the result in root transform, but it does not work. On the other hand, it looks better when adding a 90 degrees rotation around X axis

 ![Screenshot 2026-01-19 175802](https://global.discourse-cdn.com/cesium/original/3X/5/7/57cf579a0b526d0523d586bba56cd3ed48771a97.jpeg)

That is where I’m getting confused. According to the documentation, cesium already rotates the whole scene to trasnform from a Y-up norm (gltf) to a Z-Up norm (cesium). Moreover, I thought the purpose of eastNorthUpToFixedFrame is to orient the geometry based on its position on earth. For instance to prevent building to “tilt” since without any rotation in the root transform they would have the same orientation no matter their position on earth ( a sphere)

So the questions are : am I missing something? How to set the root transform in tileset.json

---

<div class="post-metadata">

**Author:** ![Marco13](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/marco13/32/2757_2.png) [@Marco13](https://community.cesium.com/u/Marco13)\
**Post date:** [January 19, 2026, 5:39pm UTC](https://community.cesium.com/t/how-to-set-tileset-json-transform-correctly/44887/2 "2026-01-19T17:39:22Z")

</div>

Yeah, that can be a bit tricky and confusing.

> According to the documentation, cesium already rotates the whole scene to trasnform from a Y-up norm (gltf) to a Z-Up norm (cesium).

I assume that this refers to the [glTF transforms](https://github.com/CesiumGS/3d-tiles/tree/main/specification#gltf-transforms) paragraph from the specification, or the ‘y-up to z-up’ section there. But this only refers to the glTF itself, and not to any placement that is done **to** this glTF based on the `tile.transform` of the tileset JSON.

In general, the `eastNorthUpToFixedFrame` is the function that you’re looking for. It generates a matrix that can _directly_ be set as the `tileset.root.transform` to place “the whole tileset” at the respective position on the globe, _including_ the proper orientation. Specifically, with this code

```javascript
    const cartographic = Cartographic.fromDegrees(/* your values here */);
    const cartesian = Cartographic.toCartesian(cartographic);
    const enuMatrix = Transforms.eastNorthUpToFixedFrame(cartesian);
    const transform = Matrix4.toArray(enuMatrix);

```

The resulting `transform` can be set as the `root.transform` in the tileset JSON. (This is basically what is done in the `createTilesetJson` command of the `3d-tiles-tools`, by calling [this function](https://github.com/CesiumGS/3d-tiles-tools/blob/24bf3b8a90074b5095f51bfaafbb5f2dbf11cf44/src/tools/tilesetProcessing/TilesetJsonCreator.ts#L283))

> each pyramid has a translation and a rotation.

This might be where some coordinate system issue could come in. If these translations are stored as part of the `transform` of the tiles, then they already have to be in z-up orientation. Maybe you applied them with y-up?

If there is some example code, or maybe examples of the input (camera positions and orientations) and output (tileset JSON), it could be easier to find out what might be wrong.

* * *

BTW: What you are doing there sounds similar to what has been considered as a feature of the `3d-tiles-tools` via [Extend tileset creation function to assign multiple positions · Issue #130 · CesiumGS/3d-tiles-tools · GitHub](https://github.com/CesiumGS/3d-tiles-tools/issues/130) and [Consider convenience functions to create instanced models · Issue #84 · CesiumGS/3d-tiles-tools · GitHub](https://github.com/CesiumGS/3d-tiles-tools/issues/84). It could be relatively low-hanging fruit in terms of implementation effort, but there are a few degrees of freedom for how the input data (instance positions) could be provided, and it hasn’t yet been decided how exactly that could be offered.

---

<div class="post-metadata">

**Author:** ![Denis.Biguenet](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/denis.biguenet/32/28173_2.png) [@Denis.Biguenet](https://community.cesium.com/u/Denis.Biguenet)\
**Post date:** [January 20, 2026, 8:57am UTC](https://community.cesium.com/t/how-to-set-tileset-json-transform-correctly/44887/3 "2026-01-20T08:57:38Z")

</div>

Hi Marco, thanks for your help

Here is an example of camera position (ecef) & rotation :

“Center” : {

```auto
"x" : 4357878.92150379438,

```

“y” : 499377.057726634433,

“z” : 4615903.61287616752

},

“Rotation” : {

“omega” : -3.03613405076508958,

“phi” : -0.72010804749420354,

“kappa” : 0.204569662598000079

},

For now, i’m not using the rotation. I will use it when the tileset is oriented as expected

Instances translations in the .bin file :

```auto
translations.push_back(pose.center() - center);

```

where “pose.center()” is “Center” from the json file, and “center” is the tileset center position (another ecef position)

Then

```auto
auto vect = Eigen::Vector3d(sceneCenter.x(), sceneCenter.y(), sceneCenter.z());
auto matrix = eastNorthUpToFixedFrame(vect);
for (int r = 0; r < 4; r++)
        for (int c = 0; c < 4; c++)
            root.transform[r + 4 * c] = matrix(r, c)

```

I get this matrix :

[-0.11385067290190085,0.993497873314173,0.0,0.0,-0.7225013006308046,-0.08279560677358744,0.6863940253861402,0.0,0.6819310044766846,0.07814642166605644,0.7272298411879223,0.0,4357691.866584947,499373.13872130145,4616051.714314801,1.0]

In euler :

Yaw (Z) –99.0°  
Pitch (Y) –43.3°  
Roll (X) +6.1°

The dataset is located in western switzerland, so the pitch and roll look good, but the result does not look good at all

 ![Screenshot 2026-01-20 095539](https://global.discourse-cdn.com/cesium/original/3X/c/e/ce52fcc5ebd020074debbd1be69589c8efb91dee.jpeg)

Here, I’m very confused : eastNorthUpToFixedFrame matrix does not work, but a simple 90 degrees rotation on X without eastNorthUpToFixedFrame does the trick

---

<div class="post-metadata">

**Author:** ![Marco13](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/marco13/32/2757_2.png) [@Marco13](https://community.cesium.com/u/Marco13)\
**Post date:** [January 20, 2026, 3:30pm UTC](https://community.cesium.com/t/how-to-set-tileset-json-transform-correctly/44887/4 "2026-01-20T15:30:11Z")

</div>

I’ll start with another disclaimer: It may be necessary to iterate on that a bit more. There are some _very_ subtle details that can decide on whether something is “right” or “wrong”, and it’s sometimes difficult to find out what _caused_ a result to be “wrong”.

But there already are some important details in your answer. For example, you initially said

> a json file describing the position and orientations of the camera

I may have silently assumed it to be a _cartographic_ position. But the JSON that you posted indicates that these are _cartesian_ (ECEF) positions. Additionally, the fact that you use the _difference_ (`pose.center() - center`) for the _individual_ translations is relevant here.

Based on that new information, I’d say that `eastNorthUpToFixedFrame` will indeed not be required. It sounds like `root.transform` simply has to be a translation matrix, with the translation just being the `sceneCenter` (i.e. that “center position” of the tileset that you mentioned). This should work when the translations that are computed as  
`translations.push_back(pose.center() - center);`  
are then the translations that are inserted as the translations of the _child tiles_ of the root tile.

---

<div class="post-metadata">

**Author:** ![Denis.Biguenet](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/denis.biguenet/32/28173_2.png) [@Denis.Biguenet](https://community.cesium.com/u/Denis.Biguenet)\
**Post date:** [February 12, 2026, 4:26pm UTC](https://community.cesium.com/t/how-to-set-tileset-json-transform-correctly/44887/5 "2026-02-12T16:26:12Z")

</div>

Hi Marco.

Sorry, I have not given any feedback for two weeks. We have found a solution, but it was not easy.

We had to apply a 90 degrees rotation for all the objects in the .bin file, and convert the ecef transform matrix to the local enu.

[Azure DevOps Services | Sign In](https://dev.azure.com/bentleycs/Reality%20Modeling/%5C_git/ContextCapture?path=/A3D/Export/ExportCalibrationTo3DTilesExe.cpp) See code between lines 815 and 850 (compute local enu + objetcs translations and rotations), and also code between lines 877 and 886 (tileset)
