天行健 君子当自强而不息

D3D Animation Basis(1)

The D3DXFRAME object helps form a hierarchy of reference frames. These reference frames are used to
connect a series of meshes together, with each frame having its own transformation to apply to the mesh
connected to it. In this way of using frames to point to meshes, you can minimize the number of meshes used
because you can reference meshes instead of having to reload them.

For example, imagine you have a car that consists of a body and four wheels. The body and wheel form two
meshes. These two meshes are used in conjunction with five frames (one for the body and four for the tires).
When rendering, each frame's transformation is used to position and render the mesh that the frame uses. That
means one frame transforms and renders the body once, while the other frames transform and render the tire
mesh four times.

here is D3DXFRAME's define:

Encapsulates a transform frame in a transformation frame hierarchy.

typedef struct D3DXFRAME {
LPSTR Name;
D3DXMATRIX TransformationMatrix;
LPD3DXMESHCONTAINER pMeshContainer;
D3DXFRAME * pFrameSibling;
D3DXFRAME * pFrameFirstChild;
} D3DXFRAME, *LPD3DXFRAME;

Members

Name
Name of the frame.
TransformationMatrix
Transformation matrix.
pMeshContainer
Pointer to the mesh container.
pFrameSibling
Pointer to a sibling frame.
pFrameFirstChild
Pointer to a child frame.

Remarks

An application can derive from this structure to add other data.

As for the D3DXMESHCONTAINER object, it is used to contain a mesh as well as to link to a series of other
meshes (using a linked list). Why not just use the ID3DXBaseMesh object instead, you ask? Well, there's
more to D3DXMESHCONTAINER than you might expect. First, you can store any type of mesh, whether it's
regular, skinned, or progressive. Second, the D3DXMESHCONTAINER object holds material and effect data.

here is D3DXMESHCONTAINER define:

Encapsulates a mesh object in a transformation frame hierarchy.

typedef struct D3DXMESHCONTAINER {
LPSTR Name;
D3DXMESHDATA MeshData;
LPD3DXMATERIAL pMaterials;
LPD3DXEFFECTINSTANCE pEffects;
DWORD NumMaterials;
DWORD * pAdjacency;
LPD3DXSKININFO pSkinInfo;
D3DXMESHCONTAINER * pNextMeshContainer;
} D3DXMESHCONTAINER, *LPD3DXMESHCONTAINER;

Members

Name
Mesh name.
MeshData
Type of data in the mesh.
pMaterials
Array of mesh materials.
pEffects
Pointer to a set of default effect parameters.
NumMaterials
Number of materials in the mesh.
pAdjacency
Pointer to an array of three DWORDs per triangle of the mesh that contains adjacency information.
pSkinInfo
Pointer to the skin information interface.
pNextMeshContainer
Pointer to the next mesh container.

Remarks

An application can derive from this structure to add other data.

D3DXMESHDATA

Mesh data structure.

typedef struct D3DXMESHDATA {
D3DXMESHDATATYPE Type;
union {
LPD3DXMESH pMesh;
LPD3DXPMESH pPMesh;
LPD3DXPATCHMESH pPatchMesh;
};
} D3DXMESHDATA, *LPD3DXMESHDATA;

Members

Type
Defines the mesh data type.
pMesh
Pointer to a mesh.
pPMesh
Pointer to a progressive mesh.
pPatchMesh
Pointer to a patch mesh.

D3DXMESHDATATYPE

Defines the type of mesh data present in D3DXMESHDATA.

typedef enum D3DXMESHDATATYPE
{
D3DXMESHTYPE_MESH = 0x001,
D3DXMESHTYPE_PMESH = 0x002,
D3DXMESHTYPE_PATCHMESH = 0x003,
D3DXEDT_FORCE_DWORD = 0x7fffffff,
} D3DXMESHDATATYPE, *LPD3DXMESHDATATYPE;

Constants

D3DXMESHTYPE_MESH
The data type is a mesh.
D3DXMESHTYPE_PMESH
The data type is a progressive mesh.
D3DXMESHTYPE_PATCHMESH
The data type is a patch mesh.
D3DXEDT_FORCE_DWORD
Forces this enumeration to compile to 32 bits in size. Without this value, some compilers would allow this enumeration to compile to a size other than 32 bits. This value is not used.
 

Extending D3DXFRAME

By itself, the D3DXFRAME object is very useful, but unfortunately it lacks a few very essential tidbits of
information, namely data for containing transformations when animating meshes, functions to handle the
animation data, and a default constructor and destructor.

To correct these omissions, I have created an extended version of D3DXFRAME, which I call
D3DXFRAME_EX. This new object adds a total of two D3DXMATRIX objects and six functions to the mix.
The two matrix objects contain the original transformation of the frame (before any animation transformations
are applied) and the combined transformation from all parent frames to which the frame is connected (in the
hierarchy).

Here's how I defined the D3DXFRAME_EX structure along with the two matrix objects:

