旋转多部分对象

Rotating a multipart object

我创建了一个对象,它有大约 7 个以上的部分,包括它的主体和 'attach' 在不同地方的较小部分。我的目标是旋转整个对象。我试图在构建整个对象之前简单地调用 glRotatef(angle, 0, 1, 0),但我意识到这似乎围绕原点旋转 'everything',无论平移如何。以下代码试图旋转主体本身并旋转附加的部件。

// 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();

我似乎无法理解需要发生什么才能使对象的较小部分随对象的主体(固定点?)正确旋转。感谢您的帮助。

矩阵栈上的操作是相互依存的。每个操作的参考系统是当前转换。如果你想转换一个由一堆对象组成的对象,那么你必须知道每个子对象相对于对象联合的参考位置的相对位置。然后您必须执行以下步骤:

  • 将每个对象移动到世界中的共同位置(glTranslate)。
  • 定位对象(glRotate
  • 将每个对象移动到其在对象联合中的相对位置

// 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();
}


请参阅 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,

并查看 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,


请注意,翻译矩阵如下所示:

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 )

绕 Y 轴的旋转矩阵如下所示:

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 ) 

矩阵乘法是这样的:

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];


translate * rotate 的结果是这样的:

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 )


请注意,rotate * translate 的结果将是:

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. 您缺少 glMatrixMode 个来电

    如果你只使用 GL_MODELVIEW 而不是它工作(如果最后设置为活动)但是当你的代码变长并且你添加其他调用时你可能会破坏它并且突然你的代码将无法按预期工作(并且很难调试)。因此最好在任何转换代码块之前添加 glMatrixMode(GL_MODELVIEW);

  2. push/pop错了

    您的对象是嵌套的,因此矩阵也必须嵌套。这意味着附加到所有者部分的任何部分都必须以所有者部分矩阵开头。所以你需要有一些部件的层次结构(装配顺序),这样你就知道哪些部件连接到哪些部件以及在哪里。

    所以你应该有一个连接到任何部分的部分列表......类似于:

    List<int> part[noOfObj];
    

    所以任何 part[i], i=<0,noOfObj-1> 都有子部分 part[i][0,1,2...,part[i].num-1] 连接到它(其中 num 是列表的大小)。 part[0] 是主要部分。这改变了一点,但简单的递归有帮助:

    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();
     }
    

    现在注意 subPosX/Y/Z 个位置必须在父部件坐标系 中。这也不适用于循环嵌套的对象(循环),因为这会导致无限循环,导致 stack overflow.