【问题标题】:Efficient way of reading depth values from depth buffer从深度缓冲区读取深度值的有效方法
【发布时间】:2011-08-23 17:17:01
【问题描述】:

对于我的算法,我需要能够访问深度缓冲区。我使用 glReadPixels 完全没有问题,但是读取 800x600 窗口非常慢(从 300 fps 到 20 fps)

我正在阅读很多关于此的内容,我认为将深度缓冲区转储到纹理会更快。我知道如何创建纹理,但如何获得深度?

创建 FBO 并从那里创建纹理可能会更快,目前我正在使用 FBO(但仍与 glReadPixels 结合使用)。

那么最快的方法是什么?

(我可能无法使用 GLSL,因为我对此一无所知,而且我没有太多时间学习,截止日期!)

编辑: PBO 会起作用吗?如此处所述:http://www.songho.ca/opengl/gl_pbo.html 它可以运行得更快,但我不能像示例中那样一直更改缓冲区。

编辑2: 我将如何将深度数据放入 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);

这让我提高了 20 FPS。这不是那么多,但它是一些东西。

所以,我使用了 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;
}

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


我显然忘记加载 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 *errString;

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(或任何其他格式)

【问题讨论】:

  • 你有没有做过两个交替的 PBO?
  • 嗯,这个主意,我去看看。
  • 我还是有问题,看我的编辑
  • 切换到 FBO 不会有任何收获,调用 glReadPixels 时驱动程序仍会停止。使用异步 PBO 的原因是,这使驱动程序能够立即从 glReadPixels 返回。
  • 但是我需要在它阅读的时候做点什么,不是吗?我的意思是,我正在使用 2 个 PBO。使用 FBO 时,我实际上多 4 fps。可能是我使用了 PBO 的错误,但我没有找到任何指向该方向的信息。我查看了您的链接并以这种方式实现了它。

标签: opengl


【解决方案1】:

最快的方法是使用异步像素缓冲区对象,这里有一个很好的解释:

http://www.songho.ca/opengl/gl_pbo.html

【讨论】:

  • 啊,我编辑的时候没有看到你的回复,我马上试试!
  • 好吧,你是对的。我第一次做 PBO 时使用了 2,但我实际上并没有做任何异步操作,因此我没有赢得任何速度。我现在做到了,惊人的20fps。它仍然很慢,但已经更好了。使用更多的 PBO,是否会增加更多?
  • 你可以,我试试看。
  • 嗯,好吧,我尝试了四个,但它似乎有点慢(fps 明智,用 GLUT 测量),所以我会保持在两个。谢谢你的帮助! (删除一些调试输出后,我实际上达到了 30+ FPS)
【解决方案2】:

我将渲染到 FBO 并在渲染帧后读取其深度缓冲区。 PBO 是过时的技术。

【讨论】:

  • 这应该比从默认缓冲区读取更快吗?无论如何我都会尝试的!
  • 我似乎遇到了问题,我初始化了我的 FBO,没有报告错误,我绑定了我的 fbo,我将我的深度写入它,但 glreadpixels 不起作用。它不会被调用。
  • 你错了。 PBO 和 FBO 是正交概念,如果您不使用异步 PBO,您的图形驱动程序将在您调用 glReadPixels 时停止,直到帧通过总线传输。
  • 如果渲染到 FBO,您可以随时读取其深度缓冲区 - 甚至在交换或刷新缓冲区之前。我一直在这样做,并且没有停顿(或者我的软粒子渲染器无法工作),因为您可以将深度缓冲区视为纹理。 PBO 处理起来很笨拙,而 FBO 可以替代它们。
  • 你在说什么,PBO和FBO是完全不同的东西,目的也不同。您是不是对 OP 有误解(您的软粒子评论表明这一点,您将深度缓冲区用作纹理,对吗?)他想将深度缓冲区从 GPU 转移到普通内存中。
猜你喜欢
  • 2013-08-03
  • 2020-07-13
  • 2011-02-05
  • 2018-06-19
  • 1970-01-01
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多