As an exercise in trying to learn 3D math, I've been experimenting with hit-testing by casting a ray from 2D screen space into 3D world space. My first attempt was as follows:
Matrix m = Matrix.Invert(
this.scene.Camera.ViewMatrix *
this.scene.Camera.ProjectionMatrix *
homogeneousToViewportTransform());
Vector3 rayOrigin = Vector3.TransformCoordinate(new Vector3(p.X, p.Y, 0), m);
Vector3 rayVector = Vector3.TransformCoordinate(new Vector3(0, 0, -1), m);
This gets the ray origin correct, but not the ray vector. My reasoning was that the vector [0, 0, -1] is facing into the screen when in screen space, so transforming that into world space would give the correct vector. But that doesn't seem to be the case. Looking around, I've found that the correct way to calculate this is by doing:
Vector3 rayVector = new Vector3(
m.M31 - (m.M34 * rayOrigin.X),
m.M32 - (m.M34 * rayOrigin.Y),
m.M33 - (m.M34 * rayOrigin.Z));
rayVector.Normalize();
Can anyone explain what's wrong with my original reasoning, and what the actual algorithm for calculating the ray vector is doing?