How to move around camera using mouse in OpenGL?

Bazinga picture Bazinga · Dec 20, 2015 · Viewed 9.6k times · Source

I realize this question has been asked before on stackoverflow, but I have yet to find an answer that I understand completely so I thought I'd get some help specific to my situation.

I basically want to be able to use the mouse to rotate around the y-axis. Following is the function I'm using for the actual rotation (angles are in degrees).

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

Since I'm using GLUT, I use the passive function to get the x,y coordinates of the cursor. And then in my display I have the following:

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
    ...    
}

Now the problem is pretty obvious, since the display function runs 60 times a second, the mouse cursor just gets stuck in the middle whenever I try to move it. If I don't have the display function loop, the rotation is really laggy and stuff. So what is the proper way of doing this?

Note again, I'm only looking to have the camera move around in right/left direction using the mouse. Although it'd be awesome if I could get it working like a proper fps, it's not really essential.

Any help is greatly appreciated.

Answer

Mr_Pouet picture Mr_Pouet · Dec 20, 2015

You may want to use glutPassiveMotionFunc with a custom callback to handle the mouse position deltas:

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

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

     glutPassiveMotionFunc(handlerFunc);  // before glutMainLoop.

     /* [...] */

     return 0;
}

Documentation: glutPassiveMotionFunc

-

Moreover, I believe there's something wrong with your delta calculation. You should be calculating the difference between the current cursor position and the center of the window (where the cursor will be set after each frame).

mouseDisplacement = mouseX - centerWindowX;

Here's some code I use in my engine to get a FPS camera (feel free to adapt accordingly):

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