How to rotate any arbitrary bone respecting to his axis

Jul 28, 2008 at 6:16 PM
Edited Jul 28, 2008 at 6:19 PM
Hi, my name's Andrea Caronello, an Padova's university's student (Department of information Engineering).
I would like to make a question, if it's possible, about your wonderful XNAnimation library .
I need this information for my final project.
So the question is:
Suppose to load in XNA an arbitrary NON-ANIMATED FBX SKINNED object (which contain a skeleton bones).
"Is it possible to rotate ANY ARBITRARY bone of the object (which I must choose ) respecting to HIS three x ,y and z axis ? "
(I'm referring to the three axis with origin in the barycentre of the bone i would like to transform !!!!)


If yes, could you send me by mail the most (most,most....) simply example-project that shows how to do this operation, please?

I hope I've been clear in explaining my problem and I thank you very very much for this information.
Yours sincerely,

Andrea Caronello
Coordinator
Jul 28, 2008 at 8:17 PM
Edited Jul 28, 2008 at 8:17 PM
Hi Andrea. Thanks for posting your question in the discussions.

Yes. You can load a model with XNAnimation containing meshes and bones (without animations), and then you can modify the mesh's bones to animate it. It is not currently a feature of the library but you can do it manually.

You should first load an animated model and create an animation controller for it:
skinnedModel = Content.Load<SkinnedModel>("myModel");
animationController = new AnimationController(skinnedModel.SkeletonBones);

Then you can retrieve the local bind pose of each bone in the model's skeleton doing this:
Pose[] poses = animationController.LocalBonePoses;

The pose array above contain the transformation of each bone stored as a translation, orientation (quaternion) and scale. And you can modify it anyway you like. But before you use it you will need to convert the pose to a Matrix array, and transform it in absolute transformations. If you look at the XNAnimation source code, it is the code of the UpdateAbsoluteBoneTransforms method of the AnimationController class.

It is not very simple to do but you can do that! =)

After you have it as a matrix array with absolute coordinates, you just set it in the animated model effect before you draw it.
basicEffect.Bones = YourMatrixArray
Jul 31, 2008 at 4:07 PM
Thank you very much for your response. It is not clear to me again, how to convert a pose object in a matrix Array.
I saw the code of UpdateAbsoluteBoneTransformsmethod in the AnimationController class but I don't understood it very much!
Could you post the source code for the conversion of one pose object in the Matrix object, please?
Thank you very much again,

Best  regards, Andrea
Coordinator
Aug 1, 2008 at 5:47 PM
Hi. Sorry for the late reply.

I store each pose as a translation, orientation and scale because it is easy to interpolate and give better results. However I need to convert it to a matrix before I could use it to draw the model. Also, I need to make each pose absolute (not local, where it is relative to its parent pose).

If your bones only has translations and orientations, the code below is enough to transform a pose in a matrix:

Pose poseToConver;
Matrix poseMatrix;
poseMatrix = Matrix.CreateFromQuaternion(poseToConvert.Orientation);
poseTransform.Translation = poseToConvert.Translation;

Then, you must calculate the absolute transformation of each matrix, multiplying it by its parent:

skinnedBoneTransforms[0] = poseTransform * parent;
for (int i = 1; i < skinnedBoneTransforms.Length; i++) {

    // Calculate the matrix for the pose
        poseTransform = Matrix.CreateFromQuaternion(localBonePoses[i].Orientation);
        poseTransform.Translation = localBonePoses[i].Translation;

        // Make its coordinate absolute
        int parentIndex = skeleton[i].Parent.Index;
        skinnedBoneTransforms[i] = poseTransform * skinnedBoneTransforms[parentIndex];
}

