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

Attaching a weapon to a skinned character hand (3D) - How to...

Last post 7/3/2009 10:12 PM by creasso. 4 replies.
  • 5/16/2009 9:38 PM

    Attaching a weapon to a skinned character hand (3D) - How to...

    Hi.


    I'm working on a game like everyone here, I can't deny that I learnt a lot from here, so I felt that is my time to try give a small contribution to pay back all that I learnt, hope that this helps someone. I warn that there must be some other ways, this one is just a solution that I got hacking some matrices and experiencing, so if you don't have another solution until now you can give this one a try ^^.

    Well, here we go:

    What you'll need:
    - Full access to your skinning processor code (You'll need do some changes if you can't access some bone properties)
    - Your skinned character already working.
    - A model from your weapon (don't need be a skinned one).
    - A bit of patience while setting up your weapon pivot on the 3D software.


    1 - The absolute transform matrix

    You need full access to the Absolute Transform from your hand bone, why? This Matrix sums all the accumulated transforms that our character's hand suffer starting from the root bone, this means that if we replace the original world matrix from our weapon model by this one on the draw call, the weapon will be rendered already on the character's hand. If you are using some of the samples found on the internet to skinned processing, you'll probably find the declaration of your bone class in the "skinning info" namespace.

    public class Bone
    {
        
    public int id; //whatever
        public String name; //whatever
        public Matrix transform; //whatever 

        
    public Matrix absoluteTransform; //YOU REALLY NEED ACCESS TO THIS!

     

        public Matrix inverseTransform; //whatever
        public List<AnimationClip> animationClips; //whatever
        public int parentID; //whatever
        public List<int> childrenIDs; //whatever
        
        public
    Bone()
        {
            childrenIDs =
    new List<int>();
            animationClips =
    new List<AnimationClip>();
        }
    }

    So, find your bone class and make sure that the Absolute Transform is freely accessible, like a public parameter or a property.
     

    2 - Add a getHandMatrix( ) method to your Animation Processor

    To get the skinned transformation to apply on our character's hand bone, we'll first update the Animation Controller (we do this when we call SkinModel.Update(GameTime)) this matrix will point all the transformations to the current frame, if you know exactly which skinnedtransformation matrix you'll need just need point it. There are reasons to the Animation Controller class keep all the matrices like protected, so imo the best way to get just the matrix without break the class security level is add a new method.
     
    public class AnimationProcessor
    {
        protected List<TrilhaAnimao> tracks;
        protected MalhaAnimao model;
        protected Matrix[] combinedFrameTransformations;
        protected Matrix[] worldTrandformations;
        protected Matrix[] skinTransformations;
        int boneCount;

        
    //Add this method
        
    public Matrix getHandMatrix(int ind)
        {
            
    return
    skinTransformations[ind]; 
        }

    ...

    This way you can call this method inside all weapon.update( )s to move the weapon - you can probably access the animation controller from your character, because it is commonly a property in most Skinned Samples - you just need point the index of your bone hand and the returned matrix will be exactly the transformations that must be applied on the animation frame. We are done with the skinnedmodel library and processors, so, just recompile your updated dll and reload on your project references.This way you can call this method inside all weapon.update( )s to move the weapon, you just need point the index of your bone hand and the returned matrix will be exactly the transformations that must be applied on the animation frame. We are done with the skinnedmodel library and processors, so, just recompile your updated dll and reload on your project references. 

    3 - Preparing your weapon/equipment class

    Now, inside your weapon class, you must do some changes to use the information, first you'll add 2 new matrices, one to keep the hand original position, and another to be a variable that will be updated:

    public class GraphWeapon
    {
        
    Model WeapModel;
        String ResourceName;

        // The trick is use the same animation controller than your character, so add a property
        AnimationController AnimControl;
        public AnimationController Animator
        {
            
    get { return AnimControl; }
            set { AnimControl = value; }
        }
        
        Matrix OriginalPos; // The first weapon state
        Matrix AnimatedPos; // The animated weapon state
        
     


    The next step is initialize the matrices, first the OriginalPos one, but, unfortunatelly we can't do this on the constructor because it needs information about a pre-initialized character, so the best place to get it is on inside the Load( ) method, and after your character be loaded by your application, the character or the own application could provide the needed info: 

        public void Load(AnimationController Controller_IN, ...)
        {
            AnimControl = Controller_IN; // links the character controller to the weapon one
            
    Bone Hand = new Bone();
    // temporary bone
            
    Hand = Controller_IN.SkinnedModel.Skeleton.skeleton[X];
            OriginalPos = Hand.absoluteTransform;
    // fills the matrix

            ...
        }


    The other matrix, will get updated info doing a call inside the weapon's update( ) method:

        public void Update( )
        {
            ...
            AnimatedPos = AnimControl.getHandMatrix(X); // here we go! the animated matrix...

            ...
        }



    Now, on our GraphWeapon.Draw( ) method, instead of point the matrix acquired from the model like world parameter, we provide the result from OriginalPos*AnimatedPos:
        
        public
    void Draw(
    )
        {
            ...
            effect.Parameters["World"].SetValue(OriginalPos * AnimatedPos);

            ...
        }



    Done, now we just need care about move and animate our heroes!

    A small note: Inside your 3D package, your weapon's pivot will be the point that will be attached, so if you use the character hand bone, you can consider pull your model pivot a bit forward or the weapon will be drawn on the middle of the character's wrist. You can get this easily in 3dsMax using the Move tool and the Affect Pivot Only option from the hierarchy panel. 
  • 5/18/2009 8:29 AM In reply to

    Re: Attaching a weapon to a skinned character hand (3D) - How to...

    Thank you for your contribution, and I know there are many who want to have this in their games :)
    Petri Wilhelmsen
    Dark Codex Studios

    Blog | Twitter

    Microsoft XNA/DirectX MVP
  • 6/18/2009 6:24 PM In reply to

    Re: Attaching a weapon to a skinned character hand (3D) - How to...

    I am trying to impliment this in my project with no luck. My skinned Data Processor does not have a bone class, or from what I can see an absoluteTransforms matrix. I created a new Matrix[] called boneTransforms and set it to contain the number of bones in my weaponModel (3 i think). I then have this line of code:

    weaponModel.CopyAbsoluteBoneTransformsTo(boneTransforms);
    OriginalPos = boneTransforms.ElementAt(1);

    I dont know if this is doing the same thing as your code, but it doesnt seem to work. Do you know what the absoluteTransforms in your example contain, or have any idea why this doesnt work?
  • 6/29/2009 11:46 AM In reply to

    Re: Attaching a weapon to a skinned character hand (3D) - How to...

    This method works but how do you scale your model??
  • 7/3/2009 10:12 PM In reply to

    Re: Attaching a weapon to a skinned character hand (3D) - How to...

    @Billy Boy: Well, a skinned model IS a model animated by bones, so if you have a character moving arms and etc, your content processor should be reading the bones, anyway, your skeleton should contain objects that are doing the "bone" role, you just need find the type and their names. My code just gets the 0,0,0 placement of the item and moves it to a hand bone position.

    @tadmiral: Usually I do my models with a size reference so is difficult find a situation where I need resize the models at runtime (TIP: on your modelling tool try keep scale while modelling anc check if it fits within your character). In XNA you'll find a function that scale objects "Matrix.CreateScale(x,y,z)". Unfortuntelly when you multiply the AbsoluteTransform by the result the object will leave the character hand, to save time, I advice you to scale the model on the 3D Tool.
Page 1 of 1 (5 items) Previous Next
var gDomain='m.webtrends.com'; var gDcsId='dcschd84w10000w4lw9hcqmsz_8n3x'; var gTrackEvents=1; var gFpc='WT_FPC'; /*<\/scr"+"ipt>");} /*]]>*/
DCSIMG