QPaint 到 QGLFramebufferObject 纹理上?

Posted

技术标签:

【中文标题】QPaint 到 QGLFramebufferObject 纹理上?【英文标题】:QPaint onto QGLFramebufferObject texture? 【发布时间】:2013-12-28 21:06:44 【问题描述】:

我正在尝试学习如何将 QPainter 与 QGLFramebufferObject 一起使用。当我尝试在 QGLWidget 中显示纹理时,它是不可见的。 (完整代码如下)

最终目标是使用 QPainter 将文本绘制到纹理上,然后 alpha 混合 2D 线几何上的纹理。

texture.pro

QT += core gui widgets opengl

TARGET = test
TEMPLATE = app

SOURCES = main.cpp
HEADERS = main.h

main.h

#include <QGLWidget>
#include <QGLFunctions>

class glview : public QGLWidget, protected QGLFunctions

    Q_OBJECT

public:
    explicit glview(QWidget *parent = 0);
    ~glview();
    QSize sizeHint() const;

protected:
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

private:
    quint32 vbo_id[2], texture_id;
;

main.cpp

#include <QApplication>
#include <QGLFramebufferObject>
#include <QPainter>
#include "main.h"

struct vrtx 
    GLint   x;
    GLint   y;
    GLubyte r;
    GLubyte g;
    GLubyte b;
__attribute__((packed)) line_geo[] = 
//   x, y,   r, g, b
    1, 1, 255, 0, 0,
    1, 2, 0, 255, 0,
    1, 2, 0, 255, 0,
    2, 2, 255, 0, 0,
    2, 2, 255, 0, 0,
    2, 1, 0, 255, 0,
    2, 1, 0, 255, 0,
    1, 1, 255, 0, 0,
;

struct txtr_vrtx 
    GLint   x;
    GLint   y;
    GLint   tx;
    GLint   ty;
__attribute__((packed)) txtr_geo[] = 
//   x, y, tx,ty
    3, 1, 0, 0,
    3, 2, 0, 1,
    4, 2, 1, 1,
    4, 1, 1, 0,
;

int main(int argc, char *argv[])

    QApplication app(argc, argv);
    glview widget;
    widget.show();
    return app.exec();


glview::glview(QWidget *parent) : QGLWidget(parent)




glview::~glview()




QSize glview::sizeHint() const

    return QSize(500, 300);


void glview::initializeGL()

    initializeGLFunctions();
    qglClearColor(Qt::white);

    glGenBuffers(2, vbo_id);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(line_geo), line_geo, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(txtr_geo), txtr_geo, GL_STATIC_DRAW);

    QGLFramebufferObject fbo(100, 100, QGLFramebufferObject::CombinedDepthStencil/*GL_TEXTURE_2D*/);
    fbo.bind();
    texture_id = fbo.texture();

    QPainter painter(&fbo);
    painter.fillRect(0, 0, 100, 100, Qt::blue);
    painter.end();

    fbo.release();


void glview::resizeGL(int w, int h)

    glViewport(0, 0, w, h);


void glview::paintGL()

    glClear(GL_COLOR_BUFFER_BIT);

    glLoadIdentity();
    glOrtho(0, 5, 0, 3, -1, 1);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    glVertexPointer(2, GL_INT, sizeof(struct vrtx), 0);
    glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(struct vrtx), ((char*)NULL + 8));
    glDrawArrays(GL_LINES, 0, sizeof(line_geo) / sizeof(struct vrtx));

    //glColor4ub(0, 0, 255, 255);
    //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_TEXTURE_2D);

    glDisableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1]);
    glBindTexture(GL_TEXTURE_2D, texture_id);

    glVertexPointer(2, GL_INT, sizeof(struct txtr_vrtx), 0);
    glTexCoordPointer(2, GL_INT, sizeof(struct txtr_vrtx), ((char*)NULL + 8));
    glDrawArrays(GL_QUADS, 0, 4);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);

    glDisable(GL_TEXTURE_2D);
    //glDisable(GL_BLEND);

    glFlush();

【问题讨论】:

独立测试用例+1! 【参考方案1】:

QGLFramebufferObject 实例在离开 initializeGL() 时被销毁。这也会导致删除纹理。在不再需要纹理之前,您需要保持 QGLFramebufferObject 处于活动状态。

【讨论】:

