首页 文章

如何根据对象的方向旋转对象

提问于
浏览
4

类似的问题WebGL:Rotate object around world axis .

我需要以用户应该能够用鼠标移动它的方式旋转对象,就像他拖动它一样 . 问题是 glRotatef 只是旋转对象而不考虑它在OpenGL中的四元数 .

这就是我现在实现轮换的方式:

// rotation 2D GLfloat C-vector, posX, posY GLfloat's
void mouse(int button, int state, int x, int y) {
    if(button== GLUT_LEFT_BUTTON) {
        if(state== GLUT_DOWN) 
        {
            posX=x;
            posY= y;
            onEvent= true;
        }
        else if(state== GLUT_UP) 
        {
            GLfloat dx= x-posX;
            GLfloat dy= y-posY;
            rotation[0]= -dy/5;
            rotation[1]= dx/5;
            onEvent= false;
            glutPostRedisplay();
        }
    }
}

然后我在显示功能中处理旋转:

glPushMatrix();
glRotatef(rotation[0],1,0,0);
glRotatef(rotation[1],0,1,0);
// Draw the object
glPopMatrix();

它有点工作,但就像我说它应该是如果用户能够拖动对象旋转它 . 相反,例如,如果对象围绕X轴旋转90度,当用户水平拖动鼠标以使其围绕Y轴旋转时,它以相反的方向旋转 . 我需要一个想法,我怎么能这样做?

Edit

我试图使用 glMultMatrixf ,但该对象在鼠标功能中没有编辑:

// Global variables:
// GLfloat xRotationMatrix[4][4];
// GLfloat yRotationMatrix[4][4];
else if(state== GLUT_UP && onEvent)
{
    GLfloat dx= (x-posX)/(180.0*5)*2.0*M_PI;
    GLfloat dy= (y-posY)/(180.0*5)*2.0*M_PI;
    // Computing rotations
    double cosX= cos(dx);
    double sinX= sin(dy);
    double cosY= cos(dy);
    double sinY= sin(dy);
    // x axis rotation
    xRotationMatrix[1][1]+= cosY;
    xRotationMatrix[1][2]+=-sinY;
    xRotationMatrix[2][2]+= sinY;
    xRotationMatrix[2][2]+= cosY;
    // y axis rotation
    yRotationMatrix[0][0]+= cosX;
    yRotationMatrix[0][2]+= sinX;
    yRotationMatrix[2][0]+= -sinX;
    yRotationMatrix[2][2]+= cosX;

    onEvent= false;
    glutPostRedisplay();
}

然后在显示功能:

glPushMatrix();
glMultMatrixf((const GLfloat*)xRotationMatrix);
glMultMatrixf((const GLfloat*)yRotationMatrix);
glutSolidTeapot(10);
glPopMatrix();

这是非旋转的茶壶:

enter image description here

如果我水平拖动鼠标以围绕y轴旋转茶壶,而不是旋转,这就是我得到的:

enter image description here

1 回答

  • 1

    首先是一些代数 . 设 v 为向量, M 为当前模型视图矩阵, R 为与 glRotate 命令关联的矩阵 . 然后,如果你使用 glRotate ,你得到的是:

    M * R * v

    这意味着您正在围绕对象轴旋转 . 您想围绕世界轴旋转,即:

    R * M * v

    看到不同?不幸的是,GL没有 MatrixPreMult 功能 .

    在现代OpenGL中,我们不再使用矩阵堆栈,事实上在使用着色器时,我们手动将转换矩阵传递给GL程序 . 人们(大多数)做的是写/使用外部向量代数库(如Eigen) .

    一个可能的(未经测试的)解决方法只使用旧的已弃用的GL内容,可能是这样的:

    void rotate(float dx, float dy)
    {
         //assuming that GL_MATRIX_MODE is GL_MODELVIEW
         float oldMatrix[4][4];
         glGetFloatv(GL_MODELVIEW_MATRIX,oldMatrix);
         glLoadIdentity();
         glRotatef(-dy,1,0,0);
         glRotatef(dx,0,1,0);
         glMultMatrixf(oldMatrix);
    }
    

    并且您将此代码放在 mouse 函数中,而不是绘制例程中 . 您可以通过将视图矩阵保持在GL矩阵堆栈中,然后在每次必须绘制对象时按下/弹出来使用此技巧 . 我不会在大型项目中推荐类似的东西 .


    另请注意,如果在上面的代码中反转两个 glRotate 调用的顺序,则可能会得到稍微不同的结果,特别是如果dx和dy不小的话 . 这段代码可能稍好一点:

    float angle = sqrt(dx*dx+dy*dy)*scalingFactor;
    glRotate(angle,-dy,dx,0);
    

相关问题