OpenGL:读取颜色缓冲区

Posted

技术标签:

【中文标题】OpenGL:读取颜色缓冲区【英文标题】:OpenGL : reading color buffer 【发布时间】:2018-12-30 17:26:47 【问题描述】:

我将 4 个颜色缓冲区附加到一个帧缓冲区并在每个缓冲区中进行渲染。每个颜色缓冲区都有窗口的大小。我正在尝试使用鼠标指针的坐标读取这些颜色缓冲区之一的像素颜色。

鼠标移动事件处理程序

void mouseMoveEvent(QMouseEvent *event)

    int x = event->pos().x();
    int y = event->pos().y();

    makeCurrent();
    glBindFramebuffer(GL_READ_FRAMEBUFFER, FBOIndex::GEOMETRY);
    
        // I save the values I'm interested in in the attachment GL_COLOR_ATTACHMENT3
        // but I always get 0 from any other attachment I try
        glReadBuffer(GL_COLOR_ATTACHMENT3);

        QVector<GLubyte> pixel(3);
        glReadPixels(x, geometry().height() - y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &(pixel[0]));

        QString PixelColor = QColor(pixel[0], pixel[1], pixel[2]).name();    
        qDebug() << PixelColor; // => always 0
    
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
    doneCurrent();

但是对于每个颜色缓冲区,我总是读取值 0。

颜色缓冲区在渲染阶段被正确写入,我通过显示它们所附加的纹理来测试它们中的每一个。我还测试了鼠标指针选择的像素读取到默认帧缓冲区,它工作正常。

我哪里错了? 谢谢!

编辑

看似奇怪的是,如果我使用“专用”帧缓冲区,我可以正确读取存储在纹理中的值。

void mouseMoveEvent(QMouseEvent *event)

    int x = event->pos().x();
    int y = event->pos().y();

    GLuint fbo;

    makeCurrent();
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    
        GLuint texture = textures[TextureIndex::COLOUR];
        glBindTexture(GL_TEXTURE_2D, texture);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

        QVector<GLubyte> pixel(3);
        glReadPixels(x, geometry().height() - y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &(pixel[0]));

        QString PixelColor = QColor(pixel[0], pixel[1], pixel[2]).name();
        qDebug() << PixelColor; // => correct value
    
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
    glDeleteFramebuffers(1, &fbo);
    doneCurrent();

但显然,当我已经拥有一个包含我需要的信息的帧缓冲区时,使用另一个帧缓冲区似乎没用。

我也尝试直接读取纹理的值(如@Spektre 建议的那样),但在这种情况下我总是得到 0。

void mouseMoveEvent(QMouseEvent *event)

    int x = event->pos().x();
    int y = event->pos().y();

    makeCurrent();
    
        GLuint texture = textures[TextureIndex::COLOUR];
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexSubImage2D(GL_TEXTURE_2D, 0, x, geometry().height() - y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &(pixel[0]));

        QString PixelColor = QColor(pixel[0], pixel[1], pixel[2]).name();
        qDebug() << PixelColor; // => always 0
    
    doneCurrent();

【问题讨论】:

您的附件作为纹理存储在 FBO 中,因此只需读取纹理,但请注意这在 IntelHD 上不起作用......另外,您错误地使用了 glReadPixels,请参阅depth buffer got by glReadPixels is always 1 @Spektre 谢谢你的评论!!如何使用鼠标光标的坐标直接读取 CPU 空间中的纹理?我阅读了您建议的讨论,但我不明白为什么我应该关心我的情况下的深度缓冲区。非常感谢您的帮助!! 1.该链接根本不使用 FBO。 glReadPixels 正在读取渲染缓冲区(在该链接中它的深度,但您可以使用您需要的任何其他缓冲区)并且您选择哪一个作为参数之一(您的代码缺少那个!!!这就是它不起作用的原因) 2. FBO 正在渲染到纹理中,所以在这种情况下,您需要使用 glGetTexImage(因为 glReadPixels 不会获取您想要的数据......)但是它会读取整个纹理以获得单点或子图像需要使用glGetTexSubImage ... 我刚刚看到了这个:opengl es 2.0 android c++ glGetTexImage alternative,所以看起来你也可以像你一样使用glReadPixels,但是你需要添加一些额外的调用,看看那里的代码来比较/修复你的。 .. opengl es 2.0 android c++ glGetTexImage alternative的可能重复 【参考方案1】:

我的方法是正确的,但我没有绑定到正确的帧缓冲区。

FBOIndex::GEOMETRY 是一个枚举值,我用它来索引一个 FBO 数组,我在其中存储所有帧缓冲区对象名称,因此通常它不是正确的帧缓冲区对象名称。

我定义了一个方法addFBO(index),它创建一个帧缓冲区并将其存储在FBOs 数组中的index 位置。该方法返回生成的帧缓冲区的帧缓冲区对象名称。如果在index 位置已经存在帧缓冲区,则该方法只返回关联的帧缓冲区对象名称。

所以,通过如下方式更改代码,我终于得到了想要的结果。

void mouseMoveEvent(QMouseEvent *event)

    int x = event->pos().x();
    int y = event->pos().y();

    makeCurrent();
    glBindFramebuffer(GL_READ_FRAMEBUFFER, addFBO(FBOIndex::GEOMETRY));
    
        glReadBuffer(GL_COLOR_ATTACHMENT3);

        QVector<GLubyte> pixel(3);
        glReadPixels(x, geometry().height() - y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &(pixel[0]));

        QString PixelColor = QColor(pixel[0], pixel[1], pixel[2]).name();    
        qDebug() << PixelColor; // => correct value
    
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
    doneCurrent();

【讨论】:

尽管如此,我仍然没有解决使用glTexSubImage2D 直接从纹理中读取值而不通过帧缓冲区的可能性。我找到了这个article,但我没有时间尝试。

以上是关于OpenGL:读取颜色缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL-载入纹理

从帧缓冲区对象读取时,OpenGL 纹理坐标是相反的

OpenGL 四 - 002OpenGL 图形渲染之颜色混合

OpenGL 帧缓冲区颜色附件到计算着色器

OpenGL 片段着色器未写入 fbo 颜色缓冲区

我可以设置 openGL 缓冲区以按照与 OBJ 文件类似的原理工作吗?