How to set position, rotation, scale of bones

The people responsible for sending me the animation data from the server side engine have decided to use absolute transforms. I will try initiate another discussion about the pros of using local transforms, but for now I will try getting it to work with absolute Transforms.

I also noticed something about my setAbsoluteRotationQuaternion funtion, which could be the cause for my transforms not working. The function seems to set the right amount of the angles, but when I try to rotate about the x axis it rotates about the z axis and vice versa. Furthermore rotating by (0,0,0) doesn’t leave the bone untouched as expected but instead rotates it as well.

Here is a playground to illustrate the issue: https://playground.babylonjs.com/#DD5YNW#1 (The relevant code begins at line 47 - 53.).

If you must use absolute transform, I think you can try sending the matrix over the wire (or composing the absolute TRS into a matrix), compute the local transform by multiplying against the inverse parent world matrix, then decompose into local TRS.

I have tried implementing this approach like so: https://playground.babylonjs.com/#FF3FD0#13
I compose the absolute TRS into a matrix using Matrix.Compose. The thing which might be going wrong here is the call to Matrix.Compose. I am assuming this gives me a 4x4 transformation matrix in homogeneous coords where the upper left 3x3 matrix is RS and the bottom row is the transformation vector (as BJS uses row-major matrices). Correct me if that is wrong.

        let eulerX = transforms[0];
        let eulerY = transforms[1];
        let eulerZ = transforms[2];

        let pX = transforms[3];
        let pY = transforms[4];
        let pZ = transforms[5];

        let scaling = transforms[6];

        let boneTN = bone.getTransformNode();

        //Transform absolute to local
        const yprQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(eulerY, eulerX, eulerZ);
        let absolutePosition = new BABYLON.Vector3(pX, pY, pZ);
        let absoluteScale = new BABYLON.Vector3(scaling, scaling, scaling);

        let absoluteTransformMatrix = BABYLON.Matrix.Compose(absoluteScale, yprQuaternion, absolutePosition);

Then I do the transform from absolute to local using the inverseParentWorld matrix.

let computeLocalTransform = function(transformNode, absoluteTransformMatrix ){
        if(transformNode.parent){
            const inverseParentWorldMatrix = BABYLON.Matrix.Identity();
            transformNode.parent.getWorldMatrix().invertToRef(inverseParentWorldMatrix);
            let localTRS = inverseParentWorldMatrix.multiply(absoluteTransformMatrix);
            
            let quatRotation = new BABYLON.Quaternion();
            let position = new BABYLON.Vector3();
            let scale = new BABYLON.Vector3();

            localTRS.decompose(scale, quatRotation, position);

            return {scale : scale, rotationQuaternion : quatRotation, position : position};

        }else{
            let quatRotation = new BABYLON.Quaternion();
            let position = new BABYLON.Vector3();
            let scale = new BABYLON.Vector3();

            absoluteTransformMatrix.decompose(scale, quatRotation, position);

            return {scale : scale, rotationQuaternion : quatRotation, position : position};
        }
}

I think this should be transforming from absolute TRS to local TRS correctly, but as one can see in the playground the transforms are way off :sweat_smile: skinning seems to be pretty tricky :face_with_spiral_eyes:

One thing I noticed is that the avatar is flipped upside down, which could have something to do with the handedness of the coordinate system? I also tried looking again over the transform node hierarchy of the .glTF to see if there is something wrong with my .glTF file somehow, do you see anything wrong with it?

Yes, that is for sure.

I think you will need to take one bone at a time and compare against the source to see why the math isn’t working.

Hello @r0bert0 just checking in, do you need any further help? :smiley:

Sorry I forgot to follow up here. The issue was that I was applying the rotations in the wrong order. The transformation data I received expected me to rotate in the order ZYX not XYZ.

After taking that into account, translating the transforms from world to local coordinates (see above) works as expected. :sunglasses:

2 Likes