Sunday, November 28, 2010

Order independent transparency (Front to back depth peeling)

I had been looking through a lot of docs on order independent transparency. I started off with http://developer.nvidia.com/object/order_independent_transparency.html
also called Front to Back Depth Peeling.
This is how it works.

You need three fbos, two fbos for depth sorting and one for final rendering. You need five fbo attachements in all, two for depth and two for front/back fragments and one texture for the final output. These are attached to the fbo as given in the setup code:
 
void setup_FBO() {
glGenFramebuffersEXT(2, fbo);
glGenTextures (2, texID);
glGenTextures (2, depthTexID);
for(int i=0;i<2;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_DEPTH_COMPONENT32F_NV, width, height, 0, GL_DEPTH_COMPONENT, 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);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo[i]);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, depthTexID[i], 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, texID[i], 0);
}

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_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, 0);

glGenFramebuffersEXT(1, &colorBlenderFBOID);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, colorBlenderFBOID);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, depthTexID[0], 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_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");

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

Next, the rendering code uses this information as follows

//matrix setup and other stuff
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, colorBlenderFBOID);
glDrawBuffer(g_drawBuffers[0]);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//In the first pass, we render normally with depth test enabled to get the nearest surface
glEnable(GL_DEPTH_TEST);
g_shaderFrontInit.bind();
g_shaderFrontInit.setUniform("Alpha", (float*)&g_opacity, 1);
RenderScene(angle); //do your rendering here
g_shaderFrontInit.unbind();
// ---------------------------------------------------------------------
// 2. Depth Peeling + Blending
// ---------------------------------------------------------------------
int numLayers = (NUM_PASSES - 1) * 2;
for (int layer = 1; g_useOQ || layer < numLayers; layer++) {
int currId = layer % 2;
int prevId = 1 - currId;

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo[currId]);
glDrawBuffer(g_drawBuffers[0]);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
if (g_useOQ) {
glBeginQuery(GL_SAMPLES_PASSED_ARB, g_queryId);
}
g_shaderFrontPeel.bind();
g_shaderFrontPeel.bindTextureRECT("DepthTex", depthTexID[prevId], 0);
g_shaderFrontPeel.setUniform("Alpha", (float*)&g_opacity, 1);
RenderScene(angle);
g_shaderFrontPeel.unbind();

if (g_useOQ) {
glEndQuery(GL_SAMPLES_PASSED_ARB);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, colorBlenderFBOID);
glDrawBuffer(g_drawBuffers[0]);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE,GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
g_shaderFrontBlend.bind();
g_shaderFrontBlend.bindTextureRECT("TempTex", texID[currId], 0);
DrawFullScreenQuad();
g_shaderFrontBlend.unbind();
glDisable(GL_BLEND);
if (g_useOQ) {
GLuint sample_count;
glGetQueryObjectuiv(g_queryId, GL_QUERY_RESULT_ARB, &sample_count);
if (sample_count == 0) {
break;
}
}
}

// ---------------------------------------------------------------------
// 3. Final Pass
// ---------------------------------------------------------------------
//remove the render to texture and set the back buffer as render target
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);

//attach the blending shader
g_shaderFrontFinal.bind();
g_shaderFrontFinal.setUniform("BackgroundColor", g_backgroundColor, 3);
g_shaderFrontFinal.bindTextureRECT("ColorTex", colorBlenderID, 0);
DrawFullScreenQuad();
g_shaderFrontFinal.unbind();

Thats it, this gives the following output.
Dual Depth Peeling Front to Back

Next, I will post infor on how to do dual depth peeling in opengl

9 comments:

Khoa Nguyen said...

Really nice,

Looking for this.

Thank you very much

MMMovania said...

You are always welcome :)

elect said...

Are shaders mandatory for the depth peeling?

MMMovania said...

Yes u will need shaders to implement depth peeling

Kati said...
This comment has been removed by the author.
Kati said...

Iam not sure how you implemented those g_XXX Methods.

Can you give me any more information?

I much appreciate your help.

MMMovania said...

HI,
You can download the source code from my book which contains a more modern implementation of this technique.

http://www.packtpub.com/support/11991

Jam-in! said...

Hi

Why do you need a color blending FBO ? Why not rendering the blending directly to the main screen ?

MMMovania said...

Hi Jam-in!,
We need color blending FBO because the blended result of pass n-1 is read to get the result for the pass n and this continues for all the depth slices.

Popular Posts

Copyright (C) 2011 - Movania Muhammad Mobeen. Awesome Inc. theme. Powered by Blogger.