performance - 快速从深度缓冲区读取值

标签 performance opengl glsl depth

我正在使用 GLSL 在 OpenGL (3.X) 中实现“景深”。 它工作得很好,中心深度被着色器(纹理(tex1,vec2(0.5)))占据以自动对焦。但使用这样的实现焦点会立即发生。他应该像眼睛一样——逐渐适应。为此,我需要 CPU 内存侧面中间的深度。 我知道如何使用 PBO,用它来读取像素/像素颜色工作得非常快(异步运行),但是将 GL_RGB 更改为 GL_DEPTH_COMPONENT 性能急剧下降。你知道有什么方法可以比较快地读出中心深度是什么颜色吗?

    glReadPixels(a/2, b/2, 1, 1, GL_RGB , GL_BYTE, 0); // WORKS FINE - 30 ns
    glReadPixels(a/2, b/2, 1, 1, GL_DEPTH_COMPONENT, GL_BYTE, 0); // WORKS SLOOOW - around 3500 microseconds
    glReadPixels(a/2, b/2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, 0); // WORKS SLOOOW- around 3500 microseconds

@编辑: 创建的 FBO 纹理:

glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT32F , sett.framebuffer_width,  sett.framebuffer_height, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);

下载深度:

index = (index + 1) % 2;// for ping-pong PBO
nextIndex = (index + 1) % 2;// for ping-pong PBO
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);
glReadPixels(w/2, h/2, 1, 1, GL_DEPTH_COMPONENT , GL_FLOAT, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);

将深度复制到内存:

GLfloat tabc[10];
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);
GLfloat* srccccc = (GLfloat*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
tabc[0]=*srccccc;
std::cout<<"Depth center: "<<tabc[0]<<std::endl;//only to check is that correct
glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);     

它现在正在工作,速度更快(从 3500 微秒缩短到 357 微秒)。 现在好不好?所有格式?

最佳答案

glReadPixels(a/2, b/2, 1, 1, GL_DEPTH_COMPONENT, GL_BYTE, 0); // WORKS SLOOOW - around 3500 ns
glReadPixels(a/2, b/2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, 0); // WORKS SLOOOW- around 3500 ns

当然他们很慢。一般来说,深度缓冲区既不是 8 位字节,也不是 32 位浮点值。您对颜色的回读之所以能够快速发挥作用,是因为您的 pixel transfer format and type匹配你的帧缓冲区。而且由于您在读回中非常明智地使用 PBO,因此必须对值进行基于 CPU 的转换将会降低您的性能。

因此您需要在这里做同样的事情:将像素传输参数与帧缓冲区图像相匹配。

如果您正在从 FBO 读取数据,那么您应该知道图像的确切位深度(您正在使用 sized internal formats ,对吗?)。所以只需匹配即可:

GL_DEPTH_COMPONENT16  -> GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT
GL_DEPTH_COMPONENT32  -> GL_DEPTH_COMPONENT, GL_UNSIGNED_INT
GL_DEPTH_COMPONENT32F -> GL_DEPTH_COMPONENT, GL_FLOAT

还有一种纯粹的深度缓冲区格式:GL_DEPTH_COMPONENT24。您可能只需使用 GL_UNSIGNED_INT 即可,但 OpenGL 在写入数据时很可能必须将数据扩展为 32 位。

这就是您应该使用 GL_DEPTH24_STENCIL8 的原因之一。对于这一点,您可以这样做:

GL_DEPTH24_STENCIL8 -> GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8

当您需要深度值时,您必须将每个 32 位值右移 8 位并屏蔽掉前 8 位。但它应该可以工作。

如果您正在阅读 default framebuffer ,这有点棘手。很有可能,当您设置渲染上下文时,您告诉 OpenGL 您想要帧缓冲区中的位深度。但你可能还没有得到它们,所以你需要询问。

为此,您需要 employ glGetFramebufferAttachmentParameter 。这样,您就可以从 GL_DEPTH 附件查询 GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE​,并从 GL_STENCIL 附件查询 GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE​。对这两者进行测试非常重要;如果您同时拥有深度和模板位,则需要使用深度/模板读取。

一旦获得位深度,就假设它们是上述内部格式之一并正常进行。

关于performance - 快速从深度缓冲区读取值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18006299/

相关文章:

performance - 有没有办法降低 O(n^2) 的时间复杂度?

asp.net-mvc - SignalR 似乎减慢了我的 MVC/Azure 应用程序的启动速度

java - 通过 Java Web 应用程序从查询中下载非常大的结果

objective-c - 不使用 Interface Builder 创建 OpenGL View

opengl - GLSL 统一仅由不相关的调用更新

opengl - 大于窗口大小的渲染缓冲区 - OpenGL

c++ - OpenGL 投影/矩阵混淆

c# - LockBits 性能关键代码

glsl - 着色器帧缓冲区回读

c++ - 延迟渲染 Skybox OpenGL