使用OpenGL渲染QImage

7

与我其他的问题有关,我认为更核心的问题是如何使用OpenGL渲染 QImage ?

我想代码应该像这样,但我不确定除了可能需要convertToGLFormat(img)之外还需要什么。

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

glGenTextures(1, &offscreenBufferTexture);
glBindTexture(GL_TEXTURE_2D, offscreenBufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgGL.width(),
         imgGL.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
         imgGL.bits());

glBegin(GL_QUADS);
  glTexCoord2d(0,0); glVertex2d(0, 0);
  glTexCoord2d(1,0); glVertex2d(windowSize.width(), 0);
  glTexCoord2d(1,1); glVertex2d(windowSize.width(), windowSize.height());
  glTexCoord2d(0,1); glVertex2d(0, windowSize.height());
glEnd();
glDisable(GL_TEXTURE_2D);

此外,我认为你可以使用glDrawPixels()(虽然不建议这样做)来快速且简单地完成操作,例如:
glDrawPixels(imgGL.width(), imgGL.height(), GL_RGBA,
         GL_UNSIGNED_BYTE, imgGL.bits());

但是无论如何,我都看不到这张图片,只有一个大小相同的白色正方形。我在这里缺少了某些东西。


你确认 imgGL 的格式与 GL_RGBA/GL_UNSIGNED_BYTE 相同吗? - cmannett85
是的,因为我从SoOffscreenRenderer缓冲区创建了QImage,它使用GL_UNSIGNED_BYTE,并且我可以设置它是否使用RGBRGBA。我尝试了两个版本,但无论哪种方式都无法显示。 - Dreiven
2个回答

4

我成功地使用OpenGL从图片源绘制了QImage,但无法像这里描述的那样SoOffscreenRenderer中绘制。

void init(){
    loadTexture2("kitten.png", backgroundimage);
}

QImage loadTexture2(char *filename, GLuint &textureID){
    glEnable(GL_TEXTURE_2D); // Enable texturing

    glGenTextures(1, &textureID); // Obtain an id for the texture
    glBindTexture(GL_TEXTURE_2D, textureID); // Set as the current texture

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

    QImage im(filename);
    QImage tex = QGLWidget::convertToGLFormat(im);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

    glDisable(GL_TEXTURE_2D);

    return tex;
}

void renderSceneGL2(){
    glClearColor(0.4f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, backgroundimage);

    glBegin(GL_QUADS);
        glTexCoord2f(0,0); glVertex3f(-1, -1, -1);
        glTexCoord2f(1,0); glVertex3f(1, -1, -1);
        glTexCoord2f(1,1); glVertex3f(1, 1, -1);
        glTexCoord2f(0,1); glVertex3f(-1, 1, -1);

    glEnd();

    glDisable(GL_TEXTURE_2D);
}

有时候,QGLWidget::convertToGLFormat 会随机抛出 Access violation 错误。


3
现如今,使用Qt 5.11,最简单的方法是使用QOpenGLWidget并重写其paintEvent方法。
在下面的代码中,OpenGLWidget继承自QOpenGLWidget,并且display(const QImage& img)是一个槽,在我需要更新图像时触发。
无论在两个OpenGL渲染之间调用display()多少次,update()调用不会直接触发渲染,它只是标记了widget需要重绘以在下一次循环时进行重新绘制。
这种方法实际上非常快速,我正在使用它以240fps显示相机帧(尽管并不是所有的帧都显示在屏幕上)。
void OpenGLWidget::display(const QImage& img)
{
  image = img;
  this->update();
}

void OpenGLWidget::paintEvent(QPaintEvent*)
{
  QPainter painter(this);
  painter.drawImage(this->rect(),image);
}

谢谢。如果我有一个视频墙,比如3x3,每个视频墙摄像头图像容器应该是QOpenGLWidget(现在它们是带有qlabels的qwidgets,运行非常缓慢)吗?或者,只需将墙本身设置为QOpenGLWidget?还是它们都必须是?我应该将主窗口也设置为QOpenGlWidget吗?我在哪里可以阅读关于这些主题(QOpenglWidget和QWidget之间的子级和父级)的内容?最好的问候!Mat. - hagor
呵呵,我不认为你想让我看movidious)。 - hagor
视频墙与QOpenGLWidget没有任何关系。您应该如何设置设备(所有部分只有一个OpenGL,或每个部分一个OpenGL窗口)取决于许多因素(首先是您的操作系统和显卡)。关于您的最后一个问题,您可以在此处找到Qt5文档:http://doc.qt.io/qt-5.11/。值得一读。 - antoine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接