[SOLVED] Issue with adding AnimClip to AnimComposer

Seems there is another bug with the new animation system.

Please take a look at this simple test:

public class TestAnimComposer extends SimpleApplication {

    public static void main(String[] args) {
        TestAnimComposer main = new TestAnimComposer();
        AppSettings s = new AppSettings(false);
    public void simpleInitApp() {
    private void workingTest() {
        Spatial model = assetManager.loadModel("models/character/model-1/model.gltf");
        model = BinaryExporter.saveAndLoad(assetManager, model);
        AnimComposer ac = getAnimComposer(model);
    private void failingTest() {
        Spatial model = assetManager.loadModel("models/character/model-1/model.gltf");
        AnimComposer ac = getAnimComposer(model);
        AnimClip animClip = ac.getAnimClip("walk");
        model = BinaryExporter.saveAndLoad(assetManager, model);
        ac = getAnimComposer(model);
    private void failingTestWithDebug() {
        Spatial model = assetManager.loadModel("models/character/model-1/model.gltf");
        AnimComposer ac = getAnimComposer(model);
        AnimClip animClip = ac.getAnimClip("walk");
        model = BinaryExporter.saveAndLoad(assetManager, model);
        ac = getAnimComposer(model);
        ac.addAction("walk-debug", new ClipAction(animClip) {
            public boolean interpolate(double t) {
                boolean interpolate = super.interpolate(t); 
                System.out.println("interpolate=" + interpolate + " , time=" + t);
                return interpolate;

    private void initLight() {
        Node probeNode = (Node) assetManager.loadModel("scenes/lightprobe/bright-sky.j3o");
        LightProbe probe = (LightProbe) probeNode.getLocalLightList().iterator().next();
        probe.setPosition(new Vector3f(0, 0, 0));

    protected AnimComposer getAnimComposer(Spatial model) {

        Spatial s = getAnimRoot(model);
        AnimComposer animComposer = s == null ? null : s.getControl(AnimComposer.class);

        return animComposer;

    protected Spatial getAnimRoot(Spatial model) {
        // Find spatial with the composer
        // For the moment, we'll guess
        Spatial animRoot = ((Node) model).getChild("Root");
        if (animRoot == null) {
            // Have to find it the hard way
            animRoot = findAnimRoot(model);
            if (animRoot.getControl(AnimComposer.class) != null) {
                System.out.println("Anim clip names:" + animRoot.getControl(AnimComposer.class).getAnimClipsNames());
        System.out.println("animRoot:" + animRoot);

        return animRoot;

    protected Spatial findAnimRoot(Spatial s) {
        if (s.getControl(AnimComposer.class) != null) {
            return s;
        if (s instanceof Node) {
            for (Spatial child : ((Node) s).getChildren()) {
                Spatial result = findAnimRoot(child);
                if (result != null) {
                    return result;
        return null;

in failingTest I first remove the “walk” clip then save and reload the model and add the clip again and play it, but nothing is played on the model and no error is poped.

I also added a debug mode to get sure if the walk tween is being interpolated and yes it is already being updated by anim composer but nothing happens on the spatial.

Here is the debug output:

interpolate=false , time=1.1401335000991821
May 25, 2019 1:51:16 AM com.jme3.anim.SkinningControl controlRender
INFO: Hardware skinning engaged for Scene (Node)
interpolate=true , time=0.22571951150894165
interpolate=true , time=0.24320552684366703
interpolate=true , time=0.2548838760703802
interpolate=true , time=0.2673773439601064
interpolate=true , time=0.28046389296650887
interpolate=true , time=0.2890698844566941
interpolate=true , time=0.3003846388310194
interpolate=true , time=0.31670890375971794
interpolate=true , time=0.3329110350459814
interpolate=true , time=0.3498958982527256
interpolate=true , time=0.36482047103345394
interpolate=true , time=0.3801583554595709
interpolate=true , time=0.3959277383983135
interpolate=true , time=0.4134633522480726
interpolate=true , time=0.42879048362374306
interpolate=true , time=0.4490779358893633
interpolate=true , time=0.46701435931026936
interpolate=true , time=0.4795372188091278
interpolate=true , time=0.49637261405587196
interpolate=true , time=0.5135316960513592
interpolate=true , time=0.5293561015278101
interpolate=true , time=0.5463519301265478
interpolate=true , time=0.5689896959811449
interpolate=true , time=0.5781451426446438
interpolate=true , time=0.595979530364275
interpolate=true , time=0.6132344976067543
interpolate=true , time=0.628871975466609
interpolate=true , time=0.6444609258323908
interpolate=true , time=0.6690077111124992
interpolate=true , time=0.6781017547473311
interpolate=true , time=0.6954481294378638
interpolate=true , time=0.7164562894031405
interpolate=true , time=0.7300194529816508
interpolate=true , time=0.7446048660203815
interpolate=true , time=0.7672818386927247
interpolate=true , time=0.77814204338938
interpolate=true , time=0.794001636095345
interpolate=true , time=0.8167021675035357
interpolate=true , time=0.8277528146281838
interpolate=true , time=0.843994134105742
interpolate=true , time=0.8688864456489682
interpolate=true , time=0.8781820805743337
interpolate=true , time=0.8948670057579875
interpolate=true , time=0.9121995540335774
interpolate=true , time=0.9276542002335191
interpolate=true , time=0.9440788691863418
interpolate=true , time=0.9670754810795188
interpolate=true , time=0.9777142563834786
interpolate=true , time=0.9941864041611552
interpolate=false , time=1.0176119627431035

I will appreciate if someone gives me a clue of where should I look for the bug :wink:



If anyone wants to give it a try, you can replace the model loading code with your own gltf or j3o model with whatever animation it has and for the light probe you can use your own or just download mine from here:


TransformTrack has a target that references to a Joint or Node (root), I needed to update the target to refer to the new model joints.


GJ! so it work or not? :slight_smile: i understand you fixed it manually just updating target, but the true issue still exist?

Is that because something isn’t getting cloned right? Or do you mean in the clip you added?

Yes, it works now. It is not an issue with JME, it was because of my misunderstanding about how TransformTrack is working.

In my uses case, my character models have no animation saved into the model itself, for example, character_1 with “walk”, “run”, … and character_2 with “walk”, “run”, … instead, I have a base rig which has all the animations like “walk”, “jump”, “kick”, … on it, so for example when I want to add a walk animation to character_1, I just need to get walk animation from the base rig and it to character_1. I hope my explanation is clear enough. Feel free to ask if you think something is unclear.

No, cloning works as it should. So no problem with cloning I gueass.

Yep, it’s about the clip I am adding in code. I should make sure that its transforms are referring to the right model’s joints.

1 Like

why not do it opposite?

you have rig, why not clone rig and just attach model into it?

that is how i do customizable characters (at least i tested on 3.2.2, not sure here but still should work)

Hmm, can you please elaborate on it.
Do you mean you are not rigging each character in blender?
I do not understand how this will work.

i got lets say one file(but it dont need to be one file anyway i think), where i have models:

  • male head
  • male body
  • male hair types
  • female head
  • female body
  • female hair types
  • helmet
  • clothes
  • gloves
  • boots
  • eyes

and many more.

so when i create character, i can change rig models it use.

  1. copy Rig as cloneable node, clean it from Geometries.
  2. calculate what geometries to attach, so clone them from overall model node and attach to cloned rig
  3. scale bones if need (it will also affect clothes, helmet and everything)
  4. use morph changes if need on some geoms

so it all use same rig all the time. with all animations needed.

im not sure if attatchmentNode is also scaled by bone, but anyway i prefer this way instead of attatchment nodes. attatchment Node i use for weapons / etc.

This is, because attatchment node can receive only scale/rot/loc, while bone affect part of verticles, so for example helmet inside rig, will work much better than in attatchmentNode (where can be issues when you scale head via bones)

finally i want split rigs for male and female anyway, but structure will be the same

1 Like

Thanks for the explanation.

One thing I yet do not understand is, for example for the helmet mesh to get influenced by rig, it should be weight painted (for example in Blender). Are you doing this in Blender or somewhere in the code, or SkeletonControl do it automatically?

in blender, but i dont do it all manually, its too much work.

In blender you have something like “automatic weight” that can even work based on bone envelopes.

so what i do is preparing skeleton to have proper “automatic weight” for models.

some of models(example is armor, where some parts cant behave like skin, lets say neck area, where metal would be bent while it should not) will still have wrong paints, so after everything is done, there might be done some fix manual weight paint work for some of models.

1 Like

I see now, thanks so much for explanation.

Actually in my case I use this add-on to auto rig my characters.

I just give it any character model I got from Sketchfab and by pressing a few buttons I get a fully rigged model, then I export it to Gltf.


i seen this, looks cool, dont need it now, but maybe will buy later.

Praise the lord and all that’s holy. This is the bees knees!

1 Like


…going to remember that.