4
\$\begingroup\$

I want to create a free cam with the lookAt matrix in OpenGL. I just made the control with W, A, S and D so you can move around. But now I nee to look around. I thought doing that with sine and cosine on the target of lookAt, and it's partially working. But the problem is the input. I just don't know how to use the mouse coordinates(btw the mouse is fixed) to move the target or how to prepare the coordinates for sine and cosine.

Is there any example of what I'm looking for?

\$\endgroup\$
  • \$\begingroup\$ Why do you need to use lookAt? For a free camera I would just create the transformation matrix myself. \$\endgroup\$ – Gigo Aug 5 '13 at 13:36
  • \$\begingroup\$ What are you trying to do? Lookat is useful if you want the camera to be focused on some point, and just spin around it, but if you want more of an FPS camera I always found translate & rotate (pitch,yaw) to be easier. \$\endgroup\$ – Will Aug 5 '13 at 13:37
6
\$\begingroup\$

As my previous answer got a downvote because it was too code-heavy I'll explain a little more:

For a camera which is not locked to any target point you should not use lookAt but rather compute the camera transformation matrix yourself.

You will need a camera position (x,y,z) and at least two rotation angles (i.e. pitch and yaw). To get the full tranformation matrix you multiply a translation matrix and one rotation matrix for each angle together, but as matrix multiplication is not commutative the order is important here. You can either first rotate and then translate, or the other way around, which yields totally different results. To understand the behavior I suggest just messing around with the order, but for a typical first person camera you will want to translate first and then rotate.

To achieve the correct movement of the camera you need to do two things:

  • First you need to capture the mouse delta, i.e. the mouse movement since the last time you checked for mouse movement and add these up to your rotation angles. Additionally you may want to incorporate some kind of mouse speed multiplier here.
  • Second you need to apply movement to the camera position correctly. This gets a little tricky as soon as the angles are not zero anymore, because movement is not along any of the axis. You will need to calculate the correct movement direction using the current rotation angles and some trigonometry. Here you may want to add some movement speed multiplier.

I hope that cleared things up a bit, and gives more insight into what my code actually does.

Previous answer:

I would suggest not using lookAt and just creating the transformation matrix yourself. I did that a while ago in C# using DirectX, but I think it's self-explanatory what happens here:

public void ApplyFreeLookCamera(Context ctx)
{
    if (Enabled)
    {
        HandleInput(ctx);
    }
    Vector3 transPos = GetPosition();
    transPos.Multiply(-1);
    Matrix view = Matrix.Translation(transPos);
    view *= Matrix.RotationY(Yaw);      // left-right rotation
    view *= Matrix.RotationX(Pitch);    // up-down rotation
    view *= Matrix.RotationZ(Roll);     // ah snake, snaaake!
    ctx.Graphics.Transform.View = view;
}

And to handle input something like that:

private void HandleInput(Context ctx)
{
    // calculate movement direction
    var distance = MovementSpeed * ctx.FrameSeconds;
    var dx = (float)Math.Sin(Yaw) * distance;
    var dz = (float)Math.Cos(Yaw) * distance;
    //float dy = (float)Math.Sin(Pitch) * distance;
    var movement = new Vector3();
    // check keys
    if (ctx.Input.KeyPressed(Constants.CameraForward))
    {
        movement.X -= dx;
        movement.Z += dz;
    }
    if (ctx.Input.KeyPressed(Constants.CameraBackward))
    {
        movement.X += dx;
        movement.Z -= dz;
    }
    if (ctx.Input.KeyPressed(Constants.CameraLeft))
    {
        movement.X -= dz;
        movement.Z -= dx;
    }
    if (ctx.Input.KeyPressed(Constants.CameraRight))
    {
        movement.X += dz;
        movement.Z += dx;
    }
    if (ctx.Input.KeyPressed(Constants.CameraUp))
    {
        movement.Y += distance;
    }
    if (ctx.Input.KeyPressed(Constants.CameraDown))
    {
        movement.Y -= distance;
    }
    Position.Add(movement);
    // view direction
    var mouseDelta = ctx.Input.GetMouseDelta();
    if (ctx.Input.MouseButtonPressed(Constants.CameraMouseButton))
    {
        Yaw -= mouseDelta.X * MouseSpeed;
        Pitch -= mouseDelta.Y * MouseSpeed;
        ctx.Input.CenterMouseInWindow();
    }
}
\$\endgroup\$
  • \$\begingroup\$ Answering questions with mostly just code, don't make very good answers, especially if you're suggesting an alternative. Can you edit the answer to explain further why look-at shouldn't be used, and why it would be better to use your approach? Further explaining the rationale for the code would be useful to beginners. \$\endgroup\$ – MichaelHouse Aug 5 '13 at 14:13
  • \$\begingroup\$ Ok, know I did something like this: glm::translate(glm::mat4(), this->mMainCamera.position) * glm::rotate(glm::mat4(), this->mMainCamera.target.x, glm::vec3(1,0,0)) * glm::rotate(glm::mat4(), this->mMainCamera.target.y, glm::vec3(0,1,0)) * glm::rotate(glm::mat4(), this->mMainCamera.target.z, glm::vec3(0,0,1)) But the problem is, that whem I'm rotating the camera, it is rotation around the origin. But I did the exact same thing on my model transformations. ?! \$\endgroup\$ – Liess Jemai Aug 5 '13 at 15:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.