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轴旋转茶壶,而不是旋转,这就是我得到的:
答案 0 :(得分: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);