I've seen this same topic discussed elsewhere, but in most cases the solution provider is dealing with a 2D (ortho) projection and so they gloss over the Z value. My world has the following characteristics:
I'm using a port of gluUnProject, and while I think my implementation of the port is sound, there could certainly be something wrong with that. What I was hoping to ask the community, though, is if my algorithm below looks correct. I'm determining the world coords at winZ=0 (near plane) and at winZ=1 (far plane). I'm then determining the ray from these two points, normalizing this, and determining at what value 't' this ray's Z coordinate will be 0 (at what point it intersections the Z=0 plane, which is what I'm after). The problem, however, is as I click near the origin (0,0,0) this works, but as soon as I start clicking away from the origin, the error grows (e.g. if the correct world coords should be 50, 0, 0 they are actually 85, 0, 0 based on the computations below.
If this procedure below is sound, then I can begin investigating my implementation of gluUnProject.
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
var pt = (touches.AnyObject as UITouch).LocationInView(this);
int[] viewport = new int[4];
float[] proj = new float[16];
float[] model = new float[16];
GL.GetInteger(All.Viewport, viewport);
GL.GetFloat(All.ProjectionMatrix, proj);
GL.GetFloat(All.ModelviewMatrix, model);
float[] near = new float[3];
float[] far = new float[3];
Utils.gluUnProjectf(pt.X, viewport[3] - pt.Y, 0f, model, proj, viewport, out near);
Utils.gluUnProjectf(pt.X, viewport[3] - pt.Y, 1f, model, proj, viewport, out far);
Vector rayDirection = new Vector(far[0] - near[0], far[1] - near[1], far[2] - near[2]);
rayDirection.Normalize();
float t = (0 - near[2]) / rayDirection.dZ;
Vertex end = new Vertex();
end.X = near[0] + rayDirection.dX * t;
end.Y = near[1] + rayDirection.dY * t;
end.Z = 0;
}
I implemented the same algorithm with a full version of OpenGL (complete with gluUnProject) and got the desired result. The algorithm is sound, my implementation of gluUnProject is not.