Controlling Bones programatically

Hi,

I am building an interface to control an avatar using a motion capturing device. For that, I want to control the bones according to the user’s movements. Yet, the classes Bone and Skeleton are giving me a hard time.

While I can set a Bone’s position using:
[java]
RagdollUtils.setUserControl(bone, true);
RagdollUtils.setTransform(bone, localVec, Quaternion.ZERO, true, Collections.<String> emptySet());
[/java]
I see the result displayed in the 3D. But calling
[java]currVec = bone.getLocalPosition();[/java] yields the same result after as before I set the coordinates.

Also, I wonder what is the best way to access the Bones’ Skeleton.

I found
[java]
AnimControl aCont = mySpatial.getControl(AnimControl.class);
aCont.setEnabled(false);
Skeleton sk = aCont.getSkeleton();
[/java]
in this forum, yet this works fine for the Ninja and Sinbad, but not for the models I import. Here only
[java]
SkeletonControl sCont = mySpatial.getControl(SkeletonControl.class);
Skeleton sk = sCont.getSkeleton();
[/java]gives me a skeleton (for AnimControl I get null back) but then I cannot move the bones.

Thanks for your answers,

ruediger05

From my tests (no garanties, it’s the right way). I use the bone.setUserTransforms(…) to modify bones.

on initialization :

  • for each bones : bone.setUserControl(true);
  • for the skeleton : skel.setBindingPose();

My case, I use an non-visible spatial with a rigidbody for each bone head. An use a control attached to parent to modify bones following spatial :

[java]
public class ControlSpatialsToBones extends AbstractControl {
Skeleton skel;
List<BoneAndSpatial> bindings = new ArrayList<>();
Vector3f v0 = new Vector3f();

@Override
protected void controlUpdate(float tpf) {
    bindings.stream().forEach((e) -&gt; {
        v0.set(e.spatial.getLocalTranslation()).subtractLocal(e.p0);
        e.bone.setUserTransforms(v0, e.spatial.getLocalRotation(), e.spatial.getLocalScale());
    });
}

@Override
public Control cloneForSpatial(Spatial spatial) {
    ControlSpatialsToBones control = new ControlSpatialsToBones();
    control.setSpatial(spatial);
    return control;
}

@Override
public void setSpatial(Spatial spatial) {
    bindings.clear();
    skel = Spatials.findSkeleton(spatial);
    if (skel == null) return;
    for(int i = skel.getBoneCount() - 1; i &gt; -1; i--) {
        Bone b = skel.getBone(i);
        Spatial child = ((Node)spatial).getChild(b.getName());
        if (child != null) {
            BoneAndSpatial e = new BoneAndSpatial();
            e.bone = b;
            e.spatial = child;
            e.bone.setUserControl(true);
            e.p0.set(child.getLocalTranslation());
            bindings.add(e);
        }
    }
    skel.setBindingPose();
    
}

@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}

static class BoneAndSpatial {
    Bone bone;
    Spatial spatial;
    Vector3f p0 = new Vector3f();
}

}
[/java]

I hope it helps.

Well… :wink:

Where have you got that Spatials class from?

I don’t understand your question.

In my case I create a spatial R (node) with several children C1, C2,… I attach the ControlSpatialToBones to the node R, then I “bind” bone with children C1, C2 if name of the node == name of the bone. It’s for my use case. I share the code as a sample about how to manage bone programmatically, using children spatial is not the only way.

In line 24, you call [java] skel = Spatials.findSkeleton(spatial); [/java] I was wondering about that Spatials class, which I don’t seem to find.

Thanks :slight_smile:

sorry, it’s my helper class for Spatials :
[java]
public static Skeleton findSkeleton(Spatial spatial) {
Skeleton r = null;
final AnimControl control = spatial.getControl(AnimControl.class);
if (control != null) {
r = control.getSkeleton();
}
if (r == null && spatial instanceof Node) {
Node node = (Node) spatial;
for (int i = 0; r == null && i < node.getQuantity(); i++) {
Spatial child = node.getChild(i);
r = findSkeleton(child);
}
}
return r;
}
[/java]

So the best practice to get a Skeleton for a Control to be coded is to steal it from AnimControl? Why is that and where does AnimControl get it from in the first place?

You could just as easily modify that method to look for SkeletonControl.

In my case I create the model + armature (skeleton) in blender. Then I convert .blend to .j3o via the SDK. If I request the SkeletonControl, I didn’t have bones.

@david.bernard.31 said: In my case I create the model + armature (skeleton) in blender. Then I convert .blend to .j3o via the SDK. If I request the SkeletonControl, I didn't have bones.

Maybe you have more than one skeleton control and searching for the anim control just happens to find the right one.

The anim control adds its skeleton control when attached… and simply asking for the AnimControl doesn’t initialize anything.