Display motion frame by frame

Hi, I am trying to display motion by parsing a bvh(bio vision hierarchy) file using immediate mode openGL. I have loaded the hierarchy data into an array of type user-defined class as shown below:

class joint
{
public:
	 string name;
	 float offset[3];
	 int channel_num;
	 int channel_order_flag;
	 float channels[6];
	 int parent_index;
public:
	joint(void);
	~joint(void);

};

I have loaded motion data in to a 2D array such as it is one frame for each row. I have 436 frames in a example bvh file I am trying to display. I am trying to display the data frame by frame after a time delay of 33 miliseconds after every frame. This is the code I have written and my display function also is shown.

void skeleton::drawStick(int q)
{
	
		for(int i=1,p=6;i<26&&p<69;i++,p++)
		{
			
			glColor3f(1.0,0.0,0.0);
			glBegin(GL_LINE_STRIP);
			glRotatef(motion[q][5],0,0,1);
			glRotatef(motion[q][3],1,0,0);
			glRotatef(motion[q][4],0,1,0);
			glTranslatef(motion[q][0],motion[q][1],motion[q][2]);
			glVertex3f(bodyPart[0].offset[0], bodyPart[0].offset[1], bodyPart[0].offset[2]);
			
				if(bodyPart[i].parent_index!=i-1)
				{
					glEnd();
					glColor3f(1.0,0.0,0.0);
					glBegin(GL_LINE_STRIP);
					

					glRotatef(motion[q][p],0,0,1);
					glRotatef(motion[q][p+1],1,0,0);
					glRotatef(motion[q][p+2],0,1,0);
					
					glTranslatef(bodyPart[bodyPart[i].parent_index].offset[0],bodyPart[bodyPart[i].parent_index].offset[1],bodyPart[bodyPart[i].parent_index].offset[2]);
					
					glVertex3f(bodyPart[bodyPart[i].parent_index].offset[0],bodyPart[bodyPart[i].parent_index].offset[1],bodyPart[bodyPart[i].parent_index].offset[2]);

					
				}

				
				glRotatef(motion[q][p],0,0,1);
				glRotatef(motion[q][p+1],1,0,0);
				glRotatef(motion[q][p+2],0,1,0);
				
				glTranslatef(bodyPart[i].offset[0], bodyPart[i].offset[1], bodyPart[i].offset[2]);

				glVertex3f(bodyPart[i].offset[0], bodyPart[i].offset[1], bodyPart[i].offset[2]);

				
			
			glEnd();
		}
	}

note: q is a global variable.

my display function is:

void display()
{
	
	while(q<436)
	{
	
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			// Clear the color buffer bit

			THREED.drawGrid();
			THREED.drawCS();
	

    				
	
			glMatrixMode(GL_MODELVIEW);
												
			SKELETON.drawStick(q);
			
			glutSwapBuffers();

			q++;
			break;
		
	}
}

I am getting a messed up output of the drawing as if it has drawn all the motion data of each frame and displayed at once.

Since I am a rookie in openGL, guide me through the best way to display my motion data frame by frame correctly.

Any help will be greatly appreciated.

Thanks in advance.

You have modeling transformation commands like glRotate between glBegin and glEnd. This is not allowed (look at the docs). It probably compiled and ignored those glRotates and glTranslates. You’ll have to come up with a different approach.

Thanks a lot! But what approach can I use when I have 26 joints and I will have to specify different rotations on all three axes for all 26 joints in every frame and also I need to use glBegin and glEnd to draw a line between two vertices to make it a joint…? Is there any other better way to draw a joint when I have vertices’ values with me other than using glBegin() and glEnd()?

Any help would be greatly appreciated.

Thank you.

You can’t reasonably implement skeletal animation using OpenGL matrix operations; the standard matrices have to be constant for a set of primitives rendered with glBegin/glEnd or with glDrawElements etc. You could probably hack something together using feedback mode, but I wouldn’t recommend it.

Either transform the vertices in the client (application) code before passing them to OpenGL, or transform them in a vertex shader with the bone index passes as an extra attribute and the absolute bone transformations passed as a uniform array.

The latter option requires knowing how to use modern OpenGL (i.e. shaders) and an implementation which supports them.

Just add to what GClements gave you:

  1. If you want to render bones (e.g. lines or tubes) between each joint (in each frame of the animation), you can render this with the legacy OpenGL matrix stack.
  2. If your skeletal model only utilizes rigid body animation (one joint influence per triangle), then you render this with the legacy OpenGL matrix stack.
  3. If your skeletal model utilizes simple skinning (one joint influence per vertex, but potentially different influences for different vertices in the same triangle) or smooth skinning (1…N joint influences per vertex, and potentially different influences for different vertices in the same triangle), then your going to have to do something else. See GClements suggestions.

