Bones - Freeze transformations

Now, if only we can figure out why setRestPose does not update the rest pose correctly.
https://www.babylonjs-playground.com/#308TR3#7

hips.rotationQuaternion = new BABYLON.Quaternion.FromEulerAngles(0, Math.PI, 0);

mySkel.bones.forEach(b => {
    b.setRestPose(b.getLocalMatrix())
})

hips.rotationQuaternion.set(0, 0, 0, 1);

// Why doesn't this use the new rest pose?
mySkel.returnToRest();

I had that at one point but gutted it, would be ezpz to enabled! Let me know if I should do that.

So, the trick seems to be to not update the “difference matrix” when resetting the local matrix with the rest pose:

https://www.babylonjs-playground.com/#308TR3#9

Note that I have added a textured cube to better see what’s going on.

I called hips.updateMatrix(hips.getRestPose().clone(), false, true); by hand because returnToRest() calls updateMatrix(this._restPose.clone(), true, true);: the first true is to update the difference matrix, the second one to update the local matrix.

Also, there’s a bug in updateMatrix() that you can work around by calling getLocalMatrix() (see code).

Here’s the PR:

Thanks for looking into this.

returnToRest works much better now!

I have realized though that setting a rest pose does not help in terms of freezing transformations. I thought maybe when you create a rest pose that it would also zero out rotations, but after testing it I’ve realized that it doesn’t.

I noticed however that I can achieve something that might resemble frozen rotations by changing the base matrix, but I don’t really know what I’m doing. :slight_smile:

Still no luck with the base matrix. It first looked like it was working by setting baseMatrix = this.getLocalMatrix() in one example with a Math.PI / 2 rotation but for other angles it just gives strange results.

Do anyone know exactly what the base matrix does?

The base matrix is used in _updateDifferenceMatrix. In this method, it is used as the local bone matrix and is multiplied by the parent absolute transform to compute the absolute transform of the current bone (_absoluteTransform property). Then the matrix is inverted and is stored in _invertedAbsoluteTransform.

If you want your changes to base matrix to have an effect, you need to call updateMatrix() by passing it your modified base matrix (this matrix will be copied into _baseMatrix by updateMatrix()) and true, false as the 2nd and 3rd parameters.

It appears base matrix is pretty much interchangeable with the local matrix. It would be good to hear some use cases where a matrix other than local matrix would be used for base matrix.

The bone constructor clones the local matrix if no base matrix is provided. Bone.updateMatrix would even update the local matrix to the same as base matrix by default.

I’m trying to wrap my head around why we want base matrix to be separate from local matrix.

Indeed, but it’s different in the gltf case:
https://github.com/BabylonJS/Babylon.js/blob/master/loaders/src/glTF/2.0/glTFLoader.ts#L1124-L1143

The call to updateMatrix with false, false will not copy the matrix to the localMatrix.

Thanks @Evgeni_Popov . That is helpful especially as I am trying to reparent bones of imported GLBs.

I’ve moved some bones around by updating its matrix and I want to save that new skeleton pose as the rest pose. I’ve tried everything here and can’t seem to get it working. What I’m doing is trying to save new pose as rest pose then export to GLB with that rest pose. However when I open the GLB in Blender I have the bone changes as a new pose only and the rest pose unfortunately is still the same. Has anyone got it working so Blender reflects the new rest pose?.

Edit:
I’ve tried this:

skeleton.setCurrentPoseAsRest()
sketeton.returnToRest()

This sets rest pose within the BabylonJS canvas but when exporting to GLB its just a normal pose.

cc @bghgary in case he has an idea regarding the glb ?

@ozRocker Can you send an example?