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 matrixCalculate a perspective projection matrix for OpenGL