In the formal code, parent is an optional parent matrix of all the skeleton (you can remove it if you don't have a parent transformation):
skinnedBoneTransforms[0] = poseTransform;


Aug 15, 2008 at 6:58 PM
Edited Aug 15, 2008 at 7:06 PM
Hi, I'm trying to do the same thing as the original poster, and have mostly gotten it to work, but I'm running into a problem with unwanted scaling while doing the rotations.  I pretty much straight copied the code from the UpdateAbsoluteBoneTransforms, and for sufficiently large rotations, it works great.  However, I am finding that if I rotate the bone more slowly, at some point it begins to scale out of control, but the actual scale stored in the pose doesn't change at all.  I can manually rescale the pose, but that's not a very good solution since I can only do that based on visual sight, I can't just look at the scale stored in the pose and make sure that it remains constant because it does remain constant.  Any ideas of what would cause the scaling to go all out of whack when applying simple x, y, and z rotations of a small magnitude?

I should also point out that this only happens with certain bones, some bones I can rotate just fine, but there are others where they just go crazy.
Nov 24, 2008 at 8:51 AM
Hi,
I tried the things described above but with unsuccess.
I tried to modify the first sample source code inside the XNANimation package to do these things.
Well, I can move each of the bone of the model (the playermarine) but there is still one problem.
I tried with the marine's head.
The rotation of the head of the subject isn't the effect I want to obtain as you can see in the project I posted here.

http://wikisend.com/download/722630/XNAnimation_EXPERIMENTS.rar

The most important pieces of the project are these:
------------------------------------------------------------------
float counter = 0;
GraphicsDeviceManager graphics;
//other instance variables.....

protected override void LoadContent(){
   // Setup camera .....
   // SkinnedModel .....
   // Animation controller .....
   // myMetod
   setAbsoluteTransformationMatrixToSkinnedObject();
}

public void setAbsoluteTransformationMatrixToSkinnedObject(){
   for (int i = 1; i < animationController.SkinnedBoneTransforms.Length; i++){

      Pose currentPose = animationController.LocalBonePoses[i];

      Matrix poseTransform = Matrix.CreateFromQuaternion(currentPose.Orientation);
      poseTransform.Translation = currentPose.Translation;

      int parentIndex = skinnedModel.SkeletonBones[i].Parent.Index;
      animationController.SkinnedBoneTransforms[i] = poseTransform * animationController.SkinnedBoneTransforms[parentIndex];
   }
}


protected override void Draw(GameTime gameTime){
   graphics.GraphicsDevice.Clear(Color.Gray);

   foreach (ModelMesh modelMesh in skinnedModel.Model.Meshes){
      foreach (SkinnedModelBasicEffect effect in modelMesh.Effects){
         // Setup camera
         effect.View = cameraView;
         effect.Projection = cameraProjection;

         // Set the animated bones to the model
         effect.Bones = animationController.SkinnedBoneTransforms;
         
         //other options.....
                  
      }
      modelMesh.Draw();
   }

   base.Draw(gameTime);
}


protected override void Update(GameTime gameTime){
   animationController.Update(gameTime.ElapsedGameTime, Matrix.Identity);          
}

public void transformObject() {
   counter += 0.002f;
   SkinnedModelBone head = getSkinnedModelBone(skinnedModel, "Head" );
   SkinnedModelBone neck = getSkinnedModelBone(skinnedModel, "Neck");
   SkinnedModelBone jaw = getSkinnedModelBone(skinnedModel, "Jaw");

   //transform the head
   animationController.SkinnedBoneTransforms[head.Index] =
   animationController.SkinnedBoneTransforms[neck.Index] =
   animationController.SkinnedBoneTransforms[jaw.Index] = Matrix.CreateRotationX(counter);
}

public SkinnedModelBone getSkinnedModelBone(SkinnedModel skinnedModel, string name)
{
   SkinnedModelBoneCollection skinnedModelBonesCollection = skinnedModel.SkeletonBones;
   foreach (SkinnedModelBone b in skinnedModelBonesCollection)
      if (b.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
         return b;
   return null;
}
------------------------------------------------------------------

I would like the head rotates around HIS X axes (pratically the subject must look down with an inclination of about 50°).
I observed also that commenting or not the invocation of the metod setAbsoluteTransformationMatrixToSkinnedObject in the loadContent
doesn't change the situation;
So, I would like to understand my mistakes. Can you help me?

Thank you very very much,
Best regard

Andrea
Dec 15, 2008 at 3:09 PM

Manipulating Skeletal Model Bones

Hi caro84 Have you solved your problems, if so, could u share your experience.
I am trying to understand the discussion here from the background of the article. Thanks
Dav
Dec 22, 2008 at 10:59 AM
Hi guys. This is what I have done and it works correctly...

// get the current transformation matrix that we want to modify...

Matrix transform = _entity.AnimationController.SkinnedBoneTransforms[_boneIndex];

Vector3 translation = transform.Translation; // save for later use...

 

// move the matrix down so we rotate around the base point correctly.

transform.Translation += new Vector3(0, translation.Y, 0);

 

// apply your transformations here. I’m rotating based on the pitch of the camera.

transform *= Matrix.CreateFromYawPitchRoll(0, _entity.Game.Camera.Pitch, 0);

 

// move the matrix back up again...

transform.Translation -= new Vector3(0, translation.Y, 0);

 

// set the final transformation matrix...

_entity.AnimationController.SkinnedBoneTransforms[_boneIndex] = transform;


Hope this helps someone...
Dec 22, 2008 at 12:46 PM
thanks for sharing, much appreciate. Will try it out.