Using d3d to implement skin Meshes

Source: Internet
Author: User
Author: Hua buxiang
Source file address
Http://www.gamedev.net/reference/articles/article1835.asp

The following is a translation:
Implementing skin meshes with DirectX 8
By Sarmad KH Abdulla

Skin meshes or bone meshes is one of the most important topics in the 3D world. Skeleton animation is always watched as an important role for them to make up woven activities. The skeleton animation is based on the simple activity idea that the object shape is composed of multiple skeleton and can be changed by the position and direction of the skeleton. You can find many theoretical resources to discuss this topic, but this article discusses how to use d3d8 and d3dx to implement bone meshes. But before I start to discuss the implementation, I will give a quick review on the skin meshes in the mathematics module.

Skin meshes Overview
Skin meshes is a type of hierarchical scene. Hierarchical scene is used to connect objects. For example, the finger belongs to the palm of the hand, and the palm belongs to the forearm. The coordinates of each object are given relative to the local space of the object. Therefore, rotating the forearm also causes the movement and rotation of the palm and fingers. The following illustration shows how the human body is constructed using a layered scenario.

  

Mathematical formulas can easily represent this scenario. matrix algebra is the key. Given the scenario, if we consider the transformation matrix from the forearm matrix to the forearm, the transformation matrix from the palm matrix to the palm matrix and the transformation matrix from the finger matrix to the finger, then, we can simply calculate the transformation matrix between fingers and the world by the following formula:

Fingerworldmat = fingermat * palmmat * forearmmat *... * bodymat

In the above formula, we consider that the basis of the layered scenario is the body. Therefore, its matrix is relative to the world space. Some of our mesh splits into the local, where each part is transformed by the world matrix of a specific skeleton, which will make it easy for us to move the mesh.

However, some characters are composed of separated and fixed sub-objects. This practice is not accepted because it may cause cracks at the joints. In the future, it will rise to skin meshes. Skin meshes overcomes this problem by changing the shape of an existing part of a character based on its location and skeleton orientation. Skin meshes also has a skeleton system, but a single part of a skin mesh can be transformed by more than one skeleton. In the following linear interpolation formula, vertices can have their positions affected by two (or more) skeleton instead of one skeleton. In the following ways, we can overcome the cracks. This technology is called vertex blending ). Vertex mixing requires that each vertex have a hybrid weight so that vertex profiling can determine how the skeleton affects vertices. For example, if one vertex is affected by two frames, the following formula will give the world coordinates of the vertex as being affected by the two frames:

Vw = VM * m1 * w + VM * m2 * (1-W)

In the preceding figure, the VW is the position of the vertex in the coordinates of the world. VM is the local space location of the vertex relative to the model. M1 and M2 are the transformation matrices of the two frameworks. W is a hybrid right. Note that the hybrid weight requires the skeleton number to be less than 1.

You can refer to the dx8 document for more details about vertex mixing.

Skin meshes and DirectX 8
It is important to know how DX handles the skin mesh before implementing our skin mesh code. Of course, there are many file formats that can store the skin mesh, but the easiest one at this time is the X file. X Files can store standard static meshes and skin meshes. Before we discuss skin meshes, let's have a general concept of X Files. I will discuss the general design of the X file and you can refer to the DX document for more details. X file storage data as a set of templates. Like the C speech structure, templates have definitions that determine how data is stored in the template instance. You can have one or more instances for each type of template. There are many types of templates, each of which is considered to be a dedicated data type. The template can be a subclass template that enables us to construct a layered scenario. Although it is not mandatory, the template instance can have a name. We don't need to process all types of templates directly. dx will handle most of the work for us, but before we can start working, we need to have some concepts about the following templates.

L Frame
A template is used to store a framework. A framework is used to construct a layered scenario. Frameworks have their own transformation matrices and they can contain subclass objects. The framework can also contain subclass frameworks. In the skin mesh, a skeleton references a framework.

