3DTileset rotation

Hi everyone,

I am currently facing an issue where the model disappears when i apply any sort of rotation to my 3DTileset based on mouse movement. Previously i have been able to update the height of the model in a relatively straightforward way but for rotation if i update the modelMatrix the model disappears from the viewer.

I have shared the loading of my 3dtileset as well as part of the rotation code below:

let tileset = this._viewer.scene.primitives.add(
            new Cesium.Cesium3DTileset({
                url: _tile_path,
                geometricError: 0.001,
                skipLevelOfDetail : true,
                baseScreenSpaceError : 1024,
                skipScreenSpaceErrorFactor : 16,
                skipLevels : 1,
                immediatelyLoadDesiredLevelOfDetail : false,
                cullWithChildrenBounds : true,
                maximumScreenSpaceError : 4,

 this._clickHandler.setInputAction(async (click) => {
            const pickedObject = this._viewer.scene.pick(click.position);
            if (this._enableTransformEditor && pickedObject && !pickedObject.id) {

                this.selectedTileset = pickedObject.primitive;
                this.initialMousePosition = Cesium.Cartesian2.clone(click.position);
        }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

        this._clickHandler.setInputAction((click) => {
            this.selectedTileset = null;
            this.initialMousePosition = null;
            }, Cesium.ScreenSpaceEventType.LEFT_UP);

        this._clickHandler.setInputAction((movement) => {
            if (this.selectedTileset && this.initialMousePosition) {
                const translation = new Cesium.Cartesian3();
                Cesium.Matrix4.getTranslation(this.selectedTileset.modelMatrix, translation);

                const dx = movement.endPosition.x - this.initialMousePosition.x;

                // Convert the dx value to a yaw rotation angle
                const yaw = Cesium.Math.toRadians(dx / 100);

                // Step 1: Translate to Origin
                const translationToOrigin = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(-translation.x, -translation.y, -translation.z));
                const translatedModelMatrix = new Cesium.Matrix4();
                Cesium.Matrix4.multiply(this.selectedTileset.modelMatrix, translationToOrigin, translatedModelMatrix);

                // Step 2: Rotate using yaw, pitch, and roll (in this case, just yaw)
                const rotationMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(Cesium.Cartesian3.ZERO, new Cesium.HeadingPitchRoll(yaw, 0, 0));
                const rotatedModelMatrix = new Cesium.Matrix4();
                Cesium.Matrix4.multiply(translatedModelMatrix, rotationMatrix, rotatedModelMatrix);

                // Step 3: Translate back to original position
                const translationBack = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(translation.x, translation.y, translation.z));
                const newModelMatrix = new Cesium.Matrix4();
                Cesium.Matrix4.multiply(rotatedModelMatrix, translationBack, newModelMatrix);

                // Apply the new model matrix
                this.selectedTileset.modelMatrix = newModelMatrix;

                // Update initialMousePosition for the next movement
                this.initialMousePosition = Cesium.Cartesian2.clone(movement.endPosition);

        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

Your feedback would be highly appreciated in this regard.

For questions like this, it is usually very helpful to provide a Sandcastle that illustrates the problem. From only looking at the code, it may be hard or even impossible to understand what the problem is. A sandcastle and a clear description of the goal or desired behavior will make it much more likely to receive a helpful response.

As far as I understood, the intention is to have some sort of “editing functionality” for the position and orientation of the tileset. Specifically, you tried to rotate the tileset with mouse drags. And you did this by modifying the modelMatrix of the tileset.

The general approach seemed to be

  • move the tileset to the origin
  • apply the rotation
  • move the tileset back to its original position

That is generally the correct approach for “rotating something around its ‘local’ center in 3D”. And… this also worked for the tileset. That’s why it seemed to disappear :slight_smile:

There are different ways for positioning “geometry” (of a tileset) on the globe. And often, the position of the geometry is determined by the transform of the root node of the tileset. So even when the modelMatrix of a tileset is the identity matrix, the geometry may appear on a certain position on the globe, due to the root node transform.

When you then modify the modelMatrix so that it describes a small rotation, it will cause the tileset to be rotated “around the center of the earth”, and end up at a completely different position:

So in order to properly rotate a tileset, you have to take all transforms into account.

There are many transforms and many different representations of them. You might even have a tileset where the vertex positions store the actual positions on the globe. In this case, the following approach will not work. You’d have to compute the “origin” for the rotation … somehow.

But one approach that might be a solution for what you are trying to do:

  • Store the initial root.transform
  • Set the root.transform to be the identity matrix
  • Compute the desired rotation from the editing operations
  • Compute the current modelMatrix from the rotation and from the initial root transform

This could allow you to rotate a tileset like this:

Cesium Tileset Rotate

And … here is a Sandcastle for that:

Again: Depending on how exactly the “position of the geometry” is represented in the tileset, this approach might not work for all tilesets. But based on the example and the information in this post, you might be able to figure out a solution for other cases as well.