OgreXML Character Custom Bone Rotation Problems

So this question may be a little advanced and hard to explain, but I’ll do the best I can.  Keep in mind that I’m using a modified version of com.jmex.model.ogrexml.anim.Bone.java as seen here: http://www.jmonkeyengine.com/forum/index.php?topic=12969



So I have an animated ogrexml soldier character for my FPS style game.  My setup is the camera is a CameraNode attached to the head bone of the model, and both the head bone as well as the two shoulder bones are controlled by the mouse using: bone.setUserTransforms()



The character is in a gun holding pose, and my problem is my rotation code to rotate the bones up and down with the mouse/camera sorta matches up.  The problem looks to be that the arms cross or spread out horizontally on the screen.  The issue I think is the shoulder bones, unlike the neck, aren’t aligned to the x-axis of the entire model and are only rotated by their local x-axis.  I hope this makes some sense.  Anyways, the code that I using to get around this isn’t working, I believe my math is incorrect since I’m rather new to Quaternions.  Much like KeyLookDownAction or KeyLookUpAction, my mouse input action has a performAction() method.  It goes like this:

     public void performAction(final InputActionEvent p_event) {
         angle += speed * p_event.getTime();
         angle = FastMath.clamp(angle, (-FastMath.DEG_TO_RAD * 45) + 0.01F, (FastMath.DEG_TO_RAD * 45) - 0.01F);
         
         tempLeftShoulderRot.fromAngleAxis(angle, leftShoulder.getWorldRot().inverseLocal().getRotationColumn(0));
         leftShoulder.setUserTransforms(Vector3f.ZERO, tempLeftShoulderRot, Vector3f.UNIT_XYZ);
         tempRightShoulderRot.fromAngleAxis(angle, rightShoulder.getWorldRot().inverseLocal().getRotationColumn(0));
         rightShoulder.setUserTransforms(Vector3f.ZERO, tempRightShoulderRot, Vector3f.UNIT_XYZ);
         
         tempNeckRot.fromAngleAxis(angle, Vector3f.UNIT_X);
         neck.setUserTransforms(Vector3f.ZERO, tempNeckRot, Vector3f.UNIT_XYZ);
     }



Just to explain the types here are the "declarations":


     private Quaternion
        tempNeckRot = new Quaternion(),
        tempLeftShoulderRot = new Quaternion(),
        tempRightShoulderRot = new Quaternion();


     private final Bone leftShoulder, rightShoulder, neck;
     private float speed;
     private float angle = 0.0F;



I believe this is what I need to convert from a specific shoulder bone space to overall model/node space, except it gives me the results of the arms crossing as I described earlier.  You also may have to look at the Bone.java file to see what the user transform is actually getting multiplied by (esp. the modified version of Bone.java I linked to above).  So what do you think?  Basically, I don't want my arms on screen to move horizontally, but only vertically as like most FPS.  Don't hesitate to ask me to specify something if I haven't explained it throughly enough.

Thanks a million in advance,
SomethingNew  :D

The user transforms are in bone space, while the world transforms are in world space. You can't simply take the inverse of the world transform and set it as a bone transform.

You must operate at only 1 space at the same time.

But doesn't updateWorldVectors() in Bone.java

    /**

     * Updates the world transforms for this bone, and, possibly the attach node if not null.

     */

    void updateWorldVectors(){

        if (parent != null){

            // worldRot = localRot * parentWorldRot

            worldRot = parent.worldRot.mult(localRot);

            //worldRot = parent.worldRot.mult(localRot, worldRot);



            // worldPos = parentWorldPos + (parentWorldRot * localPos)

            worldPos = parent.worldRot.mult(localPos);

            //parent.worldRot.mult(localPos, worldPos);

            worldPos.addLocal(parent.worldPos);

        }else{

            worldRot.set(localRot);

            worldPos.set(localPos);

        }



        if (attachNode != null){

            attachNode.setLocalTranslation(worldPos);

            attachNode.setLocalRotation(worldRot);

        }

    }

update the worldRot with the localRot (i.e. the bind pose * anim * user set transform) multipled by the parents worldRot, so the inverse of that would give me the model space?



I don't think I'm understanding this correctly.  Can I convert between the two spaces to get the desired effect?



As always, thank you so much for your help.  :wink:

Nvm, you were right.  I just needed to change it from worldRot to initialRot.  So my code should have been:

         tempLeftShoulderRot.fromAngleAxis(angle, leftShoulder.getInitialRot().inverse().getRotationColumn(0));
         leftShoulder.setUserTransforms(Vector3f.ZERO, tempLeftShoulderRot, Vector3f.UNIT_XYZ);
         tempRightShoulderRot.fromAngleAxis(angle, rightShoulder.getInitialRot().inverse().getRotationColumn(0));
         rightShoulder.setUserTransforms(Vector3f.ZERO, tempRightShoulderRot, Vector3f.UNIT_XYZ);


So it works now? I really didn't understand what you were trying to do, I just noticed the coordinate systems mistake.

Yeah, I got it working.  :wink: