将深度缓冲区提取到数组

Posted

技术标签:

【中文标题】将深度缓冲区提取到数组【英文标题】:Extracting depth buffer to array 【发布时间】:2013-09-12 13:14:38 【问题描述】:

我正在尝试将深度缓冲区从 OpenGL 提取到 CPU 上的数组中。

我在下面的代码(稍微修改为原始代码是一个旨在提取渲染图像并成功提取的现有组件)“有效”,但总是返回正好 0。

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
int size = w*h*sizeof(GLubyte);
glBufferData(GL_PIXEL_PACK_BUFFER, size, NULL, GL_STREAM_READ);
glReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
GLubyte* depth = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
return depth;

我在glBindBuffer 调用之后尝试了glReadBuffer(GL_DEPTH),以及使用GL_DEPTH_COMPONENT24(每个资源都推荐但似乎没有人解释原因),但两者都会产生无效的枚举错误。 GL_DEPTH_TEST 已启用,并且没有生成错误。

【问题讨论】:

第一件事让我跳出来,这可能是因为你正在将深度缓冲区作为一个字节读取,这应该导致所有字节为 0 或 1;如果您的场景中没有任何内容处于饱和深度值,您可能只会看到零,除非您将其读取为 GL_FLOAT。只是一个想法。 GL_FLOAT 产生了类似的结果,但一切都是白色的。更改为使用 GL_INT (并将深度值右移 8,我在另一个源中读取是必要的,否则图像完全是灰色的),它正在提取深度缓冲区,但有些东西搞砸了。该图像显示了四个子图像,这些子图像显然是深度图,每个子图像的大小为 1/4(因此底部的 3/4 为纯灰色),但有变化,几乎就像字节以某种方式交错一样。 glReadBuffer() 不接受GL_DEPTH 【参考方案1】:

确保你有一个深度缓冲区:

#include <GL/glew.h>
#include <GL/glut.h>

GLuint pbo = 0;
void display()

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glEnable( GL_DEPTH_TEST );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho( -2, 2, -2, 2, -1, 1 );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glColor3ub( 255, 0, 0 );
    glBegin( GL_QUADS );
    glVertex3i( -1, -1, 0 );
    glVertex3i(  1, -1, 0 );
    glVertex3i(  1,  1, 0 );
    glVertex3i( -1,  1, 0 );
    glEnd();

    int w = glutGet( GLUT_WINDOW_WIDTH );
    int h = glutGet( GLUT_WINDOW_HEIGHT );
    glBindBuffer( GL_PIXEL_PACK_BUFFER, pbo );
    glBufferData( GL_PIXEL_PACK_BUFFER, w * h * sizeof( GLfloat ), 0, GL_STREAM_READ );
    glReadPixels( 0, 0, w, h, GL_DEPTH_COMPONENT, GL_FLOAT, 0 );
    GLfloat* ptr = (GLfloat*)glMapBuffer( GL_PIXEL_PACK_BUFFER, GL_READ_ONLY );
    if( ptr )
    
        // look for values of ~0.5 here in ptr...
    
    glUnmapBuffer( GL_PIXEL_PACK_BUFFER );
    glBindBuffer( GL_PIXEL_PACK_BUFFER, 0 );

    glutSwapBuffers();


int main( int argc, char **argv )

    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
    glutInitWindowSize( 128, 128 );
    glutCreateWindow( "GLUT" );
    glewInit();

    glGenBuffers( 1, &pbo );

    glutDisplayFunc( display );
    glutMainLoop();
    return 0;

【讨论】:

深度缓冲区已启用。使用 GL_FLOAT 会产生所有 1.0。使用 GL_INT 我得到一个图像,尽管深度值通过不同的深度从黑色到白色多次缩放(即,沿深度轴缩放的对象在最接近时从黑色开始,继续通过灰色到白色,然后跳回黑色并重复) .上面评论中描述的 1/4 大小问题原来是图像结构的问题。除了使用 GL_INT 而不是 GL_FLOAT(并且没有 GLUT)之外,我的 gl 代码和你的一样。 我能想到的效果最好的描述是“Beetlejuicing”,它对近剪裁平面(更远的平面 -> 更多重复的黑白渐变)高度敏感。 @MikeBarriault:听起来您正在尝试将其表示为 RGB 位平面图像,而没有任何适当的步骤。您应该做的是将每个像素(整个 32 位?整数)除以 INT_MAX,然后乘以 255,然后将此值分配给 R、G 和 B,如果您想将其可视化为彩色图像。基本上,您正在处理定点标准化。 @MikeBarriault:不过,这是描述这种现象的一种非常有趣的方式。我必须记住这一点:)

以上是关于将深度缓冲区提取到数组的主要内容,如果未能解决你的问题,请参考以下文章

如何从 ByteBuffer 中提取使用过的字节数组?

使用帧缓冲区将深度缓冲区渲染到纹理中

(阴影贴图)将深度缓冲区渲染到纹理并绘制它以检查它

OpenGL(FBO)中的普通后台缓冲区+渲染到深度纹理

如何将已经读过的文章提取到 gnus 的摘要缓冲区中?

将固定字节从输入流存储到字节数组中