Sign in to follow this  

OpenGL Deferred Depth Reconstruction

Recommended Posts

EnlightenedOne    142

Hi All,


I am porting/migrating my pipeline from forward to deferred rendering because I want precomputed atmospheric scattering. If I do not learn how to achieve the technique I will never die a happy man (and vice versa smile.png). The goal is:


The paper with it is interesting reading as is prolands source code example, however prolands demo does not actually use a GBuffer so I need to blend their high level behaviour from this DX port to achieve the effect in GLSL 330.


I am binding my render buffer as a texture (24bit 8 bit stencil), I can read and draw it to a quad on screen, I know that the none linear depth values it writes are valid and my shader/model binding process is tried and true (right handed). My current goal is to establish all the fiddly unpleasant transforms required to get from GBuffer post processing exposed and to better understand the most practical way to handle transforms around depth. My first stop was the realisation that if I can get the post process surfacePos below I will be home free as all the lighting is similar it is just the sources used to lookup values that have changed.


Here is the code I am attempting to port, the transforms through various coordinate space I have a loose grasp of, but the part I do not get is how the SV_POSITION translates in GLSL. Changing the gl_FragDepth to try and mimic screen space changes ends badly.


GBUFFER GEOMETRY___________________________________________________


struct VS_OUT {

float4 posH : SV_POSITION;

float3 posW : POSITION;

float3 tangent : TANGENT0;

float3 bitangent : TANGENT1;

float2 texC : TEXCOORD0;





Vertex shader snippet of interest to position:


output.posH = mul(float4(posWorld, 1.0f), g_viewProj);

output.posH.z = output.posH.z * output.posH.w * g_invFarPlane;


POST PROCESSING_____________________________________________________


Vertex Shader

static const float EPSILON_ATMOSPHERE = 0.002f;

static const float EPSILON_INSCATTER = 0.004f;


Texture2D g_depth;

Texture2D g_color;

Texture2D g_normal;

Texture2D g_texIrradiance;

Texture3D g_texInscatter;

float3 g_cameraPos;

float3 g_sunVector;

float4x4 g_cameraWorld;

float4 g_frustumFar[4];

float4 g_frustumNear[4];


struct VS_IN {

float3 posL : POSITION;

float2 texC : TEXCOORD0;

uint index : TEXCOORD1;



struct VS_OUT {

float4 posH : SV_POSITION;

float2 texC : TEXCOORD0;

float3 nearToFar : TEXCOORD2;

float3 cameraToNear : TEXCOORD3;



VS_OUT VS(VS_IN input) {

VS_OUT output;

output.posH = float4(input.posL,1.0f);

output.texC = input.texC;

float3 frustumFarWorld = mul(float4(g_frustumFar[input.index].xyz, 1.0f), g_cameraWorld).xyz;

float3 frustumNearWorld = mul(float4(g_frustumNear[input.index].xyz, 1.0f), g_cameraWorld).xyz;

output.cameraToNear = frustumNearWorld - g_cameraPos;

output.nearToFar = frustumFarWorld - frustumNearWorld;

return output;



Pixel Shader:


// reconstructing world space postion by interpolation

float depthVal = g_depth.SampleLevel( PointSamplerClamp, input.texC, 0 ).r;

float3 surfacePos = g_cameraPos + input.cameraToNear + depthVal * input.nearToFar;


// obtaining the view direction vector

float3 viewDir = normalize(input.nearToFar);


  • Can anyone confirm how the PosH value is impacting the encoding of the depth buffer and what the openGL equivalent would be?
  • Can anyone tell me the real values of those vec4[4] fustrums and where they can be derived from? I have no problem adding an index to my screen quad to link to it or building a clipping frustrum near or far plane. The problem I have is that it is glossed over and I am worried my deductive reasoning will be slower than the my goal. I really want my GBuffer ready to start assembling this post processing effect before the Easter holiday is done.


I believe g_cameraWorld is the world rotation of the camera.


I have gone through all of the following resources to try and understand how people are handling this process:


So far I have had no success reconstructing raw depth by blending these snippets input on the problem or testing them in relative isolation, I have a feeling that everyone is tampering with depth output in the geometry buffer but its not very clear in many of the snippets I have found exactly what parameters they are using to do this and why. I am going to try and focus on filling in the gaps from the model above because the resources above suggest it is still an efficient mechanism for solving reconstructing the desirable spaces in most post processes.


Does anyone have a tutorial where this reconstruction process is applied as a holistic piece of functioning code? I would love to see the implementation for these frustum shapes on the near and far plane. I just need to see a proper GBuffer pipeline using depth to reconstruct position and linear depth so I can reverse engineer and inspect its properties to understand the bugs in my own code and move on.


I really cannot wait to play with that effect. If I get my shaders to reconstruct from depth I will post them up and describe the parts that have as of yet confounded me.


I welcome any input.


Many Thanks,

Enlightened One

Share this post

Link to post
Share on other sites
EnlightenedOne    142

I solved a bug in one of the references where they multiply 2 * zNear * zFar when they only need 2 * zNear in part of the equation, this got me seeing linearised space from a none linear depth in the real depth buffer. I reread the details of the precomputed atmospheric scattering paper and concluded that the SVPosition and Position allow the real position and clip space depth? to be set independently. Although I might have really screwed up in my interpretation of their duality.


Ok so I am attempting to understand how to force linear depth in the hardware Depth buffer to bring myself closer to the DX PCAS paper, the goal is linear depth in the real depth buffer with the world space position and by extension the view direction cheaply solved in the pixel shader from this depth.


Right now I am studying Yours3!f's description to progress:

I am concerned he is using a separate texture from the real depth buffer... if he is using something to map to the SV_Poistion equivalent he is not hinting at it.


This article is interesting but just too abstract for me to apply:

Off of it is a sample for "attack the depth buffer", it is a great sample but their pixel shader code has:

float2 DepthCS      : DEPTH;
float4 PositionCS   : SV_POSITION;
Again it seems not understanding the GL version of clip space is hurting me.


To better qualify my FBO I have 24/8 depth/stencil buffer, normal 32 and colour 32, I believe that should be enough.

Share this post

Link to post
Share on other sites
EnlightenedOne    142

My goodness it worked!



#version 330
in vec3 inPos;
in vec4 inCol;
//model being tested has no normals yet
uniform mat4 inverseProjectionMatrix;
uniform mat4 wvpMatrix;
uniform mat4 modelViewMatrix;
out vec3 pass_colour;
out vec4 worldPosition;
out float depth;
const float far_plane_distance = 15000.0f;
void main(void) {
gl_Position = wvpMatrix * vec4(inPos, 1);
worldPosition = gl_Position;
vec4 viewSpacePos = modelViewMatrix * vec4(inPos, 1);
depth = viewSpacePos.z / - far_plane_distance;
pass_colour =;
#version 330
in vec3 pass_colour;
in vec4 worldPosition;
in float depth;
layout (location = 0) out vec4 ColourOut;   
layout (location = 1) out vec4 NormalOut;
layout (location = 2) out vec4 PosOut;     
void main(void) {
ColourOut = vec4(pass_colour, 1);
NormalOut = vec4(0.5,0.5,0.5,1); //dummy values please ignore =; //intending to use this to compare to the reconstructed positions as soon as I have either working smile.png
PosOut.w = 1;
gl_FragDepth = depth;


Then just sampling the depth:

    d = texture2D(texture_depth, pass_texCoord).x;
  DepthOut = vec4(d, d, d, 1.0);
My old linearisation from none linear depth buffer approach when using this is redundant as the depth texture is linear. Following on from his approach I expect I will get the desired view space positions necessary to get around.
I dug out this:
It suggests what I am doing is a recipe for performance disaster, however "gl_Position.z = viewSpacePos.z / - far_plane_distance;" simply causes depth testing to fail.
Interestingly but obviously I get less close banding from the none linear depth calculation, reconstructing linear depth without storing it must be the way forward.
I am about to find out if I stick with post GBuffer linear depth reconstruction can I still reconstruct the surface position using Yours3!f's method? more challenging will be to get the viewDir from this data.
Edited by EnlightenedOne

Share this post

Link to post
Share on other sites
EnlightenedOne    142

Looks like I can get to both view and world space if I plug my derived linear depth into:


Based on the attack the depth buffer pixel shader:

    float3 viewRay = float3(Input.PositionVS.xy / Input.PositionVS.z, 1.0f);
    float3 positionVS = LinearizedDepth(depthTextureForPizel) * viewRay;

Where positionVS is the world view project multiplied vertex as per standard transform, Yours3!f's method includes additional transforms that may be required for OpenGL but I haven't tested that yet.


The real work will be getting to world space without matrix multiplication per pixel that is my current task.

Share this post

Link to post
Share on other sites

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  

  • Similar Content

    • By Zaphyk
      I am developing my engine using the OpenGL 3.3 compatibility profile. It runs as expected on my NVIDIA card and on my Intel Card however when I tried it on an AMD setup it ran 3 times worse than on the other setups. Could this be a AMD driver thing or is this probably a problem with my OGL code? Could a different code standard create such bad performance?
    • By Kjell Andersson
      I'm trying to get some legacy OpenGL code to run with a shader pipeline,
      The legacy code uses glVertexPointer(), glColorPointer(), glNormalPointer() and glTexCoordPointer() to supply the vertex information.
      I know that it should be using setVertexAttribPointer() etc to clearly define the layout but that is not an option right now since the legacy code can't be modified to that extent.
      I've got a version 330 vertex shader to somewhat work:
      #version 330 uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewMatrix; layout(location = 0) in vec4 Vertex; layout(location = 2) in vec4 Normal; // Velocity layout(location = 3) in vec3 TexCoord; // TODO: is this the right layout location? out VertexData { vec4 color; vec3 velocity; float size; } VertexOut; void main(void) { vec4 p0 = Vertex; vec4 p1 = Vertex + vec4(Normal.x, Normal.y, Normal.z, 0.0f); vec3 velocity = (osg_ModelViewProjectionMatrix * p1 - osg_ModelViewProjectionMatrix * p0).xyz; VertexOut.velocity = velocity; VertexOut.size = TexCoord.y; gl_Position = osg_ModelViewMatrix * Vertex; } What works is the Vertex and Normal information that the legacy C++ OpenGL code seem to provide in layout location 0 and 2. This is fine.
      What I'm not getting to work is the TexCoord information that is supplied by a glTexCoordPointer() call in C++.
      What layout location is the old standard pipeline using for glTexCoordPointer()? Or is this undefined?
      Side note: I'm trying to get an OpenSceneGraph 3.4.0 particle system to use custom vertex, geometry and fragment shaders for rendering the particles.
    • By markshaw001
      Hi i am new to this forum  i wanted to ask for help from all of you i want to generate real time terrain using a 32 bit heightmap i am good at c++ and have started learning Opengl as i am very interested in making landscapes in opengl i have looked around the internet for help about this topic but i am not getting the hang of the concepts and what they are doing can some here suggests me some good resources for making terrain engine please for example like tutorials,books etc so that i can understand the whole concept of terrain generation.
    • By KarimIO
      Hey guys. I'm trying to get my application to work on my Nvidia GTX 970 desktop. It currently works on my Intel HD 3000 laptop, but on the desktop, every bind textures specifically from framebuffers, I get half a second of lag. This is done 4 times as I have three RGBA textures and one depth 32F buffer. I tried to use debugging software for the first time - RenderDoc only shows SwapBuffers() and no OGL calls, while Nvidia Nsight crashes upon execution, so neither are helpful. Without binding it runs regularly. This does not happen with non-framebuffer binds.
      GLFramebuffer::GLFramebuffer(FramebufferCreateInfo createInfo) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); textures = new GLuint[createInfo.numColorTargets]; glGenTextures(createInfo.numColorTargets, textures); GLenum *DrawBuffers = new GLenum[createInfo.numColorTargets]; for (uint32_t i = 0; i < createInfo.numColorTargets; i++) { glBindTexture(GL_TEXTURE_2D, textures[i]); GLint internalFormat; GLenum format; TranslateFormats(createInfo.colorFormats[i], format, internalFormat); // returns GL_RGBA and GL_RGBA glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, createInfo.width, createInfo.height, 0, format, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); DrawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; glBindTexture(GL_TEXTURE_2D, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, textures[i], 0); } if (createInfo.depthFormat != FORMAT_DEPTH_NONE) { GLenum depthFormat; switch (createInfo.depthFormat) { case FORMAT_DEPTH_16: depthFormat = GL_DEPTH_COMPONENT16; break; case FORMAT_DEPTH_24: depthFormat = GL_DEPTH_COMPONENT24; break; case FORMAT_DEPTH_32: depthFormat = GL_DEPTH_COMPONENT32; break; case FORMAT_DEPTH_24_STENCIL_8: depthFormat = GL_DEPTH24_STENCIL8; break; case FORMAT_DEPTH_32_STENCIL_8: depthFormat = GL_DEPTH32F_STENCIL8; break; } glGenTextures(1, &depthrenderbuffer); glBindTexture(GL_TEXTURE_2D, depthrenderbuffer); glTexImage2D(GL_TEXTURE_2D, 0, depthFormat, createInfo.width, createInfo.height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthrenderbuffer, 0); } if (createInfo.numColorTargets > 0) glDrawBuffers(createInfo.numColorTargets, DrawBuffers); else glDrawBuffer(GL_NONE); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cout << "Framebuffer Incomplete\n"; glBindFramebuffer(GL_FRAMEBUFFER, 0); width = createInfo.width; height = createInfo.height; } // ... // FBO Creation FramebufferCreateInfo gbufferCI; gbufferCI.colorFormats =; gbufferCI.depthFormat = FORMAT_DEPTH_32; gbufferCI.numColorTargets = gbufferCFs.size(); gbufferCI.width = engine.settings.resolutionX; gbufferCI.height = engine.settings.resolutionY; gbufferCI.renderPass = nullptr; gbuffer = graphicsWrapper->CreateFramebuffer(gbufferCI); // Bind glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); // Draw here... // Bind to textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[0]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textures[1]); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textures[2]); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, depthrenderbuffer); Here is an extract of my code. I can't think of anything else to include. I've really been butting my head into a wall trying to think of a reason but I can think of none and all my research yields nothing. Thanks in advance!
    • By Adrianensis
      Hi everyone, I've shared my 2D Game Engine source code. It's the result of 4 years working on it (and I still continue improving features ) and I want to share with the community. You can see some videos on youtube and some demo gifs on my twitter account.
      This Engine has been developed as End-of-Degree Project and it is coded in Javascript, WebGL and GLSL. The engine is written from scratch.
      This is not a professional engine but it's for learning purposes, so anyone can review the code an learn basis about graphics, physics or game engine architecture. Source code on this GitHub repository.
      I'm available for a good conversation about Game Engine / Graphics Programming
  • Popular Now