Rotating a multipart object

谁都会走 提交于 2019-12-09 04:03:29
Rabbid76

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 )


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 )

  1. you are missing glMatrixMode calls

    If you are using only GL_MODELVIEW than it works (if lastly set active) but when your code grows longer and you add other calls you might broke this and suddenly your code will not work as expected (and very hard to debug). Therefore it is better to add glMatrixMode(GL_MODELVIEW); before any transformation chunk of code.

  2. You are push/pop ing wrongly

    Your objects are nested so the matrices must be nested too. That means any part attached to owner part must start with the owners part matrix. So you need to have some hierarchy of the parts (assembly order) so you know what parts are attached to which ones and where.

    so You should have a list of parts connected to any part ... Something like:

    List<int> part[noOfObj];
    

    so any part[i], i=<0,noOfObj-1> has children parts part[i][0,1,2...,part[i].num-1] connected to it (where num is size of the list). And part[0] is the main part. That changes things a bit but simple recursion helps:

    void part_draw(int ix) // this is just recursion call used by the main function do not use it directly
     {
     glMatrixMode(GL_MODELVIEW);
     glPushMatrix();
     glTranslatef(subPosX[ix], subPosY[ix], subPosZ[ix]);
    
     glPushMatrix();            // this should not be here 
     glScalef(9.0, 1.75, 1.75); // this should not be here
     ..... // draw the object ix here
     glMatrixMode(GL_MODELVIEW);// this should not be here
     glPopMatrix();             // this should not be here
    
     for (int iy=0;iy<part[ix].num,iy++)
      part_draw(part[ix][iy]);
    
     glMatrixMode(GL_MODELVIEW);
     glPopMatrix();
     }
    
    void mesh_draw() // this is the main rendering routine which you should use
     {
     glMatrixMode(GL_MODELVIEW);
     glPushMatrix();
     glTranslatef(refPosX, refPosX, refPosZ);
     glRotatef(angle, 0, 1, 0); 
    
     part_draw(0);
    
     glMatrixMode(GL_MODELVIEW);
     glPopMatrix();
     }
    

    Now beware that subPosX/Y/Z positions must be in parent part coordinate system. Also This will not work for cyclicly nested objects (loops) as that would lead to infinite loop causing stack overflow.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!