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