【问题标题】:How to rotate an object according to it's orientation如何根据对象的方向旋转对象
【发布时间】:2013-11-15 23:43:09
【问题描述】:

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

我需要以一种用户应该能够用鼠标移动它的方式旋转一个对象,就像他正在拖动它一样。问题是glRotatef 只是旋转对象而不考虑它的方向。对于 WebGL,解决方案是使用四元数,但我猜 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 轴旋转时,它会沿相反方向旋转。我需要一个想法,我该怎么做?

编辑

我尝试使用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();

这是不可旋转的茶壶:

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

【问题讨论】:

  • 你试过rotation[1]= -dx/5; 吗?
  • 你不能只存储两个浮点数。您需要使用四元数或旋转矩阵。您可以定义一个rotation[4][4],将其初始化为单位矩阵,并在mouse 函数中预乘适当的旋转矩阵。然后在你的 draw 方法中调用 glMultMatrixf(rotation) 而不是 glRotate 的东西。
  • @sbabbi 我试过这种方式,但不是旋转,而是对象被缩放和变形。你能看看我的编辑吗?

标签: c++ opengl rotation glut


【解决方案1】:

首先是一点代数。 让 v 是一个向量,M 是您当前的模型视图矩阵,而 R 是与glRotate 命令关联的矩阵。那么,如果你使用glRotate,你得到的是:

M * R * v

这意味着您正在围绕对象轴旋转。你想绕 world 轴旋转,即:

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

【讨论】:

  • 如果我在顶点着色器中进行旋转会怎样?我将如何进行轮换?
  • @RamyAlZuhouri 这个问题的答案很长,并且取决于 GLSL 版本(如果您使用默认的 gl_ModelviewMatrix 统一或自定义统一)。在一天结束时,您将完整的模型视图矩阵传递给着色器,因此您必须在 C++ 端手动计算它。我建议您寻找有关 GL 着色器和矩阵转换的教程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-16
  • 2013-01-04
  • 1970-01-01
  • 2013-04-02
  • 1970-01-01
  • 2021-07-18
  • 2017-01-11
相关资源
最近更新 更多