I mention this because it looks like you’re just wanting to do #1 right now. Just get the matrix operations (e.g. Rotate/Translate/Scale) used to move into joint space out of your Begin/End loops (which should just draw a stick or a tube).

[QUOTE=Vaidyanath;1281479] … what approach can I use when I have 26 joints and I will have to specify different rotations on all three axes for all 26 joints in every frame and also I need to use glBegin and glEnd to draw a line between two vertices to make it a joint…? Is there any other better way to draw a joint when I have vertices’ values with me other than using glBegin() and glEnd()?[/QUOTE] I just took a look at some bvh files. They seem to come in two parts: 1) define the topology of a stick figure, and 2) list the motion data. To model this using OpenGL in the most general case, you’d have to parse the input file to get the topology of the stick figure, and implement rotational degrees of freedom at the joints. Each ‘link’ could be represented with a line segment or tube. Joint motion would be animated using glRotatef commands (which you have attempted). For me, this would be fun, but not trivial.

However, your case might be much simpler. Is the shape and topology of your stick figure fixed? If so, you could ignore the first part of the file and hard-code up the stick figure. Then you would only have to input and animate the motion data (i.e. rotations at the joints).

Sort of.

The “obvious” approach of using vertices at the origin in both the parent’s coordinate system and the child’s coordinate system won’t work, as you can’t change the transformation while constructing a primitive.

You can render each bone as a line or tube with one end at the origin of the bone’s parent’s coordinate system and the other end manually offset by the bone’s translation relative to its parent. This lets you leave the rotation part of the bone’s transformation to the OpenGL transformation matrices.

Not sort of. You definitely can. I’ve done that before.

Thanks a lot! But what approach can I use when I have 26 joints and I will have to specify different rotations on all three axes for all 26 joints in every frame and also I need to use glBegin and glEnd to draw a line between two vertices to make it a joint…? Is there any other better way to draw a joint when I have vertices’ values with me other than using glBegin() and glEnd()?
You still use glBegin and glEnd. Modeling transformations are used, but not between glBegin and glEnd.

The code below shows how this could be done. The data in the offset array comes from a BVH file I grabbed off the web. This code doesn’t do the parsing, but it shows you how to structure the code to do animation. I’m only animating one leg. Animating all of the joints would require lots more Push, Pop, and glRotate commands. For complete generality, 3 glRotate commands would be needed at each joint. This animation shows the code in action. My joint angles are generated internally, not read from the BVH file.


//--+----4----+----3----+----2----+----1----+----||----+----1----+----2----+----3----+----4----+----
//-----------------------------------------   vec_sum   --------------------------------------------

void vec_sum (float a[3], float b[3], float c[3])
{
    c[0] = a[0] + b[0];
    c[1] = a[1] + b[1];
    c[2] = a[2] + b[2];
}

//--+----4----+----3----+----2----+----1----+----||----+----1----+----2----+----3----+----4----+----
//--------------------------------------   Line_Segment   ------------------------------------------

//  Draw line segment from point 'aaa' to point 'bbb', colored 'col'.

void Line_Segment (float col[3], float aaa[3], float bbb[3])
{
    glColor3fv  (col);

    glBegin (GL_LINES);
       glVertex3fv (aaa);
       glVertex3fv (bbb);
    glEnd ();
}

//--+----4----+----3----+----2----+----1----+----||----+----1----+----2----+----3----+----4----+----
//----------------------------------------   Stick_Man   -------------------------------------------

