Is there a way to freeze transformations on a bone?
My use case:
My character rig’s rest pose does not match up with rest pose of the input animation.
I want to rotate my rigs rest pose around the it’s Y axis to line up with the rest pose of the input data.
I tried passing a local matrix with the desired rotation to the skeleton root bone’s constructor and a matrix with zeroed rotation as the rest pose matrix but that did not work.
I have a working solution where I managed to create a new skeleton from the rotated skeleton but it feels quite hacky.
Hey! do you mind reproducing the question in the Playground? there are some options (like forcing a call to return to rest, or cancelling animations but it will be easier with a repro)
It works, but it ain’t pretty. The only way I managed to get the desired result was by copying my skeleton and modifying it in steps.
Gray (srcSkeleton): Input data
Gray (rigSkeleton): This is the rig from Maya, it’s inside the purple skeleton so you can’t see it. The pose doesn’t match the input data so I can’t use it directly.
Purple (rigCopy): Copy of rigSkeleton. The way I copy it, I guess the transformation of the root bone is frozen.
Yellow (rotatedSkeleton): Rotated copy of rigCopy. This is aligned with the rest pose of the input data. I did not manage to just rotate an existing skeleton without messing something up so I came up with this method.
Green (targetSkeleton): Again, frozen version of rotatedSkeleton. This drives the mesh.
This all seems a bit crazy and it’s probably my lack of understanding how things work that led me to this complicated solution.
If anyone happen to come up with ways to simplify it I’m all ears
UPDATE
This Playground shows the rest pose of the input data.
Is it not possible to provide a simplified repro which would only show the problem?
The repro you provided is quite complicated as you create multiple skeletons and manually modify bones and animations… I don’t think you need to do that to repro (?)
hips.rotationQuaternion = new BABYLON.Quaternion.FromEulerAngles(0, Math.PI, 0);
// Freze somehow?
//hips.freezeTransformations();
// If frozen correctly, this should not reset the skeleton.
hips.rotationQuaternion.set(0, 0, 0, 1);
UPDATE 1
Maybe it’s possible with setRestPose. I will do some tests…
UPDATE 2
I would have thought the following should work.
Orient bone as desired.
Get current local matrix.
Use matrix to update rest pose.
Set all rotations to zero.
Expected result: Bone oriented as desired in new rest pose.
But it doesn’t seem to work that way:
hips.rotationQuaternion = new BABYLON.Quaternion.FromEulerAngles(0, Math.PI, 0);
var m = hips.getLocalMatrix();
hips.setRestPose(m);
hips.rotationQuaternion.set(0, 0, 0, 1);
We had a argument for this on the SkeletonViewer updates at one point but that was not the correct place for it to live. Maybe need to add a method on the skeleton class that is skeleton.setCurrentPoseAsRest(), or something like that?
It’s just that hips.setRestPose(hips.getLocalMatrix()) doesn’t really work. Or perhaps I’m just confused since mySkel.returnToRest() does not assume the new rest pose, but instead reverts to the original pose.
Another weird thing I noticed is that bone.getLocalMatrix() has side effects. I’m not sure if it’s by design or not but it was kind of suprising to me.
Maybe it’s OK, I’m not sure, I just noticed it and was a bit suprised.
It’s unrelated to my main bone issue though, ie setting a new rest pose/freezing transformations. It’s like the rest pose is not updating properly after calling setRestPose.
The call to hips.rotationQuaternion = new BABYLON.Quaternion.FromEulerAngles(0, Math.PI, 0); record the new quaternion and mark the underlying as dirty but does not actually updates it. The update will be done when a call on the bone instance requires the matrix to be up to date: getLocalMatrix() is one of these calls.
As the skeleton viewer does not use any call that would require the matrix to be recomputed, you see the bone in a position that does not take into account the change of the quaternion when you don’t call getLocalMatrix() and you see the change when calling it.
@Pryme8 Maybe the skeleton viewer should start by making sure all matrices are up to date by calling getLocalMatrix on each bone?