1
\$\begingroup\$

I have a camera position (Vec3) and camera horizontal/vertical angle. Now I want to translate my camera position toward the current camera orientation - what is the best way to do that? I am sure it's simple but the logic escapes me.

(I am using GLM math lib btw)

\$\endgroup\$
3
  • \$\begingroup\$ "I have a camera position (Vec3) and camera horizontal/vertical angle." Stop treating the camera as "angles". Treat it as an orientation, which points in a direction. \$\endgroup\$ Mar 16, 2013 at 1:09
  • \$\begingroup\$ @NicolBolas. In practice it doesn't really matter whether you store the view direction as angles or as vector. Either way there must be a point in your implementation where you convert between them. Be it in the function where you apply rotating or in the matrix calculation. Storing the view direction as two angles works well, see my answer. \$\endgroup\$
    – danijar
    Mar 16, 2013 at 11:57
  • \$\begingroup\$ @sharethis: I never said to store it as a vector; I said as an orientation. An orientation is more than just a direction. \$\endgroup\$ Mar 16, 2013 at 12:25

2 Answers 2

1
\$\begingroup\$

The best way to do that is to generate a vector in the direction your camera is pointing. The simplest way to do it would be to rotate it around the corresponding axes:

Vec3 GetCameraDir(float horiz, float vert) {

    // Start out pointing to the right
    Vec3 dir = Vec3 (1, 0, 0);

    // Rotate dir around the Y axis by your horizontal angle
    dir = RotateY(dir, horiz);

    // Rotate dir around the X axis by your vertical angle
    dir = RotateX(dir, vert);

    return dir;
}

Once you have this vector, you can translate your camera by some amount along this direction:

// Translate the camera's position by your time-step times the speed in the
// direction that your camera is pointing
Vec3 newCamPos = camPos + dT * speed * GetCameraDir(horiz, vert);

That being said, you may want to take a look at this question:

Camera rotation - First Person Camera using GLM

\$\endgroup\$
2
  • \$\begingroup\$ is RotateX/Y a GLM function? \$\endgroup\$ Mar 15, 2013 at 23:40
  • \$\begingroup\$ @KaiserJohaan: No, but neither is any of his other code. \$\endgroup\$ Mar 16, 2013 at 1:08
1
\$\begingroup\$

Given your description, your camera representation might look like this. I also included the headers of your maths library GLM needed for the following implementation.

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/constants.hpp>
using namespace glm;

struct Camera
{
    vec3 Position;
    vec2 Angles;
    mat4 View, Projection;
};

Camera cam;

To more your camera, you can first calculate the vector for the directions forward and sidewards (in this implementation to the right side). Then update the position based on that vector, the speed of movement, and the elapsed time Delta. Relying on the time is important to make the movement independent from the FPS of your game. Otherwise the camera rotation would be faster on faster machines and vise versa.

Calculating the forward vector is just basic trigonometry. If you have no basic understanding of sine and cosine you can look it up on Wikipedia or somewhere else. After computing the forward vector, we can derive the sidewards vector like shown in the code.

void Move(vec3 Amount, float Delta, float Speed = 10.f)
{
    vec3 forward = vec3(sinf(cam.Angles.x), 0, cosf(cam.Angles.x));
    vec3 right = vec3(-forward.z, 0, forward.x);

    cam.Position   += forward * Amount.x * Speed * Delta;
    cam.Position.y +=           Amount.y * Speed * Delta;
    cam.Position   += right   * Amount.z * Speed * Delta;
}

As you can see we only depend on the view direction for the X and Z coordinate. Otherwise the player could fly if the player walks facing the sky.

Because you haven't especially asked about rotation, I guess you already implemented that. But as a reference this might help other users. The negation because of the different direction of the world coordinates and the mouse coordinates.

void Rotate(ivec2 Amount, float Delta, float Speed = .08f)
{
    cam.Angles += vec2(-Amount.x, -Amount.y) * Speed * Delta;
}

The last step is to create the view matrix. Since you use GLM you can use its lookAt function to do so. Before, I wrap the horizontal angle if it exceeds 360 degrees and I limit the maximum vertical angle a bit. So the player wouldn't loose orientation if he looks straight to the top or to the bottom and rotate the camera then.

void Calculate()
{
    const float pi = glm::pi<float>();
    if      (cam.Angles.x < -pi) cam.Angles.x += pi*2;
    else if (cam.Angles.x >  pi) cam.Angles.x -= pi*2;

    const float margin = 0.2f;
    if      (cam.Angles.y < -pi/2+margin) cam.Angles.y = -pi/2+margin;
    else if (cam.Angles.y >  pi/2-margin) cam.Angles.y =  pi/2-margin;

    vec3 lookat(
        sinf(cam.Angles.x) * cosf(cam.Angles.y),
                             sinf(cam.Angles.y),
        cosf(cam.Angles.x) * cosf(cam.Angles.y)
    );

    cam.View = lookAt(cam.Position, cam.Position + lookat, vec3(0, 1, 0));
}

If you still have questions about that, feel free to ask.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .