【问题标题】:OpenGL - moving camera with mouseOpenGL - 用鼠标移动相机
【发布时间】:2011-01-13 13:09:55
【问题描述】:

我不确定该如何解释,但希望你能明白我的意思。

基本上我已经画了一个立方体,并且想拖动鼠标来查看所有的边。 仅水平或垂直旋转都可以,但如果我尝试将它们结合起来,事情就会变得有点奇怪。

例如如果我垂直旋转 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;
    }
}

【问题讨论】:

    标签: opengl 3d


    【解决方案1】:

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

    如果您想使用鼠标进行旋转,可以说“黄金标准”是 Shoemake 在 Graphics Gems IV 中描述的“Arcball”界面(目前可用 here)。 Arcball 的改进版本与 Glut 库一起作为“轨迹球”分发,当点击发生在旋转球体之外时,它提供更直观的界面。它由 Gavin Bell 编写,可通过herehere 获取。贝尔的轨迹球是Blender project 使用的方法,我认为商业包使用类似的东西。

    【讨论】:

      【解决方案2】:

      您使用的是欧拉角,因此存在云台锁定问题。

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

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

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

      【讨论】:

        【解决方案3】:

        大多数应用程序只允许向上/向下旋转最多 90 度;否则,视图是颠倒的,是的,从左到右是颠倒的。对于大多数应用程序,旋转这么远以至于您将世界颠倒过来是没有意义的。

        另外,这不是其他两位回答者所说的云台锁;万向节锁需要三个(或更多?)旋转轴。简单来说,云台锁就是当一个轴向任一方向旋转90度,使另外两个轴对齐;然后围绕其他两个轴中的任何一个旋转会产生相同的效果。维基百科页面中间的飞机图像显示得很好。

        无论如何,最好的选择是将camera_angle_v 限制在范围(-90,90);换句话说,无论何时添加或减去它,然后检查它是否大于 90 并将其设置为 90,或者如果它小于 -90 则将其设置为 -90。

        还需要注意的是,过去我实际上在 v 角正好为 90 或 -90 时遇到了问题,所以我会将其钳制为 +/- 89.9。

        【讨论】:

          【解决方案4】:

          听起来好像您的应用程序正在遭受gimbal lock 的影响。有几种方法可以解决它,最简单的方法是限制允许的旋转。

          【讨论】:

            【解决方案5】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-09-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多