PDA

View Full Version : Getting worldspace coordinate out of z-value



Jan
04-25-2004, 12:50 AM
Hi there

Iīm not so good at this math-stuff, therefore i couldnīt quite get the solution to this problem myself.

All i need, is to calculate the worldspace-position of a pixel. As information i have the z-value and the modelview and projection-matrix (and maybe their inverse).

Oh, almost forgot: Of course the screenspace-coordinates are available, too.

AFAIK it is possible to do that, but i donīt know how.

Thanks in advance,
Jan.

mikeman
04-25-2004, 04:55 AM
I have no idea what kind of algorithms are needed to write your own function that does that,but you can always use gluUnProject.

Jan
04-25-2004, 04:57 AM
Na, i have to be able to do it in a fragment program.

Thanks, though.
Jan.

mikeman
04-25-2004, 06:47 AM
This explains how gluUnProject works(quite simple,suprisingly):
http://www.hmug.org/man/3/gluUnProject.html

Jan
04-25-2004, 07:02 AM
Great. Thanks.

Now the only question remaining is, how i get the inverse of model*proj. Since this is certainly not an orthogonal matrix, i assume i cannot simply take the transpose, can i ?

Jan.

plasmonster
04-25-2004, 11:26 AM
Jan, here's another way to do it:



Since this is certainly not an orthogonal matrix, i assume i cannot simply take the transpose, can i ?
You can only do the transpose trick with an orthonormal basis.

edit:
-replaced sz with z
-changed variable names to clarify a few things

Jan
04-26-2004, 10:16 AM
Cool, thatīs a really great formula !
I didnīt have the time to try it, yet, but i will as soon as possible.

eyePos and eyeLeft, etc. are in worldspace, no ?

Thanks again.
Jan.

plasmonster
04-26-2004, 11:35 AM
Jan, that's affirm on the world space, for all the eye* vecs.

mikeman
04-26-2004, 12:30 PM
Originally posted by Portal:
Vector deproject( float sx, float sy, float z ){

float aspect = height / width;
float proj = tan( fieldOfViewX );
float x = -z*(2.0*sx/width-1.0)*proj;
float y = -z*(2.0*sy/height-1.0)*proj* aspect;

return eyePos + eyeLeft*x + eyeUp*y + eyeForward*z;
}
You are aware that the z-value is in the range [0,1],right?I don't think eyeForward*z will give the result you're expecting.Personally,i find it a little strange to be able to unproject a z-value in range[0,1] without having to use the Modelview and Projection matrices.

plasmonster
04-26-2004, 03:28 PM
mikeman, the z is an eye space z, not a screen space z. Also, I am using the projection and model view matrices, just not in a familiar matrix form. All I'm doing is reversing the projection process, in place of an explicit matrix inversion.

plasmonster
04-26-2004, 08:26 PM
Jan,

another thought: If you are using a fragment program, put the world vertex position from your vertex program into a tex coord, and use the lerped value in your fragment program, or did I misunderstand your question. The code I gave above assumes screen space, not homogeneous projection space. That too is doable, you just need to reverse that setup.

For the model view projection setup:
P = ProjMat * ModelView * Pw

You need to solve for Pw, the world position

invert(ProjMat * ModelMat) * P = Pw

or

invert(ModelMat) * invert(ProjMat) * P = Pw
(reverse order law of inversion)

All this says is (reading right to left): First undo the homogeneous projection, then undo the eye space projection.

Here's the invert(ProjMat) right out of the red book:
[(r-l)/(2n) 0 0 (r+l)/(2n) ]
[ 0 (t-b)/(2n) 0 (t+b)/(2n) ]
[ 0 0 0 -1 ]
[ 0 0 -(f-n)/(2fn) (f+n)/(2fn)]

Multiply this matrix with P to get your eye space position,

Pe = invert(ProjMat) * P.

Then proceed as before

Pw = eyePos + eyeLeft*eyeX + eyeUp*eyeY + eyeForward*eyeZ

Hope this makes some sense. :)

Jan
04-26-2004, 08:55 PM
I want to save the depth-value (meaning 1/z) into a texture. Later on i want to reconstruct the worldspace-coordinate by using the screenspace-position (ie. x=1..1024, y=1..768) of the pixel and the depth-value.

This is for deferred shading. By only saving the depth-value i want to save memory, instead of saving x,y,z i only want to save z (or better 1/z).

But as far as i understood you, that formula should be exactly what i need.

Thanks,
Jan.

mikeman
04-26-2004, 10:45 PM
If you want that formula to work,you have to save the eye-space z-coordinate,not (1/z) or the value of the depth buffer.

plasmonster
04-26-2004, 11:33 PM
It's a trivial matter going from a z-value in eye space to a z-value in projection or screen space:

projZ = -(f+n)/(f-n) * eyeZ - 2fn/(f-n)

this is from the red book - just the eye column vector with the 3rd row of the projection matrix.

screenZ = projZ / -eyeZ

eyeZ here is just the eye column vector with the 4th row of the projection matrix [0 0 -1 0], essentially a division by w.

I left all this out of my code simply because I just don't use the normalized z in my work, and I though it would confuse the issue.