Depth buffer emulation

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:

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.