0

I am using GLFW to render some things in OpenGL. I created a Camera class that allows movement and looking around with the camera. These work fine when being done alone, but when they are used together, the following things happen:

When moving the camera forward, the rotation becomes slow and rotation resets the camera to the original position.

When moving the camera backwards, left, or right, the rotation causes everything to go out of the picture. The only things that I am rendering right now are two triangles directly in front of the camera, so I don't know what the camera ends up looking at. It will also occasionally reset the camera position like above, but only after moving forward first.

The code is relatively simple and the entire source is here, mainly in the Camera, Entity, and main source and header files, but I will also include the relevant bits below.

This is the function that I'm setting for GLFW's key callback and deals with movement:

void keyCallback(GLFWwindow * window, int key, int scancode, int action, int mods)
{
    switch(key)
    {
        case GLFW_KEY_W:
            cam->move(glm::vec3(0.0, 0.0, -0.05));
            break;
        case GLFW_KEY_S:
            cam->move(glm::vec3(0.0, 0.0, 0.05));
            break;
        case GLFW_KEY_A:
            cam->move(glm::vec3(-0.05, 0.0, 0.0));
            break;
        case GLFW_KEY_D:
            cam->move(glm::vec3(0.05, 0.0, 0.0));
            break;
        case GLFW_KEY_ESCAPE:
            glfwSetWindowShouldClose(window, GL_TRUE);
            break;
        default:
            break;
    }
}

This is the function dealing with mouse movement and looking around with the camera:

void cursorMoveCallback(GLFWwindow * window, double xpos, double ypos)
{
    printf("Mouse Moved to (%f, %f)\n", xpos, ypos);

    // Change camera angle
    glm::vec3 cameraMovement;

    // Change in x (rotation about y axis)
    if(xpos > 0)
        cameraMovement.x = -0.0005;
    else if (xpos < 0)
        cameraMovement.x = 0.0005;

    // Change in y (rotation about x axis)
    if(ypos > 0)
        cameraMovement.y = 0.0005;
    else if(ypos < 0)
        cameraMovement.y = -0.0005;

    // Reset Cursor position
    glfwSetCursorPos(window, 0, 0);


    // Change Position of Camera
    cameraMovement += Camera::getCurrentCamera()->getDirection();
    Camera::getCurrentCamera()->setDirection(cameraMovement);
}

Moving Camera:

glm::vec3 Camera::move(glm::vec3 translation)
{
    int dims = viewMatrix.length() - 1;
    // Apply translation
    for (int i = 0; i < dims; i++)
        viewMatrix[dims][i] -= translation[i];

    // Update viewMatrix
    Program::updateViewMatrix(viewMatrix);

    return Entity::move(translation);
}

glm::vec3 Entity::move(glm::vec3 translation)
{
    // Move by amount
    position += translation;

    // Return new position
    return position;
}

Looking with camera:

glm::vec3 Camera::setDirection(glm::vec3 newDirection)
{
    viewMatrix = glm::lookAt(newDirection, position, glm::vec3(0.0, 1.0, 0.0));

    Program::updateViewMatrix(viewMatrix);

    return Entity::setDirection(newDirection);
}

glm::vec3 Entity::setDirection(glm::vec3 newDirection)
{
    // Set direction of entity
    direction = newDirection;

    // Return new direction of entity
    return direction;
}

The Program::updateViewMatrix() call just goes through all active OpenGL programs and sets uniforms for the view matrix. Please let me know if there could be any other relevant code that would make a difference.

My guess would be that I'm running into some sort of threading issue due to the callbacks or there's an issue with trying to both move and look around at the same time.

UPDATE 1: I have fixed the order of arguments to glm::lookAt(). This fixes the disappearing issue, but after moving any, the rotation seems to be slower than it should.

Daniel Underwood
  • 2,191
  • 2
  • 22
  • 48
  • glm::lookAt does not take a direction as first parameter. Check out this [question](http://stackoverflow.com/questions/21830340/understanding-glmlookat). – BDL Nov 17 '14 at 09:04
  • @BDL That seemed to fix most of the issues. I had the order wrong everywhere in my code, so it was working until I tried changing both at one time. The triangles are no longer disappearing, but looking around seems to be slow after moving. Any ideas on what may be causing that? – Daniel Underwood Nov 17 '14 at 15:22
  • Changing the order alone is not enough. lookat requires you to supply two position in space, the position of the camera and the POSITION you want to look at. For me your code looks like as if your supplying a direction in which you want to look. – BDL Nov 17 '14 at 15:30
  • Btw.: you know, that rotation a vector is not the same as adding values to one of it's components? Because you write "(rotation about y axis)" and then subtract/add 0.0005 from the x-component. – BDL Nov 17 '14 at 15:33
  • @BDL That was it! I thought the center for `lookAt()` was a direction in look rather than a position to look at. Changing the `Camera::direction` when I move fixes this. You may want to put that as an answer since it is what fixed it. Thanks! – Daniel Underwood Nov 17 '14 at 16:03
  • Also, I realize that rotation doesn't work like that. Since I was using `lookAt()`, changing the direction that it was looking would work like that, I thought. Since `lookAt()` actually using a position for where the camera is looking, I believe this should work. And moving the x coordinate position that the camera is looking at would effectively rotate around the y axis. – Daniel Underwood Nov 17 '14 at 16:15

2 Answers2

1

The problem is that glm::lookAt(eye, center, up) expects other parameters than you supply:

  • eye is the position of the camera in space
  • center is the point where the camera looks at. Important: This is a position, not a direction
  • up is the up vector, which is a direction.

For more details one might find this post very useful.

Community
  • 1
  • 1
BDL
  • 21,052
  • 22
  • 49
  • 55
0

You should set uniform values right before you need them, i.e. in the drawing code, before making the glDraw… calls. If you set them somewhere in the event handlers, anything happening between the event handler and drawing may overwrite the values you put there. This is what happens to you: Your both camera class instances write to the same location and only one of them can win.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • That's certainly something that needed to be done. I was looking for a way to make those calls a bit less frequently, but for some reason didn't think of putting it in the render loop; unfortunately, it didn't seem to fix the issue. – Daniel Underwood Nov 17 '14 at 15:19