从深度缓冲区中读取深度值的高效方法

7
为了我的一个算法,我需要能够访问深度缓冲区。使用glReadPixels完全没有问题,但读取800x600的窗口非常慢(从300 fps到20 fps)。
我正在阅读很多关于这个的内容,我认为将深度缓冲区转储到纹理中会更快。我知道如何创建纹理,但是如何获取深度呢?
从那里创建FBO并创建纹理可能会更快,目前我正在使用FBO(但仍与glReadPixels结合使用)。
那么最快的方法是什么?
(我可能无法使用GLSL,因为我对它一无所知,而且我没有时间去学习,期限!)
编辑: PBO可以吗?如此描述:http://www.songho.ca/opengl/gl_pbo.html它可以更快,但我不能像示例中那样经常更改缓冲区。
第二次编辑: 我该如何将深度数据放入PBO中?目前我执行以下操作:
glGenBuffersARB(1, &pboId);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboId);
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, 800*600*sizeof(GLfloat),0,     GL_STREAM_READ_ARB);

在我的readpixels之前,我再次调用glBindbuffer。结果是我什么都没读到。如果我禁用PBO,一切正常。

最终编辑: 我想我解决了这个问题,我必须使用:

glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboId);
glReadPixels( 0, 0,Engine::fWidth, Engine::fHeight, GL_DEPTH_COMPONENT,GL_FLOAT, BUFFER_OFFSET(0));

GLuint *pixels = (GLuint*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);

这使我的FPS提高了20。虽然不是很多,但还是有点效果的。

所以,我使用了2个PBO,但仍然遇到一个问题:我的代码只被执行了一次。

glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);  
std::cout << "Reading pixels" << std::endl;
glReadPixels( 0, 0,Engine::fWidth, Engine::fHeight, GL_DEPTH_COMPONENT,GL_FLOAT, BUFFER_OFFSET(0));
std::cout << "Getting pixels" << std::endl;
//  glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, 800*600*sizeof(GLfloat), 0, GL_STREAM_DRAW_ARB);
GLfloat *pixels = (GLfloat*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
int count = 0;
for(int i = 0; i != 800*600; ++i){
    std::cout << pixels[i] << std::endl;
}

最后一行只执行一次,之后它会继续调用该方法(这是正常的),但在调用pixels时停止。

我显然忘记了加载glUnMapBuffers,这有点解决了问题,但我的帧率又变慢了..


我决定尝试使用FBO,但是我遇到了一个问题:初始化FBO:

glGenFramebuffersEXT(1, framebuffers);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffers[0]);
std::cout << "framebuffer generated, id: " << framebuffers[0] << std::endl;
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

glGenRenderbuffersEXT(1,renderbuffers);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffers[0]);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 800, 600);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, renderbuffers[0]);
bool status = checkFramebufferStatus();
    if(!status)
        std::cout << "Could not initialise FBO" << std::endl;
    else
        std::cout << "FBO ready!" << std::endl;

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

我的绘图循环:

GLenum 错误代码; const GLubyte *错误字符串;

if ((errCode = glGetError()) != GL_NO_ERROR) {
    errString = gluErrorString(errCode);
   fprintf (stderr, "OpenGL Error: %s\n", errString);
}

++frameCount;
// -----------  First pass to fill the depth buffer  -------------------
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffers[0]);

std::cout << "FBO bound" << std::endl;
//Enable depth testing
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDepthMask( GL_TRUE );
//Disable stencil test, we don't need that for this pass
glClearStencil(0);
glEnable(GL_STENCIL_TEST);

//Disable drawing to the color buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

//We clear all buffers and reset the modelview matrix
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity();

//We set our viewpoint
gluLookAt(eyePoint[0],eyePoint[1], eyePoint[2], 0.0,0.0,0.0,0.0,1.0,0.0);
//std::cout << angle << std::endl;
std::cout << "Writing to FBO depth" << std::endl;
//Draw the VBO's, this does not draw anything to the screen, we are just filling the depth buffer
glDrawElements(GL_TRIANGLES, 120, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

在此之后,我调用一个调用glReadPixels()的函数。但是该函数甚至没有被调用。循环重新从函数调用开始。
显然我也解决了这个问题:我必须使用


glReadPixels( 0, 0,Engine::fWidth, Engine::fHeight, GL_DEPTH_COMPONENT,GL_UNSIGNED_SHORT, pixels);

使用GL_UNSIGNED_SHORT代替GL_FLOAT(或其他任何格式)


1
你是否制作了两个PBO并在它们之间交替使用? - Andreas Brinck
嗯,这是个好主意,我会去看看的。 - Kevin
我仍然有问题,请看我的编辑。 - Kevin
切换到FBO并不能带来任何好处,当你调用glReadPixels时驱动程序仍然会停止。使用异步PBO的原因是这使得驱动程序能够立即从glReadPixels返回。 - Andreas Brinck
但是在读取时我需要做些什么,不是吗?我的意思是,我正在使用2个PBO。实际上,当使用FBO时,我有4个fps更多。可能是我使用PBO的方式不对,但我没有找到任何指向那个方向的信息。我看了一下你的链接,并按照那种方式实现了它。 - Kevin
显示剩余2条评论
2个回答

4

啊,我修改的时候没有看到你的回复,我马上尝试这个! - Kevin
好的,你是对的。第一次我使用了2个PBO,但实际上我并没有执行任何异步操作,因此我没有获得任何速度优势。现在我做到了,达到了惊人的20fps。虽然仍然很慢,但已经有所改善。使用更多的PBO,会进一步增加吗? - Kevin
你可以试一试,我会建议你去尝试看看。 - Andreas Brinck
嗯,好的,我尝试了四个,看起来速度有点慢(用GLUT测量),所以我会保持在两个。谢谢你的帮助!(实际上,在删除一些调试输出后,我得到了30+ FPS) - Kevin

1

我会渲染到FBO并在帧渲染完成后读取其深度缓冲区。PBO已经过时了。


那应该比从默认缓冲区中读取更快吧?不管怎样,我会尝试一下的! - Kevin
我似乎遇到了一个问题,我初始化了我的FBO,没有报错,我绑定了我的FBO,我将深度写入其中,但是glreadpixels不起作用。它没有被调用。 - Kevin
你是错误的。PBO和FBO是正交概念,如果您不使用异步PBO,当您调用glReadPixels时,您的图形驱动程序将停止,直到帧已通过总线传输为止。 - Andreas Brinck
我所说的不是pbuffers,而是像素缓冲对象。请参考http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt。 - Andreas Brinck
没问题,这些名称确实令人困惑,“像素缓冲区”与“像素缓冲对象”。 - Andreas Brinck
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接