Whenever I call armature.saveBindPose(), it is causing unexpected distortions to my model’s fingers. And as that method gets called more times during an editing session, the distortion becomes more severe.
Even if I make no changes and just re-save the original bind-pose, the issue still occurs.
Here is my code, I commented out all joint adjustments, and simply apply and re-save the model’s original bindpose (which I expected would cause no changes to the armature).
armature.applyBindPose();
// upperBodyHeightModification.apply(1.2f, armature);
// lowerBodyHeightModification.apply(1.0f, armature);
//
armature.saveBindPose(); // <-- commenting this out stops this issue
But for some reason it still distorts the fingers like this:
And here is how it becomes worse after I’ve dragged the height/weight sliders or pressed the slider buttons alot (which calls armature.saveBindPose() more times)
I tried tweaking some small things in the Armature class that did not require too deep of an understanding, but I had no luck.
I tested with a different animated model, and the issue still occurs. I also can’t seem to find any other jme users or projects that appear to have had success using armature.saveBindPose() in a similar context, so it is likely a newer bug in the new animation system.
After more investigation, It seems like this is most likely related to one of these two classes (possibly both), that handle combining parent joints’ transforms to determine a child joint’s local transform when a bindPose is saved.
It sounds like SeparateJointModelTransform is best used in cases where a model was migrated from the old system to the new (however that is not the case for my models I’m having this issue with)
And MatrixJointModelTransform is the one that appears to be used by default, although I’m not entirely certain where or how that is determined. I think I still need to do some more investigating into the new animation system to get a better understanding of things in order to find where the bug is.
My best guess so far is that some un-normalized transform values may need to be normalized, and are unintendedly accumulating and causing more distortion every time the bind pose is saved and recalculated.
Hi @yaRnMcDonuts , I experienced a similar, though less pronounced, finger deformation issue when changing 3D model animations in the view editor within the SDK. Without knowing what’s running underneath, I couldn’t determine the cause. It might be worth investigating the problem further. Have you discovered anything else? Could you provide a test case to reproduce the problem ?
Here’s a quick test case that you could use to recreate the issue:
(It doesn’t look like JME-testdata has any models using the new animation system, unless I’m mistaken, so I used the Erika archer model from the shader tech demo we worked on earlier this year. But this is the 3rd model I have reproduced this issue with, so I expect any model will trigger this)
import com.jme3.anim.SkinningControl;
import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.light.LightProbe;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
public class Main extends SimpleApplication {
private Node model;
private SkinningControl skinningControl;
private boolean saveEveryFrame = false;
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
//lights:
DirectionalLight sun = new DirectionalLight();
sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
rootNode.addLight(sun);
LightProbe lightProbe = (LightProbe) assetManager.loadModel("Scenes/defaultProbe.j3o").getLocalLightList().get(0);
rootNode.addLight(lightProbe);
//load model:
model = (Node) assetManager.loadModel("Models/Erika.j3o");
skinningControl = model.getChild("Armature").getControl(SkinningControl.class);
rootNode.attachChild(model);
//key input:
inputManager.addMapping("SaveBindPose", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(actionListener, "SaveBindPose");
}
private void saveBindPose(){
skinningControl.getArmature().applyBindPose();
skinningControl.getArmature().saveBindPose();
}
@Override
public void simpleUpdate(float tpf) {
super.simpleUpdate(tpf);
if(saveEveryFrame){
saveBindPose();
}
}
final private ActionListener actionListener = new ActionListener() {
@Override
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("SaveBindPose") && !keyPressed) {
saveBindPose();
// saveEveryFrame = !saveEveryFrame; //un-comment this to speed up the distortion and eventually cause a "java.lang.ArithmeticException" at com.jme3.anim.SeparateJointModelTransform.applyBindPose(SeparateJointModelTransform.java:33)
}
}
};
}
And I was going to say I have not discovered anything new yet.
However after I ran this test case with the Erika model and called saveBindPose() alot, eventually I got this error:
java.lang.ArithmeticException: This matrix cannot be inverted
at com.jme3.math.Matrix4f.invert(Matrix4f.java:1516)
at com.jme3.math.Matrix4f.invert(Matrix4f.java:1485)
at com.jme3.anim.SeparateJointModelTransform.applyBindPose(SeparateJointModelTransform.java:33)
at com.jme3.anim.Joint.applyBindPose(Joint.java:196)
at com.jme3.anim.Joint.applyBindPose(Joint.java:200)
at com.jme3.anim.Joint.applyBindPose(Joint.java:200)
at com.jme3.anim.Joint.applyBindPose(Joint.java:200)
at com.jme3.anim.Joint.applyBindPose(Joint.java:200)
at com.jme3.anim.Joint.applyBindPose(Joint.java:200)
at com.jme3.anim.Joint.applyBindPose(Joint.java:200)
at com.jme3.anim.Joint.applyBindPose(Joint.java:200)
at com.jme3.anim.Joint.applyBindPose(Joint.java:200)
at com.jme3.anim.Armature.applyBindPose(Armature.java:236)
at com.mygame.Main.saveBindPose(Main.java:57)
at com.mygame.Main.simpleUpdate(Main.java:69)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:261)
at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:628)
at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:717)
at java.base/java.lang.Thread.run(Thread.java:840)
Possibly because Erika is using SeparateJointModelTransform instead of the other one (MatrixJointModelTransform ) which I thought models used by default. But now I’m not sure on that.
But anyways it looks like the error happens at this line:
Eventually inverseModelBindMatrix gets corrupted to the point it can no longer be inverted and throws that error.
Yeah, Nehon was very cautious about adding models to the repo.
The tests use old J3Os and then convert them using AnimMigrationUtils.migrate(model) or else they load Ogre models such as “Oto.mesh.xml” (since the Ogre importer loads to the new system).