Search code examples
opengl3drotationcoordinate-transformation

Rotating a multipart object


I've created an object that has about 7+ parts to it including its body and smaller parts that 'attach' to it in different places. My goal is to rotate the entire object. I tried to simply call glRotatef(angle, 0, 1, 0) before constructing the entire object, but I realize that this seems to rotate 'everything' around the origin, no matter the translation. The following code was an attempt to rotate the body itself and rotate the attached parts to it.

// glRotatef(angle, 0, 1, 0); //old way of rotating the object

// body
glPushMatrix();
    // movement
    glTranslatef(subx, suby + y, subz);
    //rotating the body itself
    glRotatef(angle, 0, 1, 0); 
    // starting position of the body
    glScalef(9.0, 1.75, 1.75);
    glTranslatef(-subx, -suby, -subz);
    glTranslatef(subx, suby, subz);
    glutSolidSphere(1.0, 50, 50);
glPopMatrix();

// attached part
glPushMatrix();
    // movement
    glTranslatef(rot1x, rot1y + y, rot1z); 
    // attempting to rotate the part while 'attached to' the body
    glRotatef(angle, 0, 1, 0);
    //placing the part on the object in starting position
    glRotatef(rot1angle, rot1xrot, rot1yrot, rot1zrot);
    glTranslatef(-rot1x, -rot1y, -rot1z);
    glTranslatef(rot1x, rot1y, rot1z);
    gluPartialDisk(gluNewQuadric(), 0, 1, 50, 1, 0, 100.0);
glPopMatrix();

I can't seem to wrap my head around what needs to happen in order for the smaller parts of the object to rotate properly with the object's body (a fixed point?). Thanks for your help.


Solution

  • The operations on the matrix stack are based on one another. The reference system of each operation is the current transformation. If you want to transform a object which consists of a bunch of objects, then you have to know the relative position of each sub object to a reference position of the object union. Then you have to do the following steps:

    • Move each object to a common position in the world (glTranslate).
    • Orientate the objects (glRotate)
    • Move each object to its relative position in the object union

    // dynamic position in the world
    float refPosX, refPosY, refPosZ;
    
    // dynamic orientation
    float angle;
    
    // constant positions of the sub object relative to the object union
    float subPosX[], subPosY[], subPosZ[];
    
    
    for ( int i = 0 i < noOfObj, ++i ) // for each object
    {
      glPushMatrix();
      glTranslatef(refPosX, refPosY, refPosZ);
      glRotatef(angle, 0, 1, 0); 
      glTranslatef(subPosX[i], subPosY[i], subPosZ[i]);
      glScalef(9.0, 1.75, 1.75);
    
      ..... // draw the object here
    
      glPopMatrix();
    }
    


    See the documentation of glTranslate:

    glTranslate produces a translation by x y z . The current matrix (see glMatrixMode) is multiplied by this translation matrix, with the product replacing the current matrix,

    and see the documentation of glRotate:

    glRotate produces a rotation of angle degrees around the vector x y z . The current matrix (see glMatrixMode) is multiplied by a rotation matrix with the product replacing the current matrix,


    Note, the translation matrix looks like this:

    Matrix4x4 translate;
    
    translate[0] : ( 1,  0,  0,  0 )
    translate[1] : ( 0,  1,  0,  0 )
    translate[2] : ( 0,  0,  1,  0 )
    translate[3] : ( tx, ty, tz, 1 )
    

    And the rotation matrix around Y-Axis looks like this:

    Matrix4x4  rotate;
    float      angle;
    
    rotate[0] : ( cos(angle),  0, sin(angle), 0 )
    rotate[1] : ( 0,           1, 0,          0 )
    rotate[2] : ( -sin(angle), 0, cos(angle), 0 )
    rotate[3] : ( 0,           0, 0,          1 ) 
    

    A matrix multiplication works like this:

    Matrix4x4 A, B, C;
    
    // C = A * B
    for ( int k = 0; k < 4; ++ k )
        for ( int l = 0; l < 4; ++ l )
            C[k][l] = A[0][l] * B[k][0] + A[1][l] * B[k][1] + A[2][l] * B[k][2] +  A[3][l] * B[k][3];
    


    The result of translate * rotate is this:

    model[0] : ( cos(angle),  0,  sin(angle), 0 )
    model[1] : ( 0,           1,  0,          0 )
    model[2] : ( -sin(angle), 0,  cos(angle), 0 )
    model[3] : ( tx,          ty, tz,         1 )
    

    translate * rotate


    Note, the result of rotate * translate would be:

    model[0] : ( cos(angle),                     0,   sin(angle),                     0 )
    model[1] : ( 0,                              1,   0,                              0 )
    model[2] : ( -sin(angle),                    0,   cos(angle),                     0 )
    model[3] : ( cos(angle)*tx - sin(angle)*tx,  ty,  sin(angle)*tz + cos(angle)*tz,  1 )
    

    rotate * translate