PDA

View Full Version : Depth buffer emulation



mlfarrell
11-14-2009, 02:03 PM
Okay, so i'm expanding on weighted average sums for order independent transparency.

My idea is so, to add a single "depth" pass to the shader pipeline with GL_MIN_EXT blend equation. To store the least depth coordinate of any opaque objects and discard fragments greater than this on the "init" pass of the weighted average shader.

For those confused, ignore everything I just said, essentially I'm just trying to emulate a depth pass. The problem is its really not working out, even if I add a tolerance value

init code


#ifdef MACOSX
FLOAT_R32 = GL_RGBA16F_ARB;
#endif

multipass_mode = MP_WEIGHTED_AVG;

glGenTextures(4, fbo_textures);
for(int i = 0; i < 4; i++)
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fbo_textures[i]);
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);

if(i == 0) //background
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if(i == 3) //min depth
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_FLOAT, NULL);
else if(i == 1)
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_FLOAT, NULL);
else if(i == 2)
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, FLOAT_R32, w, h, 0, GL_RGBA, GL_FLOAT, NULL);
}

//add a pass that uses GL_MIN to blend equation, store in texture, now use it as the end all
//stopping point in the "init" pass. gooooood

//background fbo
fbos[0] = new FrameBuffer();
fbos[0]->attach_texture(fbo_textures[0], GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB);

//depth pass fbo
fbos[1] = new FrameBuffer();
fbos[1]->attach_texture(fbo_textures[3], GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB);

//weighted average shader target fbo
fbos[2] = new FrameBuffer();
fbos[2]->attach_texture(fbo_textures[1], GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB);
fbos[2]->attach_texture(fbo_textures[2], GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB);


draw code


for(int f = 0; f < 3; f++)
{
glLoadIdentity();
fbos[f]->bind();

//depth pass
if(f == 1)
{
glBlendEquationEXT(GL_MIN_EXT);
glEnable(GL_BLEND);
use_depth_rec_shader();
glClearColor(1, 1, 1, 1);
}
if(f == 2)
{
const GLenum drawbuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers(2, drawbuffers);
glBlendEquationEXT(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);

glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fbo_textures[3]);

//use_wavg_init_shader();
glClearColor(0, 0, 0, 0);
}

fbos[f]->clear(GL_COLOR_BUFFER_BIT);
draw_3d(false, i, fbos[f]);
fbos[f]->unbind();

glUseProgram(0);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
}
glDrawBuffer(GL_BACK);
}


depth shader


//vert
void main(void)
{
gl_FrontColor = gl_FrontMaterial.diffuse;
gl_Position = ftransform();
}
//frag
void main()
{
if(gl_Color.a >= 1.0)
gl_FragColor = vec4(0, 0, 0, gl_FragCoord.z+0.0005);
else
gl_FragColor = vec4(0, 0, 0, 1.0);
}


rendering fragment shader


uniform sampler2DRect DepthTex;

vec4 ShadeFragment();

void main()
{
//my little depth test
if(gl_FragCoord.z > texture2DRect(DepthTex, gl_FragCoord.xy).a)
{
//gl_FragData[0] = vec4(0.0);
//gl_FragData[1] = vec4(0.0);
discard;
}
else
{
vec4 color = ShadeFragment();
gl_FragData[0] = vec4(color.rgb * color.a, color.a);
gl_FragData[1] = vec4(1.0);
}
}


The ugly result: http://i633.photobucket.com/albums/uu58/ltsword/Screenshot2009-11-14at40159PM1.png

mlfarrell
11-14-2009, 06:33 PM
Nevermind I got it. Turns out the color loses some precision during the interpolation, so I needed to add a fuzz factor to my test for opaque surfaces ie (gl_color.a >= 0.95)

This method is actually works out really well. You get the advantage of efficient order independent transparency + opaque surfaces without sorting in just two rendering passes, three if you need a background.