Weapon attachment points

Started by
10 comments, last by fuchiefck 18 years, 9 months ago
Hi all, I want to implement weapon attachment points on my model, so I can attach a sword to its back, or let it hold it in his hand and so on... i have no idea on how to do this.... can anyone give me some advice? thanks very much in advance... -fuchiefck
-fuchiefck----------------------------------------------------------"Inside the world that you as a programmer or developer create, you are God" - Zerbst & Duvel
Advertisement
Hello fuchiefck,

There are two common possible ways that I know of...

Way the first:
When you build your model, if you're using bones (which I happen to know that you are), then you can add an extra bone attached to the hand bone. The biped tool in 3DS Max actually has "props" you can add to him and animate. Then attach one to the back of the model as well.

Then, when you want to attach a mesh to that point you just have to render the mesh as if it were a meshcontainer of that bone. And by that I mean use the bone's CombinedTransformationMatrix as the parent to the mesh your going to attach when you render it.

Way the second:
Instead of attaching dummy bones you can fake it by adding your own frame in the software to the hierarchy where ever you might want to attach something, then continue like above. And you don't even really need a frame, you just need to store an offset matrix from the bone it's being attached to. (with the proper rotations and such. Little more confusing and work...

I think the first option is easier to implement since you can actually animate the attachment bone and rotate it properly right in your modeling tool. But then if you have LOTS of attachments, or if you want to add one later you have to edit the model. If you setup the second method properly you could actually attach things on the fly.

For example. Lets say you have a pouch, and you want to put it on his belt.
Well you have a CombinedTransformationMatrix for this hip bone which is the bones absolute position in the world. You also know the scale size of the model (if you scaled it) that matrix would be somewhere. You can keep a constant of how wide it is from bone to hip normally.

So all you'd have to do is scale the distance to the outside of the skin if you scaled the entire model at all, then offset the hip bone's location by that much, and then render your pouch there. And it should animate along with the hip!

If you did it with the thigh bone you could even make it look like it's swinging as he walks.

Hope this gives you some ideas.
Good Luck,
-------------------------------------------------------------------Life is short so go on and live it, cause the chicks dig it.- Kahsm
Thanks Kahsm, nice to hear from you again...

thanks for your recommendations on attachments, I will start on it later. right now I'm still stuck at the replacing mesh container part... :(

ok... the model of the person is a skinned mesh, as you prolly already know. I have made the whole arm as one mesh container. Now I want to replace the arm with a new arm... I have successfully cloned the mesh, and copied over the textures. But when it animates its screwed... :(

first time, I replaced it with an arm with no bones.. the result was.. when the person animates (runs), the arm doesn't bend as it should, and its position is a bit off, and also, the replaced part is separated from the rest of the body (skin doesn't stretch anymore). Second time, I replaced it with an arm that has a bone in it, and is a skinned mesh. When the person runs again, the mesh morphs into weird shapes... (it looks like the mesh of the arm doesn't move, but the bone inside it is moving, and its stretching the mesh).

As I use the code from the SkinnedMesh sample, I have the function GenerateSkinnedMesh.

I tried, after I cloned the mesh, call GenerateSkinnedMesh again on the replaced part. But that only generates the old mesh back.... so I end up with the old mesh again....

I tried memcopying the pSkinInfo, and all the other pointers from the new one to the old one.... nothing happens or the program just crashes....

what else can I do...???

you mentioned you have done something like this before, did you ever come across these problems? was there anything to look out for when drawing the models? my models are created in 3ds max....

thanks again...........

-fuchiefck
-fuchiefck----------------------------------------------------------"Inside the world that you as a programmer or developer create, you are God" - Zerbst & Duvel
The problem you're facing is that the animation controller is changing the transformation matrices for the frames in the original mesh.

When you just apply a new meshcontainer to a frame that doesn't have bones, that meshcontainer doesn't have any skinning information for the bones that are moving. So, it won't blend, or if it has it's own bones, it won't have the PROPER skinning information, and won't bend correctly.

What I do is, in Max I take my person model and I get rid of the mesh (leaving the bones). Then I model my replacement skin onto the original bone structure (this way I know the bones will line up perfectly). Even if it's just an arm that I'm replacing then I'll just model the arm on the whole skeleton. This also works really well because you'll know it lines up nicely with the rest of the skin. When I export, I export only the new mesh and the bones which are actually used by that mesh, but none of the animations which that skeleton has.

So now you could load up the mesh and render it, and it would do nothing but sit there at it's neutral place because it has bones but no animation.

But, when you want to attach it to your model you know that the bones in your replacement line up with the bones in your original skeleton. So.... *Drum roll*

When you're doing skinned meshes, your meshcontainer is usually influenced by more than 1 bone, so you should have a step where you recurse through your skeletal tree and save pointers to the bones that affect each meshcontainer right?

Mine looks like this: (in C# of course)
public void SetupBoneMatrixPointers(Direct3D.Frame frame, XEntity replacementFor)		{			if(frame.MeshContainer != null)			{				SetupBoneMatrixPointers(frame.MeshContainer, replacementFor);			}			Direct3D.Frame nextFrame = frame.FrameFirstChild;			while(nextFrame != null)			{				SetupBoneMatrixPointers(nextFrame, replacementFor);				nextFrame = nextFrame.FrameSibling;			}		}		/// <summary>		/// Found a mesh container, filling in the pointers.		/// </summary>		/// <param name="meshContainer">The meshcontainer to edit</param>		public void SetupBoneMatrixPointers(Direct3D.MeshContainer meshContainer, XEntity replacementFor)		{			if(meshContainer.SkinInformation != null)			{				ExtendedMeshContainer extendedMeshContainer = (ExtendedMeshContainer)meshContainer;				int numberBones = extendedMeshContainer.SkinInformation.NumberBones;							extendedMeshContainer.BoneFramePointers = new ExtendedFrame[numberBones];				extendedMeshContainer.BoneOffsetMatrices = new DirectX.Matrix[numberBones];				for(int bone = 0; bone < numberBones; ++bone)				{					Direct3D.Frame animationRoot;					if(replacementFor != null)					{						// Use the bones from the person so that this mesh will be animated						animationRoot = replacementFor.RootFrame;					}					else					{						// Use this mesh's bones so that it won't be animated						animationRoot = _rootFrame;					}					ExtendedFrame frame = (ExtendedFrame)Direct3D.Frame.Find(animationRoot, extendedMeshContainer.SkinInformation.GetBoneName(bone));					extendedMeshContainer.BoneFramePointers[bone] = frame;					extendedMeshContainer.BoneOffsetMatrices[bone] = extendedMeshContainer.SkinInformation.GetBoneOffsetMatrix(bone);				}			}		}


You can see I recurse down my bone hierarchy and every time I find a MeshContainer I find all the bones that influence that meshcontainer according to the BoneCombination table and save them so that when I render, they are handy.

Now, you'll also see I added this "replacementFor" stuff. That's for my attachments. If replacementFor is not null, that means I'm setting this mesh entity up to be a replacement for that item, and instead of using pointers to it's OWN bones, I use the pointers to the original skeleton's bones, the ones that are animated.

Once these bone pointers are setup, your replacement mesh should snap into place, as it will now be rendered with the original skeleton's matrix data instead of it's own, and it will have the proper skinning information because it was skinned onto an exact replica originally.

Get it? need some clearing up?

Edit: My horrible early morning writing, and commented the code a bit
-------------------------------------------------------------------Life is short so go on and live it, cause the chicks dig it.- Kahsm
Kahsm, thanks sooo much again... its very hard to find help on what i am trying to do... maybe you should be the first person to create a tutorial on this..!
just a few things to clear up...
Quote:Original post by Kahsm
What I do is, in Max I take my person model and I get rid of the mesh (leaving the bones). Then I model my replacement skin onto the original bone structure (this way I know the bones will line up perfectly).

This is what i have assumed as well, so all the skins created are from the same skeleton... But as you said I should export the bones with the part right? and no animations for that part...
Quote:Original post by Kahsm
When you're doing skinned meshes, your meshcontainer is usually influenced by more than 1 bone, so you should have a step where you recurse through your skeletal tree and save pointers to the bones that affect each meshcontainer right?

You can see I recurse down my bone hierarchy and every time I find a MeshContainer I find all the bones that influence that meshcontainer according to the BoneCombination table and save them so that when I render, they are handy.

Does this mean when i replace something, I should save the bone pointers for the whole person, or just the replaced part?
Quote:Original post by Kahsm
Now, you'll also see I added this "replacementFor" stuff. That's for my attachments. If replacementFor is not null, that means I'm setting this mesh entity up to be a replacement for that item, and instead of using pointers to it's OWN bones, I use the pointers to the original skeleton's bones, the ones that are animated.

So the "replacementFor" is the new mesh that I am replacing with?

again, thanks so much for your help... I am going to dive into this now... once this is done (hopefully..!), i shall PM u my demo... :)

-fuchiefck
err... that was me... dunno why i was logged out... :0

-fuchiefck
-fuchiefck----------------------------------------------------------"Inside the world that you as a programmer or developer create, you are God" - Zerbst & Duvel
umm, another question...

extendedMeshContainer.BoneFramePointers = new ExtendedFrame[numberBones];

Is BoneFramePointers a frame? does it represent the bones that influences the meshcontainer? umm, my derived mesh container has the following variables...
//from the SDK skinnedmesh sampletypedef struct _D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER{    LPDIRECT3DTEXTURE9*  ppTextures;    LPD3DXMESH           pOrigMesh;    LPD3DXATTRIBUTERANGE pAttributeTable;    DWORD                NumAttributeGroups;     DWORD                NumInfl;    LPD3DXBUFFER         pBoneCombinationBuf;    D3DXMATRIX**         ppBoneMatrixPtrs;    D3DXMATRIX*          pBoneOffsetMatrices;    DWORD                NumPaletteEntries;    bool                 UseSoftwareVP;    DWORD                iAttributeSW;    std::vector<CString> TextureFileNames;}


what else would i need?

and if I do need this pBoneFramePtr, how do i initialise it in my CreateMeshContainer function?

thanks again...
-fuchiefck----------------------------------------------------------"Inside the world that you as a programmer or developer create, you are God" - Zerbst & Duvel
Quote:
This is what i have assumed as well, so all the skins created are from the same skeleton... But as you said I should export the bones with the part right? and no animations for that part...


Correct. The only reason you need to export the bones at all is because you need the skin information and the names of the bones(frames) so you can find them again in the animating skeleton.

Quote:
Does this mean when i replace something, I should save the bone pointers for the whole person, or just the replaced part?


and...

Quote:
So the "replacementFor" is the new mesh that I am replacing with?

again, thanks so much for your help... I am going to dive into this now... once this is done (hopefully..!), i shall PM u my demo... :)


Hrm...
When you draw a mesh container, despite your rendering method, you need to setup the matrix palette based on the original frame offset matrix and the combined transformation matrix for each frame(bone) that influences the vertices in the current mesh subset right?

Your custom mesh container should probably have an array to store pointers to those matrices, then you can use functions like the ones I have above to set the pointers.

When you load your person with the full skeleton, he would have pointers to his own skeleton.

When you load the replacement mesh, it would start with pointers to it's own skeleton.

When you attach the mesh, all you need to do is set the pointers to the animating skeleton instead of the mesh's original non animated bones and it will attach itself.

This is probably the most confusing part of the whole process, and it's kind of hard to explain, and there's lots of scattered source involved. The Skinned Mesh example has a C++ example of those functions I gave you, it calls the function SetupFrameMatrices() I believe. That might help you get a better idea of how it's used, if you don't have your own at the moment.

Then you just have to realize that if you do the same thing but instead of using the root frame from the new mesh's mesh container, you can use the root frame from your original skin, then it will animate along with your model. That's why I have replacementFor, it's not the new mesh, it's the original mesh so I can get the root frame of the animated skeleton out of it.

If replacementFor is null, then the new mesh will use it's own unanimated bones.

I think I'm just repeating myself now. I'm not sure how else to explain it. Don't really have the time to break out diagrams =) But I might.

I have actually considered writing a tutorial.

Good Luck,
-------------------------------------------------------------------Life is short so go on and live it, cause the chicks dig it.- Kahsm
As for you next quesiton...

Quote:
extendedMeshContainer.BoneFramePointers = new ExtendedFrame[numberBones];

Is BoneFramePointers a frame? does it represent the bones that influences the meshcontainer? umm, my derived mesh container has the following variables...


Ahh right forgot about that. In C# a matrix is a structure not a class, and you can't get a pointer to a structure. The frame however, is a class, and classes are always pointers. All I need out of that frame is the matrix, but I save a pointer to the frame so I know that it _IS_ a reference and not a copy. You don't need that. Instead you need...

These two...
D3DXMATRIX** ppBoneMatrixPtrs;
D3DXMATRIX* pBoneOffsetMatrices;

These are the members I've been talking about.
These are the C++ equivalents to the two arrays I set in thoes functions.

ppBoneMatrixPtrs replaces my BoneFramePointers.

As I mentioned, take a look at the SkinnedMesh example for where those two are used, it should clear a lot up.
-------------------------------------------------------------------Life is short so go on and live it, cause the chicks dig it.- Kahsm
Hi again, hmmm sorry i know its hard to explain everything here, I think i know what you are talking about now... seems like I haven't fully understood the skinned mesh sample yet... esp on the matrices for the bones.. :[ btw... how should the hierarchy be set up in the model? currently, the model i am working with:

[+]Bipe01 - the bipe hierarchy created in Max
[-]Head
\_(head mesh)
[-]Body
\_(body mesh)
[-]L_Arm
\_(L_Arm Mesh)

.
.
.

So as you can see, the Frames with mesh containers are not part of the Bipe hierarchy.... does this matter? as far as I know, some models have meshes in the bipe hierarchy, and some (eg tiny.x) has a Bipe and one single mesh container separate from the bipe....

thanks....

EDIT: I guess the format of the hierarchy does not matter... now that I understand, each mesh container, if influenced by any bones, will contain matrix pointers referencing to the frames in the bipe hierarchy...

[Edited by - fuchiefck on June 30, 2005 3:58:47 AM]
-fuchiefck----------------------------------------------------------"Inside the world that you as a programmer or developer create, you are God" - Zerbst & Duvel

This topic is closed to new replies.

Advertisement