Join skeletons in new animation system?

OK, forgive my ignorance, I am trying to get an idea of how to do something that I understand very little about.

Say I have a player model rigged with a skeleton, and I have a model of a pair of pants rigged with the same skeleton. How can I join the two skeletons together so that when the player is animated the pair of pants’ bones are animated with the player?

Is there a way to join/bind the rigs together in jme? I would like to be able to swap out several different clothing models and just have the bones bind to the player models’ bones.

Thanks,
Trevor

1 Like

A SkinningControl transforms all geometries in the subtree it controls. So attach the player model and the pants model to a Node, then add the SkinningControl and AnimComposer to that Node.

2 Likes

Thank you for the fast reply. I did not think it would be anywhere near the simple. I will test that and report back. Thank you.

1 Like

So I am going to assume I perhaps did something wrong.

Is this a bone rotation issue? It is the same rig, but the animated character was exported from a T-pose and the clothing was from a A-pose, would this be an issue?

package io.tlf.jme.test;

import com.jme3.anim.*;
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.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;

public class AnimClothingTest extends SimpleApplication {

    private boolean cursor = false;

    @Override
    public void simpleInitApp() {
        //Import cloths
        Spatial cloths = assetManager.loadModel("Models/daz Joan 2.glb");

        Node world = new Node("world");
        //Load lighting
        JmeLightingState lightingState = new JmeLightingState();
        stateManager.attach(lightingState);

        //Player with walking animation
        Spatial walker = assetManager.loadModel("Models/daz Joan.glb");
        AnimComposer composer;
        SkinningControl skinning = null;

        for (Spatial child : ((Node) walker).getChildren()) {
            System.out.println("Spatial Name: " + child);
            System.out.println("Controls:");
            for (int i = 0; i < child.getNumControls(); i++) {
                Control control = child.getControl(i);
                System.out.println(control.getClass().getName());
                if (control instanceof AnimComposer) {
                    composer = (AnimComposer) control;
                    System.out.println("Animations:");
                    for (AnimClip clip : composer.getAnimClips()) {
                        System.out.println(clip.getName());
                    }
                } else if (control instanceof SkinningControl) {
                   skinning = (SkinningControl) control;
                }
            }
        }

        if (skinning != null) {
            Node root = (Node) skinning.getSpatial();
            root.attachChild(cloths);
        }

        //Add to world
        world.attachChild(walker);
        rootNode.attachChild(world);

        cam.setLocation(new Vector3f(0, 10f, 50f));
        cam.setFrustumFar(5000f);
        flyCam.setMoveSpeed(20f);


        ActionListener tab = new ActionListener() {
            @Override
            public void onAction(String name, boolean isPressed, float tpf) {
                if (!isPressed) {
                    cursor = !cursor;
                    flyCam.setEnabled(cursor);
                }
            }
        };
        inputManager.addMapping("tab", new KeyTrigger(KeyInput.KEY_TAB));
        inputManager.addListener(tab, "tab");

    }

    public static void main(String[] args) {
        AnimClothingTest main = new AnimClothingTest();
        main.start();
    }
}

Could be.