Mapping Bones to Frames
If you peruse an .X file, you might notice some similarities between the
Frame data objects and the SkinWeights objects. For every bone in your skeletal
structure, there is a matching SkinWeights object embedded inside a Mesh object
that contains the name of a Frame object (or a reference to a Frame object).
That's right−each bone is named after its corresponding Frame data object!
After you load your skinned mesh, you need to connect each bone to its
corresponding frame. This is simply a matter of iterating all bones, getting the
name of each, and searching the list of frames for a match. Each matching frame
pointer is stored in a special bone structure of your design.
I embedded the bone−mapping data in the D3DXMESHCONTAINER_EX structure. The
D3DXMESHCONTAINER_EX structure adds an array of texture objects, a secondary
mesh container object, and the bone−mapping data to the D3DXMESHCONTAINER
structure.
struct D3DXMESHCONTAINER_EX : D3DXMESHCONTAINER
{
IDirect3DTexture9 **pTextures;
ID3DXMesh *pSkinMesh;
D3DXMATRIX **ppFrameMatrices;
D3DXMATRIX *pBoneMatrices;
// .. extra data and functions to follow
};
For this chapter, the important variables are ppFrameMatrices and
pBoneMatrices. The pBoneMatrices array contains the transformations from your
bone hierarchy; one transformation matrix is applied to each vertex belonging to
the appropriate bone. The only problem is, the transformations from your bones
are not stored in an array; they're stored as a hodgepodge of single
transformations spread throughout the hierarchy.
The D3DXMESHCONTAINER_EX structure provides a pointer to each bone
transformation matrix contained within the hierarchy of D3DXFRAME_EX objects
inside an array of pointers (ppFrameMatrices). Using these pointers, you can
pull each bone transformation and place it into the pBoneMatrices array you'll
create and use during the call to update your skinned mesh.
You can create the array of pointers and the array of matrices after you load
the bone hierarchy by taking the number of bones from the hierarchy and
allocating an array of D3DXMATRIX pointers and D3DXMATRIX objects, like this:
// pSkinInfo = skinned mesh object
// Get the number of bones in the hierarchy
DWORD NumBones = pSkinInfo−>GetNumBones();
// Allocate an array of D3DXMATRIX pointers to point to each bones'
transformation.
D3DXMATRIX *ppFrameMatrices = new D3DXMATRIX*[NumBones];
// Allocate an array of D3DXMATRIX matrix objects to contain the actual
transformations
// used to update the skinned mesh.
D3DXMATRIX *pBoneMatrices = new D3DXMATRIX[NumBones];
After you load your skinned mesh, you can set up the pointers to each bone
transformation by querying the skinned mesh info object for each bone name.
Using that, you can scan the list of frames for a match. For each matched bone,
set the pointer to that frame's transformation matrix. When all bones and frames
are matched up, you can then iterate the entire list and copy the matrices to
the pBoneMatrices array.
First let me show you how to match up the bones and frames. Remember that
earlier in this chapter I mentioned that the bones are named after the frames.
Using the ID3DXSkinInfo::GetBoneName function, you can obtain the name of the
bone and frame to match.
// Go through each bone and grab the name of each to
work with
for(DWORD i=0;i<pSkinInfo−>GetNumBones();i++) {
// Get the bone name
const char *BoneName = pSkinInfo−>GetBoneName(i);
When you have the bone's name, you can scan through the list of frames in the
hierarchy to look for a match. To do so, you use the recursive FindFrame
function developed in the "Modifying Bone Orientation" section earlier in this
chapter, as follows.
// pRootFrame = D3DXFRAME_EX root frame object
// Find matching name in frames
D3DXFRAME_EX *pFrame = pRootFrame−>Find(BoneName);
If a frame with the name provided by the bone is found, you can link to the
frame's combined transformation matrix. If no match is found, then the link is
set to NULL.
// Match frame to bone
if(pFrame)
pMesh−>ppFrameMatrices[i] = &pFrame−>matCombined;
else
pMesh−>ppFrameMatrices[i] = NULL;
}
You might not understand the exact reasons for mapping the bones to the frame
at this moment, but it will make more sense when you get into manipulating the
skinned mesh and rebuilding the mesh to render it. For now, take each step in
stride, and start by learning how to manipulate the skinned mesh.
Manipulating the Skinned Mesh
Now nothing is stopping you from twisting up that skeletal structure and
going crazy. Just make sure it's your mesh's imaginary skeletal structure you're
manipulating and not your own−I just hate it when I accidentally manipulate my
bones into a pose I can't get out of for an hour! Kidding aside, you can now
alter the frame orientations in your frame hierarchy. It's those frames that
represent your bones.
Speaking of altering the frame orientations, be aware that you should only
rotate your bones; you should never translate them. Scaling is acceptable, but
be careful−remember that all transformations propagate throughout the hierarchy.
If you were to scale your character's upper arm, the lower arm would be scaled
as well.
I covered changing the orientations of the various bones earlier in this
chapter, in the "Modifying Bone Orientation" section, so I won't rehash anything
here. After you've loaded the skeletal structure and skinned mesh, feel free to
start working with the bone transformations using those techniques covered
earlier. When you're ready, you can update the skinned mesh and prepare it for
rendering.