Sign in to follow this  

gluUnProject() Question

This topic is 4068 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

(Note: I am using my own equivalent of the glu library for portability reasons; the function is pretty much exactly the same) I am confused what the purpose of the "WinZ" parameter to gluUnProject(WinXYZ,...,ObjXYZ&,...) is? As far as I know, the WinZ is supposed to be the distance I want the 'unprojected' world-space point (ObjXYZ) to be from the camera near plane, in "camera space" [is that the right terminology?] (0.0 = near, 1.0 = far). With the camera facing +Z from Z=0, with a frustum near-far of 0.1-5000.0, I pass a WinXYZ with WinZ as 1.0. The returned ObjXYZ point is around the far-plane at Z=~5000.0 (the result seems to be slightly inaccurate - I'll assume that's normal behavior for now). When I do WinZ=0.0, the returned ObjXYZ point is on the near-plane at Z=~0.1. Everything seems normal so far. But when I pass a WinXYZ with WinZ=0.5, the returned ObjXYZ remains on the near-plane at Z=~0.1, instead of what I wanted: Z=~2500.0. Anything other than WinZ=1.0 results in the ObjXYZ remaining on the near-plane. Q) Is this supposed to happen? Q) Is the slight inaccuracy in gluUnProject() normal? Thanks. My gluUnProject() equivalent, just in case there's an error I may have overlooked: The difference is that the inverse composed projection and modelview matrices are precomputed outside of the function
bool UnProjectVector(Vector3f& rkVec, Matrix4f& rkInvComposedMatrix, float afViewport[4])
{

    Vector4f kIn;
    Vector4f kOut;
    
    kIn[0] = rkVec[0];
    kIn[1] = rkVec[1];
    kIn[2] = rkVec[2];
    kIn[3] = 1.0f;
    
    kIn[0] = (kIn[0] - afViewport[0]) / afViewport[2];
    kIn[1] = (kIn[1] - afViewport[1]) / afViewport[3];
    
    kIn[0] = kIn[0]*2.0f-1.0f;
    kIn[1] = kIn[1]*2.0f-1.0f;
    kIn[2] = kIn[2]*2.0f-1.0f;
    
    kOut = rkInvComposedMatrix*kIn;
    if(kOut[3]==0.0)
	return false;
    
    kOut[0] /= kOut[3];
    kOut[1] /= kOut[3];
    kOut[2] /= kOut[3];
    
    rkVec = Vector3f(kOut[0],kOut[1],kOut[2]);
    return true;
}




Share this post


Link to post
Share on other sites
The reason is because the Z-axis transformation is non-linear, and your near plane value is extremely bad. A good near-to-far value ratio range is about 0.001-0.002, while your ratio is .00002! If you have a graphing calculator (or any graphing software), graph the function (-FN/(F-N))(1/x) + (F/(F-N)), which is the projection transformation for the Z-axis, with N=0.1 and F=5000. Choose your viewing window to be x=[N,F] and y=[0,1]. You'll see that the graph is almost vertical around the near plane, and about 90% of your precision is between 0.1 and 1. So when you do the reverse transformation, WinZ is the y value in this graph, and you're determining the x value. Again, you can see that almost the entire y range between 0 and 1 is spanned within the first couple of units of x.

Now let N=10 and F=10000 (N/F = 0.001). You'll notice that the graph rises much slower and that there's a smooth rounded curve more reminiscent of the inverse-linear graph 1/x we're used to. As far as testing your function, an N/F of about 0.5 will give you a very good mapping. While you'd never actually use that ratio in a real application, it gives you something almost linear that's easy to test.

Share this post


Link to post
Share on other sites
@Zipster: are you saying the the near/far ratio will adversely affect the outcome of the ObjXYZ?

I changed my near/far to 1.0 and 1000.0f, and I just noticed something new. If I pass WinZ as 1.0, I get the ObjXYZ on the far plane. If I pass WinZ as 0.0, I get the ObjXYZ on the near plane. If I pass WinZ as 0.5, I don't get an ObjXYZ half-way between the near and far planes, as I'd expect it to. Instead, as WinZ goes from 0.5 to 1.0, the ObjXYZ depth increase exponentially. A WinZ of 0.999 seems to return what I'd expect a WinZ of 0.5 to return ("half-way"). Am I missing something?

[Edited by - swordfish on October 21, 2006 1:50:59 PM]

Share this post


Link to post
Share on other sites
It's not increasing exponentially, it's increasingly inverse-linearly, according to the equation I posted before. It's not an "adverse" effect, it's just the way the transformation works. I definitely recommend taking a look at the graph of that function. It's guaranteed to answer all your questions [smile]

Share this post


Link to post
Share on other sites
Okay, I see what you mean by 'inverse linear'. I was on the right track at first, but I forgot to invert my Y screen coord, which caused a domino effect of confusion.

So in conclusion, WinZ is 1.0/Near. And don't forget to invert your Y-coord (1-WinY).

[EDIT]
Wrong once again. I did some more research (sorry, I'm not good with graphing) and found this: z = (1/Zn - 1/Z) / (1/Zn - 1/Zf)

I can see where many people would get confused here.
There is a difference between "Screen Space Z" and "World Space Z".

WinZ = (1.0f/fNear-1.0f/fDistance)/(1.0f/fNear-1.0f/fFar)
Where fNear/fFar are the near/far plane distances, and fDistance is the distance you want the unprojected point to be from the camera.

[Edited by - swordfish on October 26, 2006 12:23:25 PM]

Share this post


Link to post
Share on other sites

This topic is 4068 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this