Control over armature bones

Hi :slight_smile:

Is it possible to dynamically control the bones of an armature? So that I could basically animate my 3D model using some logic written in Java code (as opposed to just playing animation previously recorded in Blender and exported into asset file)?

I’m trying this:

        Spatial anim = assetManager.loadModel("babe.gltf");
        

        AnimComposer ac = anim.getControl(AnimComposer.class);
        if (ac != null) {
            System.out.print("AnimComposer OK\n");
        } else {
            System.out.print("AnimComposer NOK\n");
        }
        
        SkinningControl sc = anim.getControl(SkinningControl.class);
        if (sc != null) {
            System.out.print("SkinningControl OK\n");
            
            Armature armature = sc.getArmature();
            if (armature != null) {
                System.out.print("Armature OK\n");
            } else {
                System.out.print("Armature NOK\n");
            }
        } else {
            System.out.print("SkinningControl NOK\n");
        }

It prints:

AnimComposer NOK
SkinningControl NOK

I’m not even sure if those are the classes I need.

The model looks ok in blender, I can see the bones, and I can play the animation…

I’d be grateful for any tips! Thanks in advance.
Cheers :slight_smile:

I think the keywords are:
Inverse Kinematics, Rag Doll, and Procedural Animation Physics

One of two things is happening:

  1. your asset pipeline (export->import) is such that the skeleton and animations weren’t included. Make sure that the gltf options have them included… probably they do because that’s the default. So the most likely reason is…
  2. that the animation composer and skeleton are actually on a CHILD of the model and not at the root node. This is super common.

Find the child that has the anim composer and then you can get past this step.

Animating a skeleton from java code is exactly how Tamarin works. I’ll dig out a link when i get home

1 Like

I’m able to find AnimComposer / SkinningControl instances using scene graph traversion (as described on wiki):

    private AnimComposer getAnimComposer() {
        var visitor = new SceneGraphVisitor() {
            public AnimComposer foundAnimComposer;
            @Override
            public void visit(Spatial spatial) {
              AnimComposer control = spatial.getControl(AnimComposer.class);
              if (control != null) {
                System.out.println("Instance of " + control.getClass().getName()
                                 + " found for " + spatial.getName());
                foundAnimComposer = control;
              }
            }
        };
        rootNode.depthFirstTraversal(visitor);
        
        return visitor.foundAnimComposer;
    }

However, it is tricky to identify which instance to use, in case I loaded more than one 3d mode assets…

EDIT: ok, I managed to identify them using control.getSpatial().getParent() for comparision - the AnimComposer seems to be a direct child of the Spatial created by assetManager.

Now I just need to figure out how to use SkinningControl and/or AnimComposer class in order to control the bones. :thinking:

You can modify a bone local transform

Here is Tamarin getting the bones out of a Geometry

Here is the core bit where Tamarin uses some java data to update the bones

I believe the SkinningControl will be automatically present if the model has been created properly. Tamarin uses j3os but I think it should work fine with other formats

It’s often predictable based on the original scene structure and the names of your objects in Blender.

Thank you @richtea @pspeed @Ali_RS
With your help I made it work :slight_smile:

In case anyone will be looking for the answer:
So first - you need to find appropriate instance of SkinningControl attached to the Spatial of your loaded model. Use similar code as in Tamarin project.
Then the SkinningControl class has getArmature() method. Accessing bones from armature instance can be done via getJoint("bone name") (or you can access the list of all bones (joints)). Then each bone (Joint class) has methods like setLocalRotation(q) etc.

https://javadoc.jmonkeyengine.org/v3.3.0-beta1/com/jme3/anim/Armature.html
https://javadoc.jmonkeyengine.org/v3.3.0-beta1/com/jme3/anim/Joint.html#setLocalRotation-com.jme3.math.Quaternion-

3 Likes