PDA

View Full Version : Please help gl_fragcoord to world coordinates

anopgl
11-03-2011, 07:50 AM
Hi ,

How can I convert in fragment shader each pixel from gl_fragcoord x,y,z respectively to my "3d space world coordinates" x,y,z ?

Thanks a lot in advance

BionicBytes
11-03-2011, 08:03 AM
gl_FragCoord is an input variable that contains the window relative coordinate (x, y, z, 1/w) values for the fragment. This value is the result of fixed functionality that interpolates primitives after vertex processing to generate fragments.
In the vertex shader, we typically compute:

gl_Position = (gl_ModelViewProjection * gl_Vertex);
The last thing the Vertex Shader stage does is a divide by w, or gl_Position.w to be precise.

So, we could say that:
gl_FragCoord.xyz = gl_Position.xyz/gl_Position.w;
and
gl_FragCoord.w = 1/gl_Position.w;

So dividing gl_FragCoord.xyz / gl_FragCoord.w
yields the original gl_Position.xyz.
Multply gl_Position.xyz by the inverseProjection matrix should give you back the eye-space poistion,
or multiply gl_Position.xyz by the inverseModelViewProjecion should give you world/model space position, eg gl_Vertex.

Give that a try and let me know if my maths is wrong!

anopgl
11-03-2011, 08:30 AM
Thanks!

But my problem is that I can't use vertex coordinate since it's different resolution.
I'm trying to do per pixel shader for each pixel.

I'm trying to use Alfonse's tutorial (which is great) code:

vec3 CalcCameraSpacePosition()
{
vec4 ndcPos;
ndcPos.xy = ((gl_FragCoord.xy / windowSize.xy) * 2.0) - 1.0;
ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
(gl_DepthRange.far - gl_DepthRange.near);
ndcPos.w = 1.0;

vec4 clipPos = ndcPos / gl_FragCoord.w;

return vec3(clipToCameraMatrix * clipPos);
}

But I have some questions about calculation here:
1.How can we assume that w = 1?
2. Are we assuming here that our world space is [-1,1]?
ndcPos.xy = ((gl_FragCoord.xy / windowSize.xy) * 2.0) - 1.0;

Thanks

BionicBytes
11-03-2011, 08:35 AM
Having just read back my own post, I think I've missed out a step in the process.
The gl_FragCoord is window space coordinates, so that means the gl_Position values must have been multiplied by the viewport to put the values in the range 0...window width, 0..window height.
These window coordinates need to be converted to NDC coordinates [0..1] and that must be undone if we want to convert back to the original gl_position given gl_FragCoord.

The following code should give you something close.

vec3 PositionFromDepth_DarkPhoton(in float depth)
{
vec2 ndc; // Reconstructed NDC-space position
vec3 eye; // Reconstructed EYE-space position

eye.z = near * far / ((depth * (far - near)) - far);

ndc.x = ((gl_FragCoord.x * widthInv) - 0.5) * 2.0;
ndc.y = ((gl_FragCoord.y * heightInv) - 0.5) * 2.0;

eye.x = ( (-ndc.x * eye.z) * (right-left)/(2*near)
- eye.z * (right+left)/(2*near) );
eye.y = ( (-ndc.y * eye.z) * (top-bottom)/(2*near)
- eye.z * (top+bottom)/(2*near) );

return eye;
}

which simplifies to...

eye.x = (-ndc.x * eye.z) * right/near;
eye.y = (-ndc.y * eye.z) * top/near;

And note that typically you don't store Z_ndc NDC-space depth (-1..1) in a depth texture. You usually store Z_viewport -- that is viewport-space depth (0..1, or whatever you set glDepthRange to). But undoing that mapping to get to Z_ndc is easy.

Referring to the projection matrix, for a perspective projection you have:

z_ndc = z_clip / w_clip
z_ndc = [ z_eye*gl_ProjectionMatrix[2].z + gl_ProjectionMatrix[3].z ] / -z_eye

The 2nd step presumes w_eye = 1. Solve the above z_eye, and you get:

float z_eye = gl_ProjectionMatrix[3].z/(-z_ndc - gl_ProjectionMatrix[2].z);

Typically your glDepthRange is 0..1, so z_ndc = z_viewport * 2 - 1, so plugging that in...

float z_eye = gl_ProjectionMatrix[3].z/(z_viewport * -2.0 + 1.0 - gl_ProjectionMatrix[2].z);

That'll get you from viewport-space Z to eye-space Z, for a perspective projection.

BionicBytes
11-03-2011, 08:42 AM
But I have some questions about calculation here:
1.How can we assume that w = 1?
2. Are we assuming here that our world space is [-1,1]?
ndcPos.xy = ((gl_FragCoord.xy / windowSize.xy) * 2.0) - 1.0;

Which .w are you talking about?
In NCD space, w will be 1 when you 'unproject'

world space is [-1,1]?

Clip space is -1,1; not world space.
Since our projected scene is converted to clipspace, then yes the entire world eventually gets reduced down to -1,1.

anopgl
11-03-2011, 08:42 AM
Thanks a lot!
It will take me a while now to "digest" it and fix and test my code.

Alfonse Reinheart
11-03-2011, 10:27 AM
1.How can we assume that w = 1?

Because NDC-space W is clip-space W divided by clip-space W.

X/X == 1 for any non-zero X.

anopgl
11-17-2011, 09:27 AM
[quote]
X/X == 1 for any non-zero X. :D