void Stick_Man (void)
{
    float aaa[3], bbb[3];
    static float offset[100][3] = {{0.00,   0.00, 0.00},    //  0 -> origin
                                  {20.00,   0.00, 0.00},    //  1 -> initial displacement ?
                                  { 3.43,   0.00, 0.00},    //  2 -> left hip
                                  { 0.00, -18.47, 0.00},    //  3 -> left knee
                                  { 0.00, -17.95, 0.00},    //  4 -> left ankle
                                  { 0.00,  -3.12, 0.00},    //  5 -> left foot
                                  {-3.43,   0.00, 0.00},    //  6 -> right hip
                                  { 0.00, -18.81, 0.00},    //  7 -> right knee
                                  { 0.00, -17.57, 0.00},    //  8 -> right ankle
                                  { 0.00,  -3.25, 0.00},    //  9 -> right foot
                                  { 0.00,   4.57, 0.00},    // 10 -> chest
                                  {-1.06,  15.33, 1.76},    // 11 -> right collar
                                  {-6.06,   0.00, 0.00},    // 12 -> right shoulder
                                  { 0.00, -11.90, 0.00},    // 13 -> right elbow
                                  { 0.00,  -9.52, 0.00},    // 14 -> right wrist
                                  { 0.00,  -7.14, 0.00},    // 15 -> right hand
                                  { 1.06,  15.33, 1.76},    // 16 -> left collar
                                  { 5.81,   0.00, 0.00},    // 17 -> left shoulder
                                  { 0.00, -12.08, 0.00},    // 18 -> left elbow
                                  { 0.00,  -9.82, 0.00},    // 19 -> left wrist
                                  { 0.00,  -7.37, 0.00},    // 20 -> left hand
                                  { 0.00,  17.62, 1.76},    // 21 -> neck
                                  { 0.00,   5.19, 0.00},    // 22 -> head
                                  { 0.00,   4.14, 0.00}};   // 23 -> head top


    vec_sum (offset[0], offset[1], aaa);
    vec_sum (aaa, offset[2], bbb);
    Line_Segment (orange, aaa, bbb);          // Left  hip joint
    vec_sum (bbb, offset[3], aaa);
    Line_Segment (yellow, bbb, aaa);          // Left knee joint
    vec_sum (aaa, offset[4], bbb);
    Line_Segment (orange, aaa, bbb);          // Left ankle joint
    vec_sum (bbb, offset[5], aaa);
    Line_Segment (yellow, bbb, aaa);          // Left foot joint

    vec_sum (offset[0], offset[1], aaa);
    vec_sum (aaa, offset[6], bbb);
    Line_Segment (orange, aaa, bbb);             // Right  hip joint
    vec_sum (bbb, offset[7], aaa);
    glPushMatrix ();
       glRotatef (rhip, 1,0,0);
       Line_Segment (yellow, bbb, aaa);          // Right knee joint
       vec_sum (aaa, offset[8], bbb);
       glPushMatrix ();
          glTranslatef ( aaa[0],  aaa[1],  aaa[2]);
          glRotatef (rkne, 1,0,0);
          glTranslatef (-aaa[0], -aaa[1], -aaa[2]);
          Line_Segment (orange, aaa, bbb);          // Right ankle joint
          vec_sum (bbb, offset[9], aaa);
          glTranslatef ( bbb[0],  bbb[1],  bbb[2]);
          glRotatef (rfot, 1,0,0);
          glTranslatef (-bbb[0], -bbb[1], -bbb[2]);
          Line_Segment (yellow, bbb, aaa);          // Right foot joint
       glPopMatrix ();
    glPopMatrix ();

    vec_sum (offset[0], offset[1], aaa);
    vec_sum (aaa, offset[10], bbb);
    Line_Segment (red, aaa, bbb);             // Chest

    vec_sum (bbb, offset[11], aaa);
    Line_Segment (yellow, bbb, aaa);          // Right collars
    vec_sum (aaa, offset[12], bbb);
    Line_Segment (orange, bbb, aaa);          // Right shoulder
    vec_sum (bbb, offset[13], aaa);
    Line_Segment (yellow, aaa, bbb);          // Right elbows
    vec_sum (aaa, offset[14], bbb);
    Line_Segment (orange, aaa, bbb);          // Right wrist
    vec_sum (bbb, offset[15], aaa);
    Line_Segment (white, aaa, bbb);           // Right hand

    vec_sum (offset[0], offset[1], aaa);
    vec_sum (aaa, offset[10], bbb);
    vec_sum (bbb, offset[16], aaa);
    Line_Segment (yellow, bbb, aaa);          // Left collar
    vec_sum (aaa, offset[17], bbb);
    Line_Segment (orange, bbb, aaa);          // Left shoulder
    vec_sum (bbb, offset[18], aaa);
    Line_Segment (yellow, aaa, bbb);          // Left elbows
    vec_sum (aaa, offset[19], bbb);
    Line_Segment (orange, aaa, bbb);          // Left wrist
    vec_sum (bbb, offset[20], aaa);
    Line_Segment (white, aaa, bbb);           // Left hand

    vec_sum (offset[1], offset[21], aaa);
    vec_sum (aaa, offset[22], bbb);
    Line_Segment (red, bbb, aaa);            // Neck
    vec_sum (bbb, offset[23], aaa);
    Line_Segment (white, bbb, aaa);          // Head
}