How to get the z-buffer value for a given screen coordinate while using anti-aliasing?

Like the title says: How to get the z-buffer value for a given screen coordinate while using anti-aliasing (in P3D)?

The following function returns the z-buffer value for the given coordinate, but it only works after deactivating anti-aliasing (via noSmooth()):

public float getDepthValue(int scrX, int scrY) {
    PGL pgl = beginPGL();
    FloatBuffer depthBuffer = ByteBuffer.allocateDirect(1 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
    pgl.readPixels(scrX, height - scrY - 1, 1, 1, PGL.DEPTH_COMPONENT, PGL.FLOAT, depthBuffer);
    float depthValue = depthBuffer.get(0);
    depthBuffer.clear();
    endPGL();
    return depthValue;
}

I know, anti-aliasing locks the depth-buffer, but maybe there is a simple/fast workaround to this problem?

Thanks for any advice.

Answers

  • I believe the only way to read the contents of a multisampled framebuffer, including its depth-buffer, is by blitting it into a single-sampled framebuffer. In the Processing code, you can see how it is done in the FrameBuffer.copy() method:

    pgl.bindFramebuffer(PGL.READ_FRAMEBUFFER, this.glFbo);
    pgl.bindFramebuffer(PGL.DRAW_FRAMEBUFFER, dest.glFbo);
    pgl.blitFramebuffer(0, 0, this.width, this.height,
                                   0, 0, dest.width, dest.height, mask, PGL.NEAREST);
    pgl.bindFramebuffer(PGL.READ_FRAMEBUFFER, pg.getCurrentFB().glFbo);
    pgl.bindFramebuffer(PGL.DRAW_FRAMEBUFFER, pg.getCurrentFB().glFbo);
    

    You use the mask parameter to choose which buffer you want to read from (for example color, depth, stencil).

    But the problem here is that you would need the GL ID's for the source and destination framebuffers that Processing uses internally. I'm testing a couple of functions in PGraphicsOpenGL to allow libraries to retrieve the FB objects used during offscreen rendering, see this commit:

    https://github.com/processing/processing/commit/45632960a7495e37926b868e341296174e30ba70

    You could use these methods to grab a reference to the multisampled FB:

      FrameBuffer fb = ((PGraphicsOpenGL)pg).getFrameBuffer(true);
      int id = fb.glFbo;
    

    and then use GL functions to blit the data into your own FB. However, these functions are still being evaluated and might be removed later.

  • @codeanticode: Thanks for the reply! :)

    Copying the whole FBO to retrieve the depth value of one screen coordinate is kind of an overhead, but I guess you are right. This is most probably the fastest method to access a multisampled depth buffer, plus I would be able to reuse it for shader effects like DOF or SSAO.

  • Hi

    I'm trying to use the new methods created by Andres for a benchmark comparation with [shader solution] for z-buffer, (http://forum.processing.org/two/discussion/2530/creating-a-depth-of-field-shader-how-to-associate-depth-information-with-a-pgraphics-object/p1). I'm trying to copy the depth texture to FrameBuffer of second pgraphics, and rendering with no results, any help? thanks!!!

    PGraphics pg;
    PGraphics pgDepth;
    
    void setup() {
      size(800, 400, OPENGL);
    
      pg = createGraphics(400, 400, OPENGL);
      pg.smooth(4);
    
    
      pgDepth = createGraphics(400, 400, OPENGL);
      pgDepth.noSmooth();
      pgDepth.beginDraw();
      pgDepth.endDraw();
    }
    
    void draw() {
      background(0);
    
      pg.beginDraw();
      pg.background(255, 0, 0);
      pg.noStroke();
      pg.lights();
      pg.fill(150);
      for (int i = 0; i < 15; i++) {
        pg.translate(20, 20, -100);
        pg.sphere(50);
      }
      pg.endDraw();
    
      FrameBuffer fb = ((PGraphicsOpenGL) pg).getFrameBuffer(true);
      int id = fb.glFbo;
    
      FrameBuffer fbDepth = ((PGraphicsOpenGL) pgDepth).getFrameBuffer(false);
      int idDepth = fbDepth.glFbo;
    
      pgDepth.beginDraw();
      //  if (fb.hasDepthBuffer()) {
      //     fbDepth.bind();
      fb.copyDepth(fbDepth);
    
      PGL pgl = pgDepth.beginPGL();
    
      //pgl.drawBuffer(idDepth);
      pgDepth.endPGL();
      //}
    
      pgDepth.endDraw();
    
    
      image(pg, 0, 0, 400, 400);
      image(pgDepth, 400, 0, 400, 400);
    }
    
Sign In or Register to comment.