L frametransformationmatrix
Like the name implies, This is the transformation matrix of the framework. It is used in the Framework template for instance description.

L Mesh
The template stores a single static mesh with its material. In the skin mesh, the entire character uses a mesh and s skin information specifies how each part of the mesh is affected by the skeleton. The mesh splits internally into sub-objects. Each sub-object is affected by a specific setting of a skeleton.

L xskinmeshheader
This template stores the natural information about the skin, which is output by mesh. This template is included in the mesh template.

L skinweights
Real skin information is stored here. The template defines how a specific skeleton affects the mesh. That is, this template is described once for each skeleton that affects the mesh. If there are 12 skeleton objects that affect the mesh, the mesh template will have 12 skinweights templates described internally.

The difference between skin mesh and static mesh is only the existence of xskinmeshheader and skinweights templates. Moving the two templates from any skin mesh template changes them to a static mesh.

We will also process activity data for other templates. I will mention them later in the article.

There are good news and bad news. The good news is that DX will process all the work and read the material and skin information of the mesh. Bad news is what we have to do. We will need to read the framework and construct a layered scenario. We will also need to connect the skin mesh to the skeleton. In general, the X file will contain a framework hierarchy and A (or more) mesh template with skin information. We will read the layered structure and mesh template of each frame independently, and then manually connect the mesh to its skeleton (framework ). Creating an X file with a skin mesh is the task of creating a model. After using any commercial software to create a person, it is easy for the model maker to use a special plug-in designed for this purpose to export its model to an X file. On the Microsoft Web site, you can find the plug-in that exports the X file for 3dmax and Maya. You can even find an application that supports creating X Files.

Now we know how data is organized in X Files. To read data, we need to use the X file library. Idirectxfile is the main interface of the library. Idirectxfile has a method to create idirectxfileenumobject. The idirectxfileenumobject method is used to retrieve data from a specified X file. Idirectxfileenumobject: getnextdataobject cyclically uses all the top-level templates in the X file and returns an idirectxfiledata interface. Later, the X file is used to retrieve the data of a single template. Similar to idirectxfileenumobject: getnextdataobject, The idirectxfiledata: getnextobject method cyclically uses all subclass templates and returns an idirectxfiledata interface. Method idirectxfiledata: getdata is used to retrieve data from the template. However, before we can retrieve data, we need to know the template type. Method idirectxfiledata: GETID returns the template guid. For example, if the template is a framework template, GETID returns tid_d3drmframe, Which is pre-defined in the DX header file. If you need the name of the template instance (as if using the framework), the getname method will give you the name.

During the process of using the X file template, we will find a template with a guid equal to tid_d3drmmesh, which means it contains a mesh. It is time for DX to help us. The d3dxloadskinmeshfromxof function reads the skin mesh and all the remaining data. Only give it a pointer to the idirectxfiledata interface and it will do the rest of the work.

The d3dxloadskinmeshfromxof function will give us a pointer to the id3dxskinmesh object. This object contains the skin mesh. Internally, this object contains mesh data as a group ). Each group is changed by a different skeleton. The function also returns a material data used by the skin mesh. As I mentioned earlier, our job is to connect the skin mesh to the skeleton. D3dxloadskinmeshfromxof gives a buffer that contains the names of all the frameworks that affect the mesh. It also gives other buffers to include their transformations. We will query the layered structure of our framework using the specified skeleton. The skeleton transformation is a bit confusing. Assume that the transformation is not included in the Framework here. In fact, this transformation is a skeleton offset (bone offset ). What is the skeleton offset? It is important to know that all vertices of the skin mesh are stored in a relative origin point, which is the origin point of the mesh and not the local origin of the skeleton. This means that in order to have a skeleton impact on the mesh, we should make the mesh deformation from the difference between the current transformation of the skeleton and the origin transformation of the skeleton. In other words, we should transform the vertices to the local space of the skeleton, and then transform them back to the mesh space to use the new skeleton transformation. To give us a clearer concept, let's give an example. Let's talk about how to place a skeleton in (, 0) and a vertex in (, 0) and let's assume that this vertex is only affected by one skeleton. If we move the skeleton from its original position to the new position (, 0), the vertex should be moved to the position (, 0 ), but if we simply change from a skeleton to a vertex, the vertex will have a new position equal to (0,102, 0), which is the wrong coordinate. Therefore, we use the skeleton's offset matrix to transform the vertex from its original position to a position relative to the skeleton. The new position will be (0, 1, 0). It will be transformed by the current matrix of the skeleton to the new position, which is (0, 52, 0 ). The simple procedure is as follows: when you use a skeleton, multiply the offset matrix by its current transformation matrix and use the result as the world matrix.

