[SOLVED] Bug: Bone animations share their bind transforms

Hi,

there is a bug in the Bone class. It is not possible to set individual bind tranforms for each model of the same modelfile.

e.g. I have 3 elephants and want to scale their legs differently.
If I try to scale one elephants bone like this:

bone = skeletonControl.getSkeleton().getBone("leg.right");
bindScale = bone.getBindScale();
bindScale.set(scale, scale, scale);

all 3 elephants will be scaled instead of only the one.
After a bit of investigation I realized that the Bone constrcutor doesn’t create clones of the given Bone object parameter. So I fixed it and it worked. Here is the fix:

    Bone(Bone source) {

    this.name = source.name;

    userControl = source.userControl;

    bindPos = source.bindPos.clone();
    bindRot = source.bindRot.clone();
    bindScale = source.bindScale.clone();

    modelBindInversePos = source.modelBindInversePos.clone();
    modelBindInverseRot = source.modelBindInverseRot.clone();
    modelBindInverseScale = source.modelBindInverseScale.clone();

    // parent and children will be assigned manually..
}

Pull request: Bone animation bind transform bug by AlrikG · Pull Request #435 · jMonkeyEngine/jmonkeyengine · GitHub

Not necessarily related to your issue but in general getting a value and settings it values directly in JME is a big big no-no.

You need to find the right setter and use that instead… and then I suspect your issue might get fixed, also. (Edit: if you supply a new value to the setter instead of reusing.)

the Bone constructor has a warning added regarding this

you can try this

bone = ...
bone.setUserControl(true);
bindScale = bone.getLocalScale();
bindScale.set(scale, scale, scale);

If you make your 3 elephants by cloning, make sure you clone the elephants before you change any bones!

Otherwise you can load them through asset manager multiple times.

Finding the “right” setter is meaningless. The problem is that the same objects are shared between the models. They have the same object ID!

Yes, so if you set the values directly, around the API… then you will be setting the values of the shared objects… instead of swapping them out for new shared objects.

I’ve changed bone scales before without them affecting every other version of the skeleton.

If I set userControl true, the animations cannot control the bones anymore. I want to control the bones on my own and by the animation at the same time

Can you tell whats the right setter please?

Well, setBindTransforms() doesn’t do the right thing anyway. But in general, bypassing the API in JME is a bad approach.

setUserTransforms() is what I’ve used before.

I’m just not sure bones were meant to be used in the way you are using them. I’ll have to wait for someone who knows animation better to answer.

setUserTransforms() requires that userControl is true. This is not the same as modifying the bind transforms. For example if I modify bindscale to make an arm bigger and the arm has an animation. The scale should only be applied to one model and may not shared between them.

Bind trasforms are the transforms to use when you reset the model.
Meaning it’s the transform in which the skeleton is reset on each frame before applying animation transforms.
They are shared to save memory and because they are supposed to be the same for all the instances of the same model.
If you need models with distinct mesh buffers you can use the deepClone method.

Ok thanks so you mean something like this?

Node node = (Node) getAssetManager().loadModel("model.j3o");
model = node.deepClone();
skeletonControl = model.getControl(SkeletonControl.class);
Bone bone = skeletonControl.getSkeleton().getBone("leg.right");
Vector3f bindScale = bone.getBindScale();
bindScale.set(scale, scale, scale);

Edit: This also doesn’t work :confused:

Ok I didn’t read thoroughly, you’re not modifying the mesh, but the bones of the skeleton.
I looked into the code and there is a bug indeed. Bones are cloned, but the transforms inside a bone are not cloned

You end up having different skeletons and diferent bones, but that share the same Vecotr3f…

However… there is this remark in the javadoc that let me think it’s on purpose.
@Momoko_Fan, any insight on this?

Pull request was finally merged: Bone animation bind transform bug by AlrikG · Pull Request #435 · jMonkeyEngine/jmonkeyengine · GitHub

Modifying bones like that is still not a good idea.

If I have a character that the player can customize, what is the better way modifying bones than change the bind transforms?

Hmm, nevermind…

We have Bone.setBindTransforms() which now officially works since all models have cloned bind transforms so modifying them doesn’t cause any issues.