好的,我在类定义中声明了 QGLFramebufferObject,所以它会在 initializeGL() 之后持续存在。我现在得到一个黑匣子。我添加了一个 fbo->toImage() 然后将图像保存到 png 文件中。 png 是空白的。 QPainter 和 QGLFramebufferObject 之间似乎有问题。 那是因为你有一个缓冲区绑定。 GL 绘制引擎不使用缓冲区对象,因此将某些内容绑定到 ARRAY_BUFFER 绑定点会导致意外结果。在使用 QPainter 在 FBO 上绘画之前执行 glBindBuffer(GL_ARRAY_BUFFER, 0)。 是的,glBindBuffer(GL_ARRAY_BUFFER, 0) 在 QPainter 修复它之前,谢谢。在 Qt 5.2 中,dangelog.wordpress.com/2013/02/10/… 建议使用 QOpenGLFramebufferObject 和 QOpenGLPaintDevice 而不是 QGLFramebufferObject。这是更好的方法吗? 迁移到更新、更现代的 QOpenGL 类通常是可取的,尽管您可能不会从现有代码中获得太多收益。 QGLFramebufferObject 和 QOpenGLFramebufferObject 大致相同,只是 QGL 变体不再接受任何开发。【参考方案2】:

这是更正后的代码。还带有 alpha 弯曲。

main.h

#include <QGLWidget>
#include <QGLFunctions>
#include <QGLFramebufferObject>
#include <QFont>

class glview : public QGLWidget, protected QGLFunctions

    Q_OBJECT

public:
    explicit glview(QWidget *parent = 0);
    ~glview();
    QSize sizeHint() const;

protected:
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

private:
    QGLFramebufferObject *fbo;
    QFont font;
    quint32 vbo_id[2], texture_id;
;

main.cpp

#include <QApplication>
#include <QPainter>
#include "main.h"

struct vrtx 
    GLint   x;
    GLint   y;
    GLubyte r;
    GLubyte g;
    GLubyte b;
__attribute__((packed)) line_geo[] = 
//   x, y,   r, g, b
    1, 1, 255, 0, 0,
    1, 2, 0, 255, 0,
    1, 2, 0, 255, 0,
    2, 2, 255, 0, 0,
    2, 2, 255, 0, 0,
    2, 1, 0, 255, 0,
    2, 1, 0, 255, 0,
    1, 1, 255, 0, 0,
;

struct txtr_vrtx 
    GLint   x;
    GLint   y;
    GLint   tx;
    GLint   ty;
__attribute__((packed)) txtr_geo[] = 
//   x, y, tx,ty
    3, 1, 0, 0,
    3, 2, 0, 1,
    4, 2, 1, 1,
    4, 1, 1, 0,
;

int main(int argc, char *argv[])

    QApplication app(argc, argv);
    glview widget;
    widget.show();
    return app.exec();


glview::glview(QWidget *parent) : QGLWidget(parent)

    font.setFamily("Helvetica");


glview::~glview()

    delete fbo;


QSize glview::sizeHint() const

    return QSize(500, 300);


void glview::initializeGL()

    initializeGLFunctions();
    qglClearColor(Qt::white);

    glGenBuffers(2, vbo_id);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(line_geo), line_geo, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(txtr_geo), txtr_geo, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, 0);       // must unbind for QPainter

    fbo =  new QGLFramebufferObject(100, 100, GL_TEXTURE_2D);
    fbo->bind();
    texture_id = fbo->texture();

    QPainter painter(fbo);
    painter.setPen(Qt::blue);
    font.setPointSize(20);
    painter.setFont(font);
    painter.drawText(0, 60, "FBO");
    painter.end();

    fbo->release();


void glview::resizeGL(int w, int h)

    glViewport(0, 0, w, h);


void glview::paintGL()

    glClear(GL_COLOR_BUFFER_BIT);

    glLoadIdentity();
    glOrtho(0, 5, 0, 3, -1, 1);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    glVertexPointer(2, GL_INT, sizeof(struct vrtx), 0);
    glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(struct vrtx), ((char*)NULL + 8));
    glDrawArrays(GL_LINES, 0, sizeof(line_geo) / sizeof(struct vrtx));

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);

    glDisableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1]);
    glBindTexture(GL_TEXTURE_2D, texture_id);

    glVertexPointer(2, GL_INT, sizeof(struct txtr_vrtx), 0);
    glTexCoordPointer(2, GL_INT, sizeof(struct txtr_vrtx), ((char*)NULL + 8));
    glDrawArrays(GL_QUADS, 0, 4);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);

    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);

    glFlush();

【讨论】:

以上是关于QPaint 到 QGLFramebufferObject 纹理上?的主要内容,如果未能解决你的问题,请参考以下文章

有效地从 QPaintDevice 到 QQuickItem 中的 QSGTexture

派生QPainterPath,QPainter性能下降很快

QwtPolar 库错误 Qt Creator

如何销毁 QPainter 对象/摆脱 drawText() 内存泄漏?

在 Qt 中的小部件内部绘画

Qt实现的酷炫轮播图