如何在OpenGL中使用鼠标移动相机?

Baz*_*nga 5 c++ opengl camera glut freeglut

我意识到这个问题之前已经在 stackoverflow 上被问过,但我还没有找到我完全理解的答案,所以我想我会得到一些针对我的情况的帮助。

我基本上希望能够使用鼠标绕 y 轴旋转。以下是我用于实际旋转的函数(角度以度为单位)。

void CCamera::RotateY (GLfloat Angle)
{
    RotatedY += Angle;

    //Rotate viewdir around the up vector:
    ViewDir = Normalize3dVector(ViewDir*cos(Angle*PIdiv180)
                    - RightVector*sin(Angle*PIdiv180));

    //now compute the new RightVector (by cross product)
    RightVector = CrossProduct(&ViewDir, &UpVector);
}
Run Code Online (Sandbox Code Playgroud)

由于我使用的是 GLUT,因此我使用被动函数来获取光标的 x,y 坐标。然后在我的显示器上有以下内容:

void display(void) {
    ...
    mouseDisplacement = mouseX - oldMouseX;

    if (mouseDisplacement > 0) Camera.RotateY(-1.0*abs(mouseDisplacement));
    else if (mouseDisplacement < 0) Camera.RotateY(1.0*abs(mouseDisplacement));

    oldMouseX = mouseX;
    glutWarpPointer(centerWindowX, centerWindowY);  // move the cursor to center of window
    ...    
}
Run Code Online (Sandbox Code Playgroud)

现在问题非常明显,由于显示函数每秒运行 60 次,每当我尝试移动鼠标光标时,它就会卡在中间。如果我没有显示功能循环,旋转就会非常缓慢。那么这样做的正确方法是什么?

再次注意,我只想使用鼠标让相机沿右/左方向移动。虽然如果我能让它像适当的 fps 一样工作那就太棒了,但这并不是真正必要的。

任何帮助是极大的赞赏。

Mr_*_*uet 1

您可能希望使用glutPassiveMotionFunc自定义回调来处理鼠标位置增量:

void handlerFunc(int x, int y) 
{ 
    /* code to handle mouse position deltas */ 
}

int main()
{
     /* [...] */

     glutPassiveMotionFunc(handlerFunc);  // before glutMainLoop.

     /* [...] */

     return 0;
}
Run Code Online (Sandbox Code Playgroud)

文档:glutPassiveMotionFunc

-

此外,我相信你的增量计算有问题。您应该计算当前光标位置与窗口中心(光标将在每帧之后设置的位置)之间的差异。

mouseDisplacement = mouseX - centerWindowX;

以下是我在引擎中使用的一些代码来获取 FPS 相机(请随意进行相应调整):

void update(float delta)  // delta is usually 1.0/60.0
{
    // Mouse.
    MouseState mouse = InputDevices.get_mouse_state();

    // - Movement
    camera->yaw += camera->speed * mouse.dx * delta;
    camera->pitch -= camera->speed * mouse.dy * delta;

    // Regular FPS camera.
    // TODO(Clem): Move this to a class.

    // Clamp.
    if (camera->pitch > math::PI_OVER_TWO) {
        camera->pitch = math::PI_OVER_TWO - 0.0001f;
    }
    else if (camera->pitch < -math::PI_OVER_TWO) {
        camera->pitch = -math::PI_OVER_TWO + 0.0001f;
    }

    float pitch = camera->pitch;
    float yaw = camera->yaw;

    // Spherical coordinates (r=1).
    camera->forward.x = -sin(yaw) * cos(pitch);
    camera->forward.y = -sin(pitch);
    camera->forward.z = -cos(yaw) * cos(pitch);

    camera->right.x = -cos(yaw);
    camera->right.y = 0.0;
    camera->right.z = sin(yaw);

    camera->up = cross(camera->forward, camera->right);

    camera->forward = normalize(camera->forward);
    camera->right = normalize(camera->right);
    camera->up = normalize(camera->up);
}
Run Code Online (Sandbox Code Playgroud)