//-------------------------------------------------------------------------------------------
// Declare an extended version of D3DXFRAME that contains a constructor and destructor
// as well as a combined transformation matrix.
//-------------------------------------------------------------------------------------------
struct D3DXFRAME_EX : D3DXFRAME
{
D3DXMATRIX mat_combined; // combined matrix
D3DXMATRIX mat_original; // original transformation from .X

For now, let's
just move on to the functions, starting with the constructor. The constructor has the job of clearing out the
structure's data (including the original data from the base D3DXFRAME object).

D3DXFRAME_EX()
{
Name = NULL;
pMeshContainer = NULL;
pFrameSibling = pFrameFirstChild = NULL;

D3DXMatrixIdentity(&matCombined);
D3DXMatrixIdentity(&matOriginal);
D3DXMatrixIdentity(&TransformationMatrix);
}

On the flip side, the destructor has the job of freeing the data used by the D3DXFRAME_EX object.

~D3DXFRAME_EX()
{
delete[] Name; Name = NULL;
delete pFrameSibling; pFrameSibling = NULL;
delete pFrameFirstChild; pFrameFirstChild = NULL;
}

As you can see, the constructor and destructor are pretty typical in the way those things normally go−initialize
the object's data and free the resources when done. What comes next are a handful of functions that help you
search for a specific frame in the hierarchy, reset the animation matrices to their original states, update the
hierarchy after modifying a transformation, and count the number of frames in the hierarchy.

The first function, find, is used to find a specific frame in the hierarchy and return a pointer to it. If you're
not aware of this, each D3DXFRAME object (and the derived D3DXFRAME_EX object) has a Name data
buffer, which you're free to fill in with whatever text you find appropriate. Typically, frames are named after
bones that define the hierarchy.

To find a specific frame (and retrieve a pointer to the frame's object), just call the find function, specifying
the name of the frame you wish to find as the one and only parameter.

// Function to scan hierarchy for matching frame name
D3DXFRAME_EX* find(const char* frame_name)
{
// return this frame instance if name matched
if(Name && frame_name && !strcmp(frame_name, Name))
  return this;

if(pFrameSibling) // scan siblings
  return ((D3DXFRAME_EX*) pFrameSibling)->find(frame_name);

if(pFrameFirstChild) // scan children
  return ((D3DXFRAME_EX*) pFrameSibling)->find(frame_name);

return NULL; // no found
}

The find function compares the name you passed to the current frame's name; if they match, the pointer to
the frame is returned. If no match is found, then the linked list is scanned for matches using a recursive call to
find.

Next in the line of added functions is reset, which scans through the entire frame hierarchy (which, by the
way, is a linked list of child and sibling objects). For each frame found, it copies the original transformation to
the current transformation. Here's the code:

// reset transformation matrices to originals
void reset()
{
TransformationMatrix = mat_original;

if(pFrameSibling)
  ((D3DXFRAME_EX*) pFrameSibling)->reset();

if(pFrameFirstChild)
  ((D3DXFRAME_EX*) pFrameFirstChild)->reset();
}

Typically, you call reset to restore the frame hierarchy's transformation back to what it was when you
created or loaded the frames. the next function in the list is update_hierarchy, which has the job of rebuilding
the entire frame hierarchy's list of transformations after any one of those transformations has been altered.

Rebuilding the hierarchy is essential to making sure the mesh is rebuilt or rendered correctly after you have
updated an animation. let's just check out the code, which takes an optional transformation matrix to apply
to the root frame of the hierarchy.

// function to combine matrices in frame hierarchy
void update_hierarchy(D3DXMATRIX* mat_trans)
{
// use an identity matrix if none passed
if(mat_trans == NULL)
{
  D3DXMATRIX mat_identity;
  D3DXMatrixIdentity(&mat_identity);

  mat_trans = &mat_identity;
}

// combine matrices with supplied transformation matrix
mat_combined = TransformationMatrix * (*mat_trans);

// combine with sibling frames
if(pFrameSibling)
  ((D3DXFRAME_EX*) pFrameSibling)->update_hierarchy(mat_trans);

// combine with child frames
if(pFrameFirstChild)
  ((D3DXFRAME_EX*) pFrameFirstChild)->update_hierarchy(mat_combined);
}

the update_hierarchy function transforms the frames by their own transformation matrix
(stored in matTransformation) by a matrix that is passed as the optional parameter of the function. This
way, a frame inherits the transformation of its parent frame in the hierarchy, meaning that each transformation
applied winds its way down the entire hierarchy.

Last, with the D3DXFRAME_EX object you have the count function, which helps you by counting the
number of frames contained within the hierarchy. This is accomplished using a recursive call of the count
function for each frame contained in the linked list. For each frame found in the list, a counter variable (that
you provide as the parameter) is incremented. Check out the Count code to see what I mean.

void count(DWORD* num)
{
if(num == NULL) // error checking
  return;

(*num) += 1; // increase count of frames

// process sibling frames
if(pFrameSibling)
  ((D3DXFRAME_EX*) pFrameSibling)->count(num);

// process child frames
if(pFrameFirstChild)
  ((D3DXFRAME_EX*) pFrameFirstChild)->count(num);
}

And that pretty much wraps up the D3DXFRAME_EX object. If you're used to using the D3DXFRAME object
(and you should be if you're a DX9 user), then everything I've just shown you should be pretty easy to
understand.


posted on 2008-04-13 17:37 lovedday 阅读(624) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论