# World position reconstruction from depth fails when viewport size does not match window size

I'm facing very strange issue. My code for world pos reconstruction works correctly when the viewport size is equal to window size (or framebuffer size in other words). Below is the part for reconstruction to view space, later I multiply the result by inversed view matrix:

vec3 posFromDepth(in vec2 Tex, in float depth) {
vec3 pos = vec3(Tex, depth) * 2.0 - 1.0; // clip-space position

float z = -projection[3][2] / (pos.z + projection[2][2]);
float x = pos.x * halfTanFovX * -z;
float y = pos.y * halfTanFovY * -z;

return vec3(x, y, z);
}


When I change the viewport light and shadow calculations seems to be incorrect. The shadows for example instead of being "glued" to the object, floats a little bit along with camera movement.

When I switched my deferred renderer to use world pos stored in G-buffer then everything was calculated right. Is there some transformation of texture coordinates which I'm missing? I tried pass fullscreen quad coords in vertex attributes and compute using below formula:

gl_FragCoord.xy * texelSize


but the results were the same.

I'm searching for the issue more than week and slowly running out of ideas what could be wrong. Maybe you'll come up with something useful.

Looks like I found the solution and it was pretty obvious but I did not found similar case in any website which mentions about position reconstruction.

In my code I used texture coordinates computed using below formula:

gl_FragCoord.xy * texelSize


where texelSize is just an inverse of screen width and height. Then I used the same texture coordinates to define xy position in clip-space coordinates. So I transformed screen space coordinates to clip space coordinates.

The formula to perform such inverse transform is

vec2 clipPos = ((2.0 / screenSpace.xy) - (2.0 * viewport.xy)) / viewport.zw - 1.0;


where viewport.xy is an origin of the viewport and viewport.zw are width and height of the viewport.

If viewport is the same as the screen then it's origin point is equal to 0 what simplifies the equation to the one used by me. And that's why it worked in that case and did not work for viewports with different origin and size.

Hope it will be helpful for others.