OpenGL + QT:渲染到纹理并显示回来

Posted

技术标签:

【中文标题】OpenGL + QT:渲染到纹理并显示回来【英文标题】:OpenGL + QT: render to texture and display it back 【发布时间】:2013-06-27 15:22:25 【问题描述】:

在遇到一些麻烦之后,我设法在 Qt 4.8 应用程序中正确渲染到帧缓冲区对象内的纹理:我可以使用 QGLWidget 打开 OpenGL 上下文,渲染到 FBO,并将其用作纹理。

现在我需要显示在 QPixmap 中渲染的纹理,并将其显示在 gui 的其他一些小部件中。但是..什么都没有显示。

这些是一些代码:

// generate texture, FBO, RBO in the initializeGL
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

// now in paintGL
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
// .... render into texture code ....
if(showTextureInWidget==false) 
    showTextureInWidget = true;
    char *pixels;
    pixels = new  char[TEXTURE_WIDTH * TEXTURE_HEIGHT * 4];
    glReadPixels(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
    QPixmap qp = QPixmap(pixels);
    QLabel *l = new QLabel();
    // /* TEST */ l->setText(QString::fromStdString("dudee"));
    l->setPixmap(qp);
    QWidget *d = new QWidget;
    l->setParent(d);
    d->show();

glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind
// now draw the scene with the rendered texture

我看到小部件打开了,但是.. 里面没有任何东西。如果我取消测试线..我看到“dudee”字符串,所以我知道有一个 qlabel 但是..没有来自 QPixmap 的图像。

我知道原始数据是“unsigned char”,我正在使用“char”,并且尝试了一些不同的颜色参数(“GL_RGBA”、“GL_RGB”等),但我不认为这是重点..重点是我什么都没看到..

有什么建议吗?如果我必须发布更多代码,我会这样做!

编辑:

我还没有发布所有代码,但我想明确的是纹理被正确渲染为立方体内的纹理。我只是无法将它从 gpu 放回 cpu 中

编辑 2:

感谢 peppe 的回答,我发现了问题:我需要一个 Qt 对象,它接受一些原始像素数据作为构造函数。这是完整的sn-p:

    uchar *pixels;
    pixels = new uchar[TEXTURE_WIDTH * TEXTURE_HEIGHT * 4];
    for(int i=0; i < (TEXTURE_WIDTH * TEXTURE_HEIGHT * 4) ; i++ ) 
        pixels[i] = 0;
    

    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    glReadPixels( 0,0,  TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    qi = QImage(pixels, TEXTURE_WIDTH, TEXTURE_HEIGHT, QImage::Format_ARGB32);
    qi = qi.rgbSwapped();

    QLabel *l = new QLabel();
    l->setPixmap(QPixmap::fromImage(qi));
    QWidget *d = new QWidget;
    l->setParent(d);
    d->show();

【问题讨论】:

您的代码显然不完整——例如,您没有为您的 FBO 设置任何颜色附件。此外,在使用 FBO 时,务必使用 glCheckFramebufferStatus 检查其完整性状态——任何错误 GL_FRAMEBUFFER_COMPLETE 都会告诉您您的 FBO 不可用。 是的,它在代码中,我只是没有复制它。当然,我正在使用glCheckFramebufferStatus 进行检查。我想明确的事实是渲染的纹理(作为立方体的纹理)被正确渲染 【参考方案1】:

鉴于这不是您的全部代码,并且 - 正如您所说 - 纹理已正确填充,那么这里发生了一个小错误:

glReadPixels(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
QPixmap qp = QPixmap(pixels);

QPixmap(const char *) ctor 需要 XPM 图像,而不是原始像素。您需要使用其中一个 QImage ctors 来创建有效的 QImage。 (您还可以将所有权传递给 QImage,解决您当前正在泄漏 pixels...)的事实

一旦你这样做了,你就会发现

    图像垂直翻转,因为 OpenGL 的原点位于左下角,向上/向右增长,而 Qt 假定原点在左上角,向下/向右增长;

    通道可能被交换 - 即 OpenGL 返回数据的字节顺序错误。我不记得在这种情况下是否使用 glPixelStorei(GL_PACK_SWAP_BYTES)GL_UNSIGNED_INT_8_8_8_8 作为类型可能会有所帮助,最终您需要求助于 CPU 端循环来修复您的像素数据:)

【讨论】:

以上是关于OpenGL + QT:渲染到纹理并显示回来的主要内容,如果未能解决你的问题,请参考以下文章

将 CIFilter 应用于 OpenGL 渲染到纹理

将纹理添加到 QT OpenGL 场景图

使用 Qt5 进行屏幕外渲染(openGL)

OpenGL ES 2.0 Framebuffer 渲染到纹理 iOS:没有显示

不断更新OpenGL窗口

OpenGL纹理渲染颠倒和模糊