Let's return to our id3dxskinmesh object. This object contains the skin mesh in its prototype. This object has no function to render the skin mesh. Therefore, we need to first convert the mesh into an id3dxmesh object. The converttoblendedmesh function will do this. Although it is the same object that is used to render static mesh, id3dxmesh obtains the difference from converttoblendedmesh that its vertices contain hybrid weights, therefore, we need to enable vertex mixing and set our skeleton matrix before calling the drawsubset method of id3dxmesh. As mentioned above, the mesh is split into groups or sub-objects. Each sub-object should be rendered together with a specified material and a specified skeleton setting. The d3dxbonecombination structure specifies that the material and skeleton are used for a single sub-object of a mesh. The array of the structure is also obtained from the converttoblendedmesh function. What we need to do is to use this array cyclically, set the material and skeleton, and then call the drawsubset method of id3dxmesh to give it the subscript in the data.

Implementation
Now we are ready to start writing code to implement our skin mesh. The design of most important parts is as follows. The following illustration shows the design of our code:

  

The illustration does not show the members of all classes. It only shows important things. As shown in the illustration, the class cmeshnode and cframenode are divided from the cobject. The purpose of cobject is to provide connections to three organizations; any object is divided from the cobject and will be able to connect to a connection tree. Cframenode is an element that establishes the layered structure of our scenario and the cmeshnode contains its own mesh. Cmeshnode is included in cframenode, and cframenode is included in cskinmesh. The entire scenario begins in cskinmesh because it contains the basic framework. All operations related to the skin mesh will be initialized in the cskinmesh class. It will pass control to the layered structure in sequence as necessary. Therefore, the main program will only process the cskinmesh; cframenode and cmeshnode will be associated only by cskinmesh.

The following algorithms show how to create a file from X:
Cskinmesh: Create ()
Begin
Initialize X file API
Register d3drm templates
Open the X file
For every top level template in the X file
Begin
Retrieve the X file data object
Pass the data object to rootframe. Load
End
Link the bones to the skin mesh (es)
End

Cframenode: load ()
Begin
Check the type of the Data Object
If the type is mesh
Begin
Create new cmeshnode object
Attach the new object to the frame
Pass the data object to cmeshnode: Create of the new mesh
End
Else if type is frametransformationmatrix
Load the transformation matrix
Else if type is frame
Begin
Create new cframenode object
Attach the new object to this frame
Set the name of the child frame to the name of the template
For every child template of the current
Begin
Retrieve the X file data object
Pass it to newframe. Load
End
End
End

Cmeshnode: Create ()
Begin
Set the name of the object to the name of the template
Load the skin mesh
Generate blended mesh from this skin mesh object
Load Materials
End

After building the skin mesh, we can start rendering it. The rendering operation contains two phases. During the first phase, the world of all skeleton is calculated (value-added through matrix) and stored in the cmeshnode object. During the second phase, the skin mesh will be rendered. The following algorithms show this operation:
Cskinmesh: render ()
Begin
Calculate the world matrix of all the frames
Call cmeshnode: render of all mesh nodes in the hierarchy
End

