代码之家  ›  专栏  ›  技术社区  ›  rafvasq

旋转多部分对象

  •  1
  • rafvasq  · 技术社区  · 7 年前

    我创造了一个物体,它有大约7个以上的部分,包括它的身体和在不同地方“附着”到它的较小部分。我的目标是旋转整个对象。我试着打电话 glRotatef(angle, 0, 1, 0) 在构建整个对象之前,但我意识到这似乎是围绕原点旋转“一切”,无论平移如何。以下代码试图旋转身体本身并旋转附着在其上的零件。

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

    为了使物体的较小部分与物体的身体(一个固定点?)正确旋转,我似乎无法围绕需要发生的事情来思考。谢谢你的帮助。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Spektre    7 年前
    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 职位必须处于 父零件坐标系 . 此外,这将不适用于循环嵌套的对象(循环),因为这将导致无限循环 堆栈溢出 .

        2
  •  1
  •   rafvasq    7 年前

    矩阵堆栈上的操作是基于彼此的。每个操作的参考系是电流变换。如果要变换由一群对象组成的对象,则必须知道每个子对象相对于对象并集的参考位置的相对位置。然后,您必须执行以下步骤:

    • 将每个对象移动到世界上的公共位置( 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(glTranslate) 生成翻译 x y z . 电流矩阵(参见 glMatrixMode )乘以该平移矩阵,乘积替换当前矩阵,

    请参阅 glRotate :

    glRotate旋转 围绕矢量生成角度旋转 x y z . 电流矩阵(参见 glMatrixMode )乘以旋转矩阵,乘积替换当前矩阵,


    注意,转换矩阵如下所示:

    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 )
    

    translate * rotate


    注意,结果 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 )
    

    rotate * translate