19 February 2017

Math - Calculate a look-at matrix for OpenGL

The final piece of the puzzle to get my basic OpenGL scene up and running was the camera or look-at matrix. It is calculated from a position vector and a direction vector; the look-at vector.

The position and direction vectors

Here's how the position and direction vectors are calculated. The input comes from the mouse and keyboard. Note that I do use some extension methods to make life easier. Delta time is a time-based value to get the same speed on slow and fast computers.

rotationHorizontal += window.MouseMovement.X * 0.1f;
rotationHorizontal = rotationHorizontal.Circular(0, 359);
rotationVertical += window.MouseMovement.Y * 0.1f;
rotationVertical = rotationVertical.Constrain(-89, 89);

float h = rotationHorizontal.ToRadians();
float v = rotationVertical.ToRadians();
float hs = h.Sin();
float hc = h.Cos();
float vs = v.Sin();
float vc = v.Cos();
float speed = 0.005f * deltaTime;

if (window.KeyDown(Key.Up))
{
    position.X -= hc * speed;
    position.Z -= hs * speed;
}

if (window.KeyDown(Key.Down))
{
    position.X += hc * speed;
    position.Z += hs * speed;
}

if (window.KeyDown(Key.Left))
{
    position.X -= hs * speed;
    position.Z += hc * speed;
}

if (window.KeyDown(Key.Right))
{
    position.X += hs * speed;
    position.Z -= hc * speed;
}

var direction = new Vector(vc * hc, vs, vc * hs);
var camera = new Matrix(position, direction);

The look-at matrix

This one is again implemented as a constructor of the Matrix class. It uses some basic vector operations; the implementations of which can easily be found online.

public Matrix(Vector position, Vector direction)
{
    var up = new Vector(0, 1, 0);
    var zAxis = direction.Normalized();
    var xAxis = Vector.CrossProduct(up.Normalized(), zAxis).Normalized();
    var yAxis = Vector.CrossProduct(zAxis, xAxis);

    var translation = new Matrix();
    translation.Translate(position.Negated());

    var rotation = new Matrix();
    rotation.M[0, 0] = xAxis.X;
    rotation.M[0, 1] = xAxis.Y;
    rotation.M[0, 2] = xAxis.Z;

    rotation.M[1, 0] = yAxis.X;
    rotation.M[1, 1] = yAxis.Y;
    rotation.M[1, 2] = yAxis.Z;

    rotation.M[2, 0] = zAxis.X;
    rotation.M[2, 1] = zAxis.Y;
    rotation.M[2, 2] = zAxis.Z;

    var lookAt = rotation * translation;
    SetMatrix(lookAt.M);
}

See also

Simplified method to create a look-at matrix
Calculate a perspective projection matrix for OpenGL

No comments:

Post a Comment