Tutorial: How to Create a controllable human skeleton model

Source: Internet
Author: User

After a period of research, we realized how to put the skeleton on the current tracking system, and transplanted the skeleton model to the system to replace the original stick model, I also saw some people trying to do this on the Internet (it seems that they are all d3d skeleton animations, not based on OpenGL). I will briefly introduce my production method, I hope it will help people who are doing this.

How to Create a controllable human skeleton model

Description: This article provides a method to map the skeleton motion vector to the human skeleton model. by inputting the current direction of each skeleton and feeding it back to the skeleton model, the animation effect is achieved.
The experimental development tool is developed on the OpenGL platform by vc6.0.

Intended audience:

If you are familiar with OpenGL programming, you only need to understand the basic rotation, translation, and stack operations.
Assume that you already know the basic C ++ programming, and you need to understand recursive algorithms. For the recursive method, see data structure.
 

Production process:

Step 1: Prepare a 3D model

The purpose of this step is to provide a decomposed skeleton model. It needs to export multiple files that make up the body structure. You don't need to make the model yourself. You just need to look for it online. There should be a lot of data, it is best to use a human body model. If you use an animal model, you can define the ing skeleton by yourself. Compared to the skeleton model, I found it from the human body animation software poser 5.0. Then, use 3D Max to export all parts of the body to a 3DS file. This step is simple and does not require any 3D MAX basics. Here is a small trick: You can select multiple parts to export as a 3DS model. For example, you need to export the left and right shoulder blades and spine ribs as the same part, in this way, you can name it the body ). In this way, we have prepared various 3DS files, which are:

Body and trunk body.3ds
Head.3ds
Left arm lshoulder.3ds
Right arm rshoulder.3ds
Left arm lelbow.3ds
Right arm relbow.3ds
Left thigh lthigh.3ds
Right thigh rthigh.3ds
Left calf lfeet.3ds
Right calf rfeet.3ds

In this way, these components can be flexibly spliced into a human body.

Step 2: define the relevant core data structure

To obtain the data of various body parts of a motion, we need to store some motion information, mainly including:
Skeleton ID
Current position of the skeleton joint; r_x, r_y, r_z
Relationship between bones, for example, the arm is an extension of the trunk, and the left arm is an extension of the left arm; PID, CID

We can understand the structural relationship between bones.


Directory where the 3DS file is stored; file_name_3ds
The initialization direction of the 3DS model. This is an abstract concept. It refers to the direction from the parent node to the child node. For example, the initial position of the left arm is flat down, then the corresponding vector is (-0.2)

The data structure section is as follows:
Class bone
{
Public:
Int y;
Int X;
Int r_z; // The zcoordinate of the real world
Int r_y;
Int r_x;
Int rotated_x; // coordinates after rotation
Int rotated_y;
Int is_marked; // whether it has been marked
Int PID; // parent node
Int CID; // subnode, which is currently valid for axial joints and knees
Float start_arc_x, end_arc_x; // The rotation angle between the left and right directions of the parent node x
Float start_arc_y, end_arc_y; // the upper and lower rotation angle of Y relative to the parent node
Float start_arc_z, end_arc_z; // The rotation angle between the frontend and backend of the Z node and the parent node
Double lengthratio;
Char name [80]; // name
Char file_name_3ds [180]; // 3DS file name
Int ID;
Bone (int id, char * Name, int PID );
Virtual ~ Bone ();
Float bone_init_x, bone_init_y, bone_init_z; // initialize the vector direction of the skeleton, 3D MAX Model
};

Step 3: Initialize the Skeleton Structure
After defining the bone structure, we define a skeleton class to load these structures during the first initialization,

Obone = bone (2, "head", 1); // defines a bone
Strcpy (obone. file_name_3ds, "head.3ds"); // set its 3DS file name
Obone. bone_init_x = 0; // initialize the vector direction of the skeleton.
Obone. bone_init_y = 1;
Obone. bone_init_z = 0;
Bonevec. push_back (obone); // put it into the vector structure. The vector in STL programming technology is used here.

The following is some of the implementation code:
Skelecton: Skelecton ()
{
Float FY = 0.56f;
Float ftx = 0.19f;
Float FFX = 0.08f;
Bone obone = bone (1, "neck", 0 );
Bonevec. push_back (obone );

Obone = bone (2, "head", 1 );
Strcpy (obone. file_name_3ds, "head.3ds ");
Obone. bone_init_x = 0;
Obone. bone_init_y = 1;
Obone. bone_init_z = 0;
Bonevec. push_back (obone );

Obone = bone (3, "rshoulder", 1 );
Bonevec. push_back (obone );

Obone = bone (4, "lshoulder", 1 );
Bonevec. push_back (obone );

Obone = bone (5, "relbow", 3 );
Strcpy (obone. file_name_3ds, "rshoulder.3ds ");
Obone. bone_init_x = FY;
Obone. bone_init_y =-1;
Obone. bone_init_z = 0;
Obone. cid = 7;
Bonevec. push_back (obone );

Obone = bone (6, "lelbow", 4 );
Strcpy (obone. file_name_3ds, "lshoulder.3ds ");
Obone. bone_init_x =-fy;
Obone. bone_init_y =-1;
Obone. bone_init_z = 0;
Obone. cid = 8;
Bonevec. push_back (obone );

//............. Too long, only part of the code is provided ..........................

}

Step 4: Learn the public class cload3ds of 3DS and load the display model.

This class is a public class. For details about the interface information of the class cload3ds, refer to an open source project. Http://scourge.sourceforge.net
Http://scourge.sourceforge.net/api/3ds_8h-source.html
In fact, when using this class, I made some modifications and added the method for getting the maximum vertex. This will be explained in step 5.

We define an OpenGL class for model control and load the model,

Cload3ds * m_3ds;

Int OpenGL: load3ds (int id, char * filename)
{
If (m_3ds! = NULL) m_3ds-> Init (filename, ID );
Return 0;
}

Then call

Int OpenGL: show3ds (int id)
{
M_3ds-> show3ds (ID );
Return 0;
}

Step 5: load the model hierarchically using recursive Methods

Here is the key content. Let's think about some issues. What needs to be done to realize that the skeleton will change the direction with the input direction?
First, consider a piece of bone:
First, we need to let the skeleton rotate around its node to the input direction.

Second, we need to know the current node position of the skeleton to rotate. However, we know that the skeleton will rotate with its parent skeleton. For example, the left arm will rotate with the left arm. When the body turns, the left arm will also rotate with the body, it seems that there is a parent-child linkage relationship, so the current node location will be related to its parent skeleton, and the Child skeleton must also rotate from the parent skeleton rotation angle, so here we naturally think of recursive models. As for how to store these rotating processes, we can see that OpenGL provides glpushmatrix (); glpopmatrix (); then all child bones must be included in the glpushmatrix (); glpopmatrix () of the parent bone.

// Implement 3D reality recursively
Int Skelecton: render_skeleton_3d (int id)
{
 
Glpushmatrix (); // starts recording the stack
Joint_point = PGL-> get_joint_point (ID); // locate the node location
Gltranslatef (joint_point.x, joint_point.y, joint_point.z); // coordinates are moved to the node location.
PGL-> rotate_bone (vt1, VT2, VTO); // rotate the skeleton to the specified direction
Gltranslatef (-joint_point.x,-joint_point.y,-joint_point.z); // return coordinates
PGL-> show3ds (ID); // display the Model

// Traverse subnodes
For (theiterator = bonevec. Begin (); theiterator! = Bonevec. End ();
Theiterator ++)
{
Pbone = theiterator;
If (pbone-> pid = ID ))
{
Render_skeleton_3d (pbone-> ID); // recursive call
}
}

Glpopmatrix (); // exit the record Stack

}

The remaining problem to be solved is how to locate the node location.
Find the node location,
We can see that the above Code get_joint_point (ID) is to find the node. In fact, if we do not pursue high accuracy, we can assume that the highest point of each model is the skeleton node, of course, the premise of this assumption is that the human body model is standing on the front and the arm hangs down naturally. This way, we can think that the highest point of each model is the bone node, so that the function is very simple, this method modifies the cload3ds class method as follows:

Vector3f cload3ds: get_joint_point (INT J0)
{
Cvector3 lastpoint;
Vector3f vect;
Lastpoint. Y =-1000;
If (J0 = 2) lastpoint. Y = 1000; // the header node is down.

 
// Traverse all objects in the Model
For (int l = 0; L <g_3dmodel [J0]. numofobjects; l ++)
{If (g_3dmodel [J0]. pobject. Size () <= 0) break; // exit if the object size is smaller than 0.
T3dobject * pobject = & g_3dmodel [J0]. pobject [l]; // obtain the currently displayed object

For (Int J = 0; j <pobject-> numoffaces; j ++) // traverse all faces
{
For (INT Tex = 0; Tex <3; Tex ++) // traverses all vertices of a triangle
{
Int Index = pobject-> pfaces [J]. vertindex [Tex]; // obtain the index for each vertex

If (J0 = 2)
{
If (pobject-> pverts [Index]. Y <lastpoint. Y)
Lastpoint = pobject-> pverts [Index];
}
Else
{
If (pobject-> pverts [Index]. Y> lastpoint. Y)
Lastpoint = pobject-> pverts [Index];
}
}
}

}
Vect. x = lastpoint. X;
Vect. Y = lastpoint. Y;
Vect. z = lastpoint. Z;
Return vect;

}

It is special that the head node is connected by the neck, so it is the lowest point.

Now we have solved the final problem and how to rotate it. Specifically, the skeleton is rotated from the original natural state to the current direction. For example, the arm is lowered from natural to lift, the vectors in two states are dropped and lifted in different directions. How can we rotate them? Here we need to use the point area and cross product concept in space ry. In short, we use the Point product to calculate the cosine of the vector angle and the cross product to obtain the normal vectors of the two vectors, if you forget these concepts, you can go back to the advanced mathematics book, this connection also provides some information, can help understand http://www.gameres.com/Articles/Program/Visual/Other/shiliang.htm
Then, we know the angle between the two vectors and their normal vectors, and the following things become simple. We let the original vector of the skeleton take the normal vector as the rotation axis and rotate a certain angle, this angle is the angle between two vectors, so the problem is solved. The code here is as follows:

Int OpenGL: rotate_bone (vector3f vvector1, vector3f vvector2, vector3f vvectororgin)
{
Vector3f vt1 = vector3f (vvector1.x, vvector1.y, vvector1.z );
Vector3f VT2 = vector3f (vvector2.x, vvector2.y, vvector2.z );
Vector3f vt4 = vt2-vt1;

Double arc12 = anglebetweenvectors (vvectororgin, vt4 );
Double rarc12 = 180 * arc12/PI;
Float Len = distance (vt1, VT2 );
Vector3f vt3 = cross (vvectororgin, vt4 );
Glrotatef (float) rarc12, vt3.x, vt3.y, vt3.z );

Return 0;

}

Now that all the problems are solved, we can breathe a sigh of relief. Here I provide a reference code. Because the model requires vector direction input for running, I cannot completely extract it from other system programs, just to provide all the code, for your reference.

Download source code

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.