[Solved] How to use: Bone setUserTransformsWorld

I am having some difficulty figuring out how to properly use the setUserTransformsWorld method that is in the bone class.

I am attempting to get some simple inverse kinematics working and almost have it working (the mathematical solution works), but the bones do not move. In the setUserTransformsWorld method it says “Must update all bones in skeleton for this to work.”, but I am at a loss as to how to do this, since all of the update methods for the skeleton and the bones overwrite the world transforms that I set using setUserTransformsWorld.



I tried understanding what is going on in KinematicRagdollControl.java, and they don’t seem to do anything special, just use setUserTransformsWorld, and somehow it works…



In a previous post on the forum (http://hub.jmonkeyengine.org/groups/general-2/forum/topic/setworldposition-for-skeleton-bones/), they solved the problem by disabling the anim control. I have already done this and still no luck.

So I figured out what was going wrong. For anyone who is encountering a similar problem to what I was, this is the solution:



I was not updating the bone positions of the children based on the orientation of the parent. So basically in my implementation, I was ignoring this line from RagdollUtils:

[java]Transform t = childBone.getCombinedTransform(pos, rot);

setTransform(childBone, t.getTranslation(), t.getRotation(), restoreBoneControl, boneList);[/java]

Hi nicholas,

I am quite new to JME and my goal is only controlling the bones of a blender model (a human hand). At the moment I struggle with some testing code on just manipulating a single bone. It sounds like you have such a example. It is possible that you share it?



I have already managed to load my blender model of 2.62 with nightly build, display the skeleton with skeleton debugger and I have also successfully used the KinematicRagdollControl in RagdollMode which shows that it is possible to manipulate my model.



Moreover if I disable AnimationControl, attach the KinematicRagdollControl in KinematicMode and use RagdollUtils.setTransform() in my UpdateMethod I could see that my skeleton transforms but not the geometry of my model.



It would be nice if you could help me!



Thanks in advance!

Ok I got it! The problem seems to be that I have created a model with one skeleton but this skeleton is attached to more than one object, because my model is build up from several objects in parent/child relation (no problem in blender). If I modify a bone of my root object in this hierarchy I can see the geometry transformation. I think I can fix this up with blender. Just one skeleton per object should be possible.



But I still have a problem/question: It seems to be necessary to disable/remove the AnimationController to get control over the bones but if I do that with my blender models they are completely collapsing (geometry and skeleton). I could avoid this by just attaching the KinematicRagdollControl (which could be disabled) . I do not understand that, could someone explain me this behavior?.



I have attached a minimal example based on JmeTests and test-data. To see how the model is collapsing you need to comment the lines with KinematicRagdollControl.





[java]

package mygame;

import com.jme3.animation.AnimChannel;

import com.jme3.animation.AnimControl;

import com.jme3.animation.Bone;

import com.jme3.animation.Skeleton;

import com.jme3.animation.SkeletonControl;

import com.jme3.app.SimpleApplication;

import com.jme3.asset.BlenderKey;

import com.jme3.bullet.control.KinematicRagdollControl;

import com.jme3.bullet.control.ragdoll.RagdollUtils;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.scene.Node;

import com.jme3.scene.Spatial;

import com.jme3.scene.debug.SkeletonDebugger;

import java.util.Set;

import java.util.TreeSet;



public class Main extends SimpleApplication {



private AnimChannel channel;

private AnimControl control;

SkeletonControl skelControl;

Skeleton skeleton;

SkeletonDebugger skeletonDebug;



public static void main(String[] args) {

Main app = new Main();

app.setShowSettings(false);

app.start();

}



@Override

public void simpleInitApp() {

flyCam.setMoveSpeed(10f);

cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f));

cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f));



DirectionalLight dl = new DirectionalLight();

dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());

dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));

rootNode.addLight(dl);



BlenderKey blenderKey = new BlenderKey("Blender/2.4x/BaseMesh_249.blend");



Spatial scene = (Spatial) assetManager.loadModel(blenderKey);

rootNode.attachChild(scene);



Node model = (Node)this.findNode(rootNode, "BaseMesh_01");



control = model.getControl(AnimControl.class);

control.setEnabled(false);

skelControl = model.getControl(SkeletonControl.class);



KinematicRagdollControl ragdoll = new KinematicRagdollControl(0.5f);

model.addControl(ragdoll);

ragdoll.setEnabled(false);



//skeleton = control.getSkeleton();

skeleton = skelControl.getSkeleton();



skeletonDebug = new SkeletonDebugger("Armature", skeleton);

Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

mat2.setColor("m_Color", ColorRGBA.Green);

mat2.getAdditionalRenderState().setDepthTest(false);

skeletonDebug.setMaterial(mat2);

model.attachChild(skeletonDebug);



}



protected Set<String> boneList = new TreeSet<String>();



@Override

public void simpleUpdate(float tpf) {

super.simpleUpdate(tpf);



Bone bone = skeleton.getBone("leg_L.002");



Quaternion PITCH = new Quaternion().fromAngleAxis(FastMath.PI *tpf, new Vector3f(1, 0, 0));



RagdollUtils.setTransform(bone, bone.getModelSpacePosition(), bone.getModelSpaceRotation().mult(PITCH), true, boneList);

}



/**

  • This method finds a node of a given name.
  • @param rootNode the root node to search
  • @param name the name of the searched node
  • @return the found node or null

    */

    private Spatial findNode(Node rootNode, String name) {

    if (name.equals(rootNode.getName())) {

    return rootNode;

    }

    return rootNode.getChild(name);

    }

    }



    [/java]