Just wanted to give ya'll food for thought, since it took me a couple days to work this out.
I'm designing a GUI system that works on a Foreground node at a distance of -0.6f from the camera.
First, using the screenToFG() function I previously figured out:
Point3f screenToFG (Point screen, float depth)
float xfrac = (float)((screen.x / canvasWidth) - 0.5f) * -2.0f;
float yfrac = (float)((screen.y / canvasHeight) - 0.5f) * 2.0f;
float heightA = canvasTanFOV * depth;
return new Point3f(xfrac * heightA * canvasAspect, yfrac * heightA, depth);
where canvasTanFOV = Math.tan(canvasFOV)
Using this, I determined that at a depth of -0.6f, a quad that exactly covers the entire screen is of the following 3D coords in the Foreground node:
Pixel -> Foreground 3D coords
(0,0) -> (-0.559797, 0.41984773, -0.6)
(800,600) -> (0.559797, -0.41984773, -0.6)
Size: 1.119594 x 0.83969546
Then, to get even fancier, I figured rather than making custom fuctions to do all this math for me, why don't I just figure out a transformation matrix to do all this work for me. So I ended up with this:
float xscale = 1.119594f / canvasWidth;
float yscale = 0.83969546f / canvasHeight;
TransformGroup foregroundTG = new TransformGroup();
Transform3D tmp = new Transform3D();
Transform3D tmp2 = new Transform3D();
Foreground fg = new Foreground(foregroundBG, View.VIEW_FIXED);
Now you can create quads with vertices in X, Y pixel coords (with Z=0) and it should map into the Foreground 3D coords automatically. Just make sure to add your quads to foregroundTG.
Another cool benefit is that with the entire GUI system based on a single TransformGroup, you can reposition the entire GUI in one step... like scrolling it off the screen, shaking it, etc.
Maybe a new ScreenGUI node (extends Foreground node) that does all this automatically? I couldn't even begin to put that into Xith, just an idea. I got my code working with the above anyway, so I'm good to go already.
Possible issues to be debugged... I might have one too many negative signs in there, flipping (and reflipping) things too many times but coming out correctly in the end. Also, the Foreground stack looks like this:
ForegroundBG -> ForegroundTG -> user quads
I dunno if the ForegroundBG is really necessary. The Foreground node only seems to accept BranchGroups, maybe it can be made to accept just Nodes and then we can skip the extraneous ForegroundBG? I don't know how to do any of this, I just know the code above works for my needs