Search code examples
cesiumjsresium

Cesium model node rotation skews the model


I am testing simple model (from a .glb file) node rotation using Resium/Cesium and while it works well with a 3d-party model, it doesn't when when I try it on my own model. I don't know why.

The model is a simple building with a small box on top of it. The box at the top needs to be able to rotate along the Z (altitude) axis. That's it. Instead, Cesium skews the model:

The model in Blender:

enter image description here

The way it appears (correctly) in Cesium before attempting to rotate the top box (ignore all the extra lines)

enter image description here

The way it appears (incorrectly) in cesium after attempting to rotate it around the altitude axis:

enter image description here

The rotation code in Cesium (I didn't write it, it works well for 3d party models I have):

const rotateNode = (
    node: any,
    angleRad: number // radians
) => {
    const matrix4 = node.matrix
    const rotation = Cesium.Matrix3.fromRotationY(angleRad)
    node.matrix = Cesium.Matrix4.multiplyByMatrix3(
        matrix4,
        rotation,
        node.matrix
    )
}

The additionally-odd part is that if I try to rotate the building BELOW the top box, it rotates correctly a long as its vertical faces are all the same size. If I change that, the skewing also happens on the building itself.

Any idea what is wrong with the model?


Solution

  • I'll go out on a limb here and guess that the smaller top box is a "child" of the larger box below, and furthermore, the larger box below has some non-uniform scaling applied to it.

    If so, you might be able to work around this issue in Blender, by selecting the larger parent box and clicking Object -> Apply -> Scale.

    What's happening is the transforms are out-of-order. In glTF, when the parent node has a non-uniform scaling, and then a child node contains some rotation, multiplying those transforms together results in a non-decomposable matrix. This causes geometry to be sheared or stretched in unfortunate ways.

    Some time ago I wrote this up as an export issue, glTF-Blender-IO#1083. But it's not really a bug in the exporter, instead it stems from glTF using much simpler rules than Blender for how parent nodes relate to their children (for example, glTF doesn't have Blender's whole "parent inverse" thing going on).

    So for now the rule is: If you want to rotate the children, don't apply non-uniform scaling to the parents.