This information is extracted from the original NVIDIA whitepaper on dual depth peeling http://developer.download.nvidia.com/SDK/10.5/opengl/src/dual_depth_peeling/doc/DualDepthPeeling.pdf
To sumup this is how it is implemented.
You need two fbo (one for depth test and other for final blending), two depth textures(RG32F not depth attachments), two textures (front/back fragments) and a color blend final texture. The fbo setup code is as follows,
The rendering code is similar to the front to back depth peeling except that now the code initialized the depths twice once for front and next for back fragments in the same pass. This is accompalished using Min/Max blending as follows
Thats it. The output this gives is as follows.
The inset displays the front and the back fragments. On some requests, here is the link to the source codes for this demo.
https://dl.dropboxusercontent.com/u/5513476/DualDepthPeeling.zip
Note that you will need NVIDIA OpenGL sdk to compile and run this as I am using some classes from the sdk package
Enjoy !!!
To sumup this is how it is implemented.
You need two fbo (one for depth test and other for final blending), two depth textures(RG32F not depth attachments), two textures (front/back fragments) and a color blend final texture. The fbo setup code is as follows,
void setup_fbo() { glGenFramebuffersEXT(1, &dualDepthfboID); glGenTextures (2, texID); glGenTextures (2, backTexID); glGenTextures (2, depthTexID); for(int i=0;i<2 br="" i="">glBindTexture(GL_TEXTURE_RECTANGLE_ARB, depthTexID[i]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T, GL_CLAMP); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB , 0,GL_FLOAT_RG32_NV, width, height, 0, GL_RGB, GL_FLOAT, NULL); glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texID[i]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T, GL_CLAMP); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB , 0,GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, NULL); glBindTexture(GL_TEXTURE_RECTANGLE_ARB,backTexID[i]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T, GL_CLAMP); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB , 0,GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, NULL); } glGenTextures(1, &colorBlenderID); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, colorBlenderID); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, 0); glGenFramebuffersEXT(1, &colorBlenderFBOID); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, colorBlenderFBOID); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, colorBlenderID, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dualDepthfboID); CHECK_GL_ERRORS; int j = 0; glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, depthTexID[j], 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, texID[j], 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_RECTANGLE_ARB, backTexID[j], 0); j = 1; glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_TEXTURE_RECTANGLE_ARB, depthTexID[j], 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT4_EXT, GL_TEXTURE_RECTANGLE_ARB, texID[j], 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT5_EXT, GL_TEXTURE_RECTANGLE_ARB, backTexID[j], 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT6_EXT, GL_TEXTURE_RECTANGLE_ARB, colorBlenderID, 0); GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if(status == GL_FRAMEBUFFER_COMPLETE_EXT ) printf("OK for render to texture\n"); else printf("Problem with FBO."); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } 2>
The rendering code is similar to the front to back depth peeling except that now the code initialized the depths twice once for front and next for back fragments in the same pass. This is accompalished using Min/Max blending as follows
//matrix manipulation stuff.. glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); // --------------------------------------------------------------------- // 1. Initialize Min-Max Depth Buffer // --------------------------------------------------------------------- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dualDepthfboID); // Render targets 1 and 2 store the front and back colors // Clear to 0.0 and use MAX blending to filter written color // At most one front color and one back color can be written every pass glDrawBuffers(2, &g_drawBuffers[1]); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); // Render target 0 stores (-minDepth, maxDepth, alphaMultiplier) glDrawBuffer(g_drawBuffers[0]); glClear(GL_COLOR_BUFFER_BIT); glBlendEquationEXT(GL_MAX_EXT); g_shaderDualInit.bind(); RenderScene(angle); g_shaderDualInit.unbind(); //The init shader above assigns float2(-1,1) to gl_FragCoord.xy; // --------------------------------------------------------------------- // 2. Dual Depth Peeling + Blending // --------------------------------------------------------------------- // Since we cannot blend the back colors in the geometry passes, // we use another render target to do the alpha blending glDrawBuffer(g_drawBuffers[6]); glClearColor(g_backgroundColor[0], g_backgroundColor[1], g_backgroundColor[2], 0); glClear(GL_COLOR_BUFFER_BIT); int currId = 0; for (int pass = 1; g_useOQ || pass < NUM_PASSES; pass++) { currId = pass % 2; int prevId = 1 - currId; int bufId = currId * 3; glDrawBuffers(2, &g_drawBuffers[bufId+1]); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); glDrawBuffer(g_drawBuffers[bufId+0]); glClearColor(-MAX_DEPTH, -MAX_DEPTH, 0, 0); glClear(GL_COLOR_BUFFER_BIT); // Render target 0: RG32F MAX blending // Render target 1: RGBA MAX blending // Render target 2: RGBA MAX blending glDrawBuffers(3, &g_drawBuffers[bufId+0]); glBlendEquationEXT(GL_MAX_EXT); g_shaderDualPeel.bind(); g_shaderDualPeel.bindTextureRECT("DepthBlenderTex", depthTexID[prevId], 0); g_shaderDualPeel.bindTextureRECT("FrontBlenderTex", texID[prevId], 1); g_shaderDualPeel.setUniform("Alpha", (float*)&g_opacity, 1); RenderScene(angle); g_shaderDualPeel.unbind(); // Full screen pass to alpha-blend the back color glDrawBuffer(g_drawBuffers[6]); glBlendEquationEXT(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (g_useOQ) { glBeginQuery(GL_SAMPLES_PASSED_ARB, g_queryId); } g_shaderDualBlend.bind(); g_shaderDualBlend.bindTextureRECT("TempTex", backTexID[currId], 0); DrawFullScreenQuad(); g_shaderDualBlend.unbind(); if (g_useOQ) { glEndQuery(GL_SAMPLES_PASSED_ARB); GLuint sample_count; glGetQueryObjectuiv(g_queryId, GL_QUERY_RESULT_ARB, &sample_count); if (sample_count == 0) { break; } } } glDisable(GL_BLEND); // --------------------------------------------------------------------- // 3. Final Pass // --------------------------------------------------------------------- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDrawBuffer(GL_BACK); g_shaderDualFinal.bind(); g_shaderDualFinal.bindTextureRECT("DepthBlenderTex", depthTexID[currId], 0); g_shaderDualFinal.bindTextureRECT("FrontBlenderTex", texID[currId], 1); g_shaderDualFinal.bindTextureRECT("BackBlenderTex", colorBlenderID, 2); DrawFullScreenQuad(); g_shaderDualFinal.unbind();
Thats it. The output this gives is as follows.
The inset displays the front and the back fragments. On some requests, here is the link to the source codes for this demo.
https://dl.dropboxusercontent.com/u/5513476/DualDepthPeeling.zip
Note that you will need NVIDIA OpenGL sdk to compile and run this as I am using some classes from the sdk package
Enjoy !!!
1 comments:
Post a Comment