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:渲染到纹理并显示回来的主要内容,如果未能解决你的问题,请参考以下文章