Cmeshnode: render
Begin
Enable vertex blending
For every subset in the skin mesh
Begin
Set the bones 'transformation matrices to the device
Set the material
Render
End
Set vertex blending back to Disabled
End

Animation in X file
Animations are not specifically used for skin mesh in X Files; they can be applied to any frame in X Files. X Files store the key frame framework and applications should generate linear interpolation in the framework. There are four types of animation key frames: rotation, scaling, location, and matrix key frames. Rotation is stored as a quaternions method and can be interpolated by spherical linear interpolation. The d3dxquaternionslerp function is provided by d3dx to implement spherical linear interpolation. The following X file template is used to store animations:

L animationkey
This template is used to store animation key frames. Each instance of the template contains an array of key frames (location, zoom, rotate, or matrix. Each element contains the key frame value and the time specified by the DWORD Value in the array.

L Animation
This template stores the animation key frames of the specified frame. It should contain at least one animationkey template. It should also contain a standard target framework.

L animationset
Action is an animation template as a container. The animation template contains the same time value in the set.

Animation implementation
To implement animation in our skin mesh, we need to add a new class. We name this class canimationnode. This class will contain the animation key frame and a pointer to the target frame. This class also contains a settime function that uses a matrix obtained from the animation key frame on the new time value to update the transformation matrix of the target framework. Each canimationnode instance contains the data of a single instance of the animation template. The following illustration shows the new design direction of our code:

  

Considering the need to work with the animation, the read code will be slightly modified. Download is the corresponding modification made to the previous read code as required:
Cskinmesh: Create ()
Begin
Initialize X file API
Register d3drm templates
Open the X file
For every top level template in the X file
Begin
Retrieve the X file data object
Pass the data object to rootframe. Load
End
Link the bones to the skin mesh (es)
Link the bones to the animations
End

Cframenode: load ()
Begin
Check the type of the Data Object
If the type is mesh
Begin
Create new cmeshnode object
Attach the new object to the frame
Pass the data object to cmeshnode: Create of the new mesh
End
Else if type is frametransformationmatrix
Load the transformation matrix
Else if type is frame
Else if type is Animation
Instruct cskinmesh to load the new animation
Begin
Create new cframenode object
Attach the new object to this frame
Set the name of the child frame to the name of the template
For every child template of the current
Begin
Retrieve the X file data object
Pass it to newframe. Load
End
End
End

Cskinmesh: loadanimation ()
Begin
Create new canimationnode object
Attach the new object to the Link List
For every child Template
Call canimationnode: load for the new animation object
End

Canimationnode: load ()
Begin
Check the type of the Data Object
If the type is a reference
Begin
Get the referenced template, which is a frame Template
Get the name of it
Store the name
End
Else if type is Data
Begin
Check the type of the animation key
Load the key accordingly
End
End

The settime function executes all animation functions there. Cskinmesh: settime calls the settime function of all animation objects.
Canimationnode: settime ()
Begin
If a matrix key is available
Begin
Get the nearest matrix to the given time
Set it to the target Frame
End
Else
Begin
Prepare an identity matrix called transmat
If a scale key is available
Begin
Calculate the accurate scale value
Prepare a scale matrix for this scale value
Append the Matrix to transmat
End
If a rotation key is available
Begin
Calculate the accurate rotation Quaternion
Prepare a rotation matrix from this value
Append the Matrix to transmat
End
If a position key is available
Begin
Calculate the accurate position value
Prepare a matrix for it
Append the Matrix to transmat
End
Set transmat to the target Frame
End
End

Now you know everything about skin mesh. It's time for you to try it (source code download ). Note that the source code is simplified for sake of clarity. The Code assumes that you have a 3D accelerator and it assumes that your system supports the necessary hybrid weights. The Code uses a non-indexed vertex buffer. For a more complex example, you can refer to the dx8 SDK example, which performs a lot of checks and achieves a mixture of indexes and non-index vertices.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.