在QGLFramebufferObject纹理上绘制QPaint?

3

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

最终目标是使用QPainter将文本绘制到纹理上,然后将纹理与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();
}

自包含测试用例加一分! - Kuba hasn't forgotten Monica
2个回答

1

当离开initializeGL()时,QGLFramebufferObject实例被销毁,从而导致纹理也被删除。您需要保持QGLFramebufferObject的存在,直到不再需要该纹理。


好的,我在类定义中声明了QGLFramebufferObject,所以它会在initializeGL()之后持久存在。现在我得到了一个黑色方框。我添加了fbo->toImage(),然后将图像保存到png文件中。这个png是空白的。似乎QPainter和QGLFramebufferObject之间出了一些问题。 - user2757704
这是因为您有一个缓冲区绑定。GL绘图引擎不使用缓冲对象,因此将某些内容绑定到ARRAY_BUFFER绑定点会导致意外结果。在使用QPainter绘制FBO之前,请执行glBindBuffer(GL_ARRAY_BUFFER, 0)。 - Laszlo Agocs
在QPainter修复之前,确实需要使用glBindBuffer(GL_ARRAY_BUFFER, 0),谢谢。在Qt 5.2中,http://dangelog.wordpress.com/2013/02/10/using-fbos-instead-of-pbuffers-in-qt-5-2/建议使用QOpenGLFramebufferObject和QOpenGLPaintDevice代替QGLFramebufferObject。这是更好的选择吗? - user2757704
一般来说,迁移到更新、更现代的QOpenGL类是可取的,尽管您可能不会从现有代码中获得太多好处。 QGLFramebufferObject和QOpenGLFramebufferObject基本相同,只是QGL变体不再接收任何开发。 - Laszlo Agocs

0

这是已更正的代码。另外还有透明度混合。

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();
}

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