Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
84 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Skin Meshes and DirectX 8

It's important before starting to implement our skin mesh code to know how DX deals with skin meshes. There are, of course, many file formats that can store skin meshes but the easiest one for us at this time are the X files that's supported by DirectX. X files can store normal static meshes as well as skin meshes. Before we talk about skin meshes, let's have a general idea about X files. I'll talk about the general design of X files and you can refer to the documentation of DX for more detailed info. X files store data as a set of templates. Like the structures of the C language, templates have definitions that decide how the data will be stored in the instances of this template. For each type of templates, you can have one or more instances. There are many types of templates, each one is supposed to store a specific type of data. Templates can have child templates, enabling us to construct hierarchical scenes. Although it's not mandatory, instances of templates can have names. We won't need to deal directly with all types of templates, DX will handle most of the work for us, but we'll need to have some idea about the following templates before we can start our work.

Frame

This template is used to store a frame. The frame is the building element of the hierarchical scene. Frames have their own transformation matrices and they can hold child objects. Frames can also hold child frames. In skin meshes, a bone refers to a frame.

FrameTransformationMatrix

As the name implies, this is the transformation matrix for the frame. It's instantiated inside the Frame template.

Mesh

This template stores a single static mesh along with its materials. In skin meshes, the whole character will be one single mesh and the skinning information specifies how each part of the mesh is affected by the bones. The mesh will be internally split into subsets; each subset will be affected by a specific set of bones.

XSkinMeshHeader

This template stores information about the nature of skinning information that's exported with the mesh. This template is contained inside the Mesh template.

SkinWeights

The real skinning information is stored here. This template defines how a specific bone can influence the mesh. This template is instantiated once for each bone that influence the mesh, i.e. if there are 12 bones that influence the mesh, the Mesh template will have 12 SkinWeights templates instantiated inside.

The only difference between skin meshes and static meshes is the existence of the XSkinMeshHeader and SkinWeights templates. Removing these two templates from the Mesh template of any skin mesh turns it into a static mesh.

Other templates that we'll also deal with hold the animation data. I'll refer back to them later in this article.

There are good news and bad news. The good news is that DX will handle all the work needed to load the mesh with its materials and its skinning information. The bad news is that we have to do the rest. We'll need to load the frames and construct the hierarchical scene. We'll also need to link the skin mesh to the bones. In general, X files will hold a hierarchy of frames and one (or more) mesh template with skinning info. We'll have to load each of these separately and then manually link the mesh to its bones (frames). Building an X file with a skin mesh is the modeler's task. After modeling the character with any of the commercial applications, the modeler can easily export his model to an X file using special plugins designed for this purpose. On Microsoft's site, you can find plugins for both 3D Max and Maya that exports X files with few mouse clicks. You can even find applications that have built in support for X files.

Now we know how the data is organized in the X file. In order to load the data, we'll need to use the X files library that comes with DX. IDirectXFile is the main interface of the library. IDirectXFile has a method for creating an IDirectXFileEnumObject. The methods of IDirectXFileEnumObject is used to retrieve data from a specific X file. IDirectXFileEnumObject::GetNextDataObject will loop through all the top-level templates in the X file and returns an IDirectXFileData interface. The later is used to retrieve the data of a single template within the X file. Similar to IDirectXFileEnumObject::GetNextDataObject, the method IDirectXFileData::GetNextObject loops through all the child templates and returns an IDirectXFileData interface. The method IDirectXFileData::GetData is used to retrieve the data from the template, but before we can retrieve the data, we need to know the type of the template. The method IDirectXFileData::GetID returns the GUID of the template. For example, if the template is a Frame template, GetID will return TID_D3DRMFrame, which is predefined in the headers of DX. In case you need the name of the instance of that template (as is the case with frames), the method GetName will give it to you.

During our navigation through the X file templates, we'll find a template with a GUID equal to TID_D3DRMMesh, which means that it holds a mesh. It's now time for DX to give us some help. The function D3DXLoadSkinMeshFromXof will load the skin mesh with all the complementary data. Just give it a pointer to the IDirectXFileData interface that you have and it'll do the rest.

The function D3DXLoadSkinMeshFromXof will give us a pointer to an ID3DXSkinMesh object. This object holds the skin mesh. Internally, this object holds the mesh data as groups. Each group is to be transformed by a different set of bones. The function will also return an array of materials to be used by the skin mesh. As I have mentioned before, it's our job to link the skin mesh to the bones. The D3DXLoadSkinMeshFromXof give us a buffer containing the names of all the bones that influence this mesh. It also gives another buffer containing their transforms. We'll use the names to search through our frame hierarchy for the specified bone. The bone transform is a bit confusing. It's supposed that the transform is included in the frame not here. Actually, this transform is the bone offset. So what is the bone offset? It's important to know that all the vertices of the skin mesh are stored relative to one origin, which is the origin of the mesh and not the local origin of the bone. This means that in order to have the influence of the bone on the mesh, we should deform the mesh by the difference between the bone's current transform and the bone's original transform. Or in other words, we should transform the vertices to the bone's local space and then transform them back to the mesh's space using the new transform of the bone. To make this clearer, let's take an example. Let's say we have a bone positioned at (0,50,0) and a vertex positioned at (0,51,0) and let's assume that this vertex is influenced only by this bone. If we moved the bone from it's original position to this new position (0,51,0), the vertex should be moved to the position (0,52,0), but if we simply multiply the vertex by the bone's transform, the vertex will have its new position equal to (0,102,0) which is the wrong coordinate. So, we'll use the bone's offset matrix to transform the vertex from its original position to a position relative to the bone. The new position will be (0,1,0) which will be transformed by the bone's current matrix to the new position, which is (0,52,0). The procedure is as simple as this: when you use a bone, multiply its current transform matrix by the offset matrix and use the result as the world matrix.

Let's get back to our ID3DXSkinMesh object. This object holds the skin mesh in its original form. This object doesn't have any functionality for rendering the skin mesh. So, we'll need first to convert the mesh into an ID3DXMesh object. The function ConvertToBlendedMesh will do the job. Although it's the same object used to render static meshes, the ID3DXMesh obtained from ConvertToBlendedMesh has the difference that its vertices include blending weights, so all we need to do is to enable vertex blending and set our bone matrices before calling the DrawSubset method of the ID3DXMesh. As mentioned before, the mesh will be divided into groups or subsets. Each subset should be rendered with a specific material and a specific set of bones. The structure D3DXBONECOMBINATION specifies the materials and the bones to be used for a single subset of the mesh. An array of this structure is obtained also from the ConvertToBlendedMesh function. All we need to do is to loop through this array, set the material and the bones and then call the DrawSubset method of ID3DXMesh giving it the index within that array.



The Implementation

Contents
  Overview of Skin Meshes
  Skin Meshes and DirectX 8
  The Implementation
  Animation

  Source code
  Printable version
  Discuss this article