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