Reconstructing world coordinates from a depth buffer and an arbitrary projection matrix

I am trying to recover the 3D coordinates of the world from the depths in my deferred renderer, but I have damn time. Most of the examples that I find on the Internet suggest a standard perspective transformation, but I do not want to make this assumption.

In my geometry, pass the vertex shader, I compute gl_Position using:

gl_Position = wvpMatrix * vec4(vertexLocation, 1.0f); 

and in my lighting transmission shader, I am trying to get world coordinates using:

 vec3 decodeLocation() { vec4 clipSpaceLocation; clipSpaceLocation.xy = texcoord * 2.0f - 1.0f; clipSpaceLocation.z = texture(depthSampler, texcoord).r; clipSpaceLocation.w = 1.0f; vec4 homogenousLocation = viewProjectionInverseMatrix * clipSpaceLocation; return homogenousLocation.xyz / homogenousLocation.w; } 

I thought that everything was correct, and indeed, the objects next to the camera seemed bright. But recently, I realized that moving further, objects are lit, as if they are farther from the camera than in reality. I played with my lighting passage and checked that my world coordinates were the only thing that miscalculated.

I cannot help but think that my clipSpaceLocation.z and clipSpaceLocation.w files are the source of the problem, but I tried all the options that I can come up with to calculate them, and the above code leads to the most correct results.

Any ideas or suggestions?

+6
source share
3 answers

I only needed to make a small correction. Line:

 clipSpaceLocation.z = texture(depthSampler, texcoord).r; 

should read:

 clipSpaceLocation.z = texture(depthSampler, texcoord).r * 2.0f - 1.0f; 

As I understand it, projection matrices are designed so that they compare the near and far planes with [-1,1], and not [0,1], as I always assumed. OpenGL then normalizes them to the range [0,1] (aka "Window Space"), so I had to invert this normalization.

All this implies glDepthRange (0, 1), which is the default, and there is little reason to change it.

+4
source

Your general approach is correct; you simply did not invert the conversion of the window space correctly. The window of space z (which you probably wtrot in your depth texture) is [0,1] ( glDepthRange() will be more general by default), but the NDC z space is [-1,1]. So you can change this line, similar to your x and y mappings, to

 clipSpaceLocation.z = texture(depthSampler, texcoord).r * 2.0 - 1.0; 
+1
source

See my answer to gamedev.stackexchange for a more efficient way to restore the world and view spatial positions:

https://gamedev.stackexchange.com/a/111885/24009

0
source

All Articles