XNA Creators Club Online
Page 1 of 1 (7 items)
Sort Posts: Previous Next

Tracking SkinnedModel Bones

Last post 9/27/2009 5:43 AM by AlectoPerfecto. 6 replies.
  • 9/23/2009 2:36 PM

    Tracking SkinnedModel Bones

    I want to track the position/orientation of a specific bone in a SkinnedModel.  I changed the SkinnedModelProcessor to save the index of the specifc bone I am interested in.  The bone translation is exposed in the AnimationPlayer class like this:

            public Matrix AttackBoneMatrix 
            { 
                get 
                { 
                    return skinTransforms[skinningDataValue.AttackBoneIndex]; 
                } 
            } 

    This works, however the transform seems to be offset from the ultimate bone position.  So that anything using the position and orientation of the AttackBoneMatrix end up mirroring the bone movements, but not at the same position.

    Are there additional processing steps that happen for each bone in a SkinnedModel that I need to take into account?

    Thanks.
  • 9/23/2009 3:12 PM In reply to

    Re: Tracking SkinnedModel Bones

    Need more information.  But the bones are translated by their root bone which is where they are in worldspace i believe.  Their rotations, translations occur from where they originally are in relation tot he pose that your model is in when you exported your fbx file, "im assuming fbx". 

    In my code, based off of skinningsample, I find the bone in the draw part...
  • 9/23/2009 3:30 PM In reply to

    Re: Tracking SkinnedModel Bones

    For a bit more information:

    Here is how I save the desired bone index in the SkinnedModelProcessor:
                int attackBoneIndex = 0; 
                int index = 0; 
                foreach (BoneContent bone in bones) 
                { 
                    if (bone.Name.Equals("Bone.Attack")) 
                        attackBoneIndex = index; 
                    bindPose.Add(bone.Transform); 
                    inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform)); 
                    skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent)); 
                    index++; 
                } 

    Once that index is found, I save it in the SkinningData class:
                // Store our custom animation data in the Tag property of the model. 
                SkinningData sdata = new SkinningData(animationClips, bindPose, 
                                             inverseBindPose, skeletonHierarchy); 
                sdata.AttackBoneIndex = attackBoneIndex; 
                model.Tag = sdata; 

    So now, once the AnimationPlayer is created for this model, I have access to the data for the attack bone.  I use the skin transformation data of the AnimationPlayer to set the position and orientation of another model.
            public override void Update(GameTime gameTime) 
            { 
                Matrix transform = animationPlayer.AttackBoneTransform; 
                this.model.Position = transform.Translation; 
                this.model.Orientation = transform; 
       
                base.Update(gameTime); 
            } 

    So the AnimationPlayer updates as it normally does (and updates all of the skin/bone/world transforms inside of it).  Then I use the transform to position a separate model when it is updated. 

    Based on what you said, should I also save the translation of the parent bone in the modelprocess and use that when determining the tracked bone's position?  In the SkinnedModelProcessor, the bones have a Parent member, but there was not an explicit root bone.  Can I just keep getting the parent of my attack bone until it returns null to find the root bone?

    Thanks for the help!
  • 9/23/2009 4:28 PM In reply to

    Re: Tracking SkinnedModel Bones

    Answer
    Reply Quote

    My Skinned Model Moving Shadow sample on my web site happens to include the code for attaching one model to another.  Try having a look at that.  I use it so the model can hold a weapon in it's hand.

    You appear to be using the skin positions rather than the bone positions.  I would have assumed you would get an odd offset result where your second object is close to where you want it but not quite right.

    The code I use with the worldTransforms is very simple especially if you already know the bone ID.  I use a bone map that saves the string name to the bone ID in the ModelProcessor just by looping through the bones.

    Anyway in summary:
    Update the moving model, so the bones are in the position you want.
    Get the worldTransforms of every bone and select just the bone you need.
    Use that transform for the world position of the object you want to move with your first

    This is from the Model's Update function:

            public void Update(TimeSpan timeSpan, bool bRelativeToCurrentTime, Matrix mtxMoveModel)  
            {  
                if (bCanAnimate)  
                {  
                    // update the main model position  
                    animationPlayer.Update(timeSpan, bRelativeToCurrentTime, mtxMoveModel);  
                    // update all attached models with the position of the main model  
                    foreach (AttachedModels item in itemsAttached)  
                    {  
                        // Move the model to where the model's parent is.  
                        item.modelAttached.setWorldPosition(animationPlayer.GetWorldTransforms()[item.idBone] * mtxWorldPosition);  
                    }  
                }  
            }  
     

    I hope most of the above is obvious but note that the WorldTransforms need to be multiplied by the original models WorldPosition to get the world position for your other model.

    This is another model function:
            public void setWorldPosition(Matrix mtxPosition)  
            {  
                mtxWorldPosition = mtxPosition;  
            }  
     
      
    Note that when called in the above Update example it is applied to the other model not the original moving model.  In my case the attached model is of the same class as the model it is attached to.


    This is from the animationPlayer:
            /// <summary>  
            /// Gets the current bone transform matrices, in absolute format.  
            /// </summary>  
            public Matrix[] GetWorldTransforms()  
            {  
                return worldTransforms;  
            }  
     
    I think it's directly from the Skinned Model sample but I've written so much code it's hard to remember that far back.

    I hope it helps.

    Regards


    **

    Well on the way to creating a 3D First person controls shooter with Over the Shoulder view... Another few YEARS and it'll be done!

    http://games.discoverthat.co.uk/ - Skinning Sample Dude for Blender and XNA Parallel Spilt Shadow Maps plus other stuff...

    My game development blog - Well a few notes from time to time...
  • 9/24/2009 6:37 PM In reply to

    Re: Tracking SkinnedModel Bones

    Thanks.  That was a huge help.  So now the second model draws in the correct place; however, I still need to get position/orientation information from it for collision calculations, etc. 

    Is there a way to extract that information from the World matrix? 
  • 9/24/2009 7:02 PM In reply to

    Re: Tracking SkinnedModel Bones


    There is no built in collision information.
    The model class creates a bounding sphere round the whole object, but I found it very inacurate and usually vastly oversized.

    If you do a search there are some articles about getting the vertex information from the model which you could use for collision.  The best I found was on a blog by Jon Watte (jwatte).  It's not covering collision but it's a simple way to get the vertex information.

    For my purposes I just use two spheres which I manually size for each model.
    **

    Well on the way to creating a 3D First person controls shooter with Over the Shoulder view... Another few YEARS and it'll be done!

    http://games.discoverthat.co.uk/ - Skinning Sample Dude for Blender and XNA Parallel Spilt Shadow Maps plus other stuff...

    My game development blog - Well a few notes from time to time...
  • 9/27/2009 5:43 AM In reply to

    Re: Tracking SkinnedModel Bones

    Ok.  This is what u do... First get the code for displaying bounding spheres.

    2.  there is a command for decomposing world matrices.  That is what i use.  Ill find it and post it alter.  but u decompose it into a vec3 rot, a vec4 trans, and a vec3 scale i believe.  Then you can apply those either using Vector3.Transform or directly, i cant remember right now, and the spheres will accurately follow the bones, believe me I Use it but im isntalling something right now and have to close firefox.
Page 1 of 1 (7 items) Previous Next