OpenGL - 用鼠标移动相机

时间:2009-09-15 10:47:25

标签: opengl 3d

我不确定如何解释这个,但希望你能理解我的意思。

基本上我画了一个立方体,想要拖动鼠标来查看所有边。 只能水平或垂直旋转很好,但如果我尝试将它们组合起来,那么事情就会变得有些奇怪。

e.g。如果我垂直旋转180度(以“倒置”)然后水平拖动鼠标,那么立方体将以与鼠标运动相反的方向旋转。

这是相关代码:

double camera_angle_h = 0;
double camera_angle_v = 0;

int drag_x_origin;
int drag_y_origin;
int dragging = 0;

void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 25.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glRotated(camera_angle_v, 1.0, 0.0, 0.0);
    glRotated(camera_angle_h, 0.0, 1.0, 0.0);

    draw_cube();

    glFlush();
    glutSwapBuffers();
}

void mouse_click(int button, int state, int x, int y) {
    if(button == GLUT_LEFT_BUTTON) {
        if(state == GLUT_DOWN) {
            dragging = 1;
            drag_x_origin = x;
            drag_y_origin = y;
        }
        else
            dragging = 0;
    }
}

void mouse_move(int x, int y) {
    if(dragging) {
        camera_angle_v += (y - drag_y_origin)*0.3;
        camera_angle_h += (x - drag_x_origin)*0.3;
        drag_x_origin = x;
        drag_y_origin = y;
    }
}

5 个答案:

答案 0 :(得分:4)

您正在使用欧拉角,因此存在万向节锁的问题。

一个简单的解决方案是将旋转存储在模型矩阵内并旋转此矩阵,而不是仅存储2个角度(通过使用矩阵乘法)。

查看此答案以获取更多信息: Will this cause gimbal-lock?

更复杂的解决方案是存储四元数

答案 1 :(得分:4)

正如其他人所说,使用四元数是解决方案。 Ken Shoemake提供了在图形宝石IV中转换四元数和欧拉角的优秀代码(参见code samples here,参见“欧拉角转换”)。它还具有与旋转矩阵的转换。

如果你想使用鼠标进行旋转,可以说“黄金标准”是Shoemake在图形宝石IV中描述的“Arcball”界面(目前可用的here)。改进版的Arcball与Glut库一起作为“轨迹球”分发,当点击发生在旋转球体外时,它提供了更直观的界面。它由Gavin Bell撰写,可用herehere。 Bell的轨迹球是Blender project使用的方法,我认为商业软件包使用类似的东西。

答案 2 :(得分:2)

听起来好像您的应用程序遇到了gimbal lock。有几种方法可以解决这个问题,最简单的方法就是限制允许的旋转。

答案 3 :(得分:2)

大多数应用程序仅允许最多90度的上/下旋转;否则,视图是颠倒的,是从左到右反转。对于大多数应用来说,旋转到目前为止你没有意义,因为你正在颠倒世界。

此外,这不像其他两位回答者说的那样是万向节锁;万向节锁需要三个(或更多?)旋转轴。简而言之,万向节锁定是指一个轴向任一方向旋转90度,使另外两个轴对齐;然后围绕其他两个轴中的任何一个旋转会产生相同的效果。维基百科页面中间的飞机图像很好地显示了它。

无论如何,最好的办法是将camera_angle_v限制在范围内(-90,90);换句话说,每当你加或减时,检查它是否大于90并将其设置为90,或者如果它小于-90,则将其设置为-90。

另外需要注意的是,过去当v角度正好是90或-90时,我确实遇到了问题,所以我会把它夹紧到+/- 89.9。

答案 4 :(得分:0)

由于您使用的是GLUT,因此您可能需要在系统上处理此问题的代码。查看trackball.c和trackball.h源文件。谷歌搜索他们也会找到来源。这是一个简单的库,可以帮助您解决这个问题。一些使用它们的GLUT例子是dinospin,bounce等。