【问题标题】:Paint a rect on qglwidget at specifit times在特定时间在 qglwidget 上绘制一个矩形
【发布时间】:2017-07-14 01:35:42
【问题描述】:

我在 ubuntu 16.04 上使用 Qt 5.7 和 c++。我正在尝试实现一个继承 qglwidget 的类,它以给定的速率(3-10 Hz)将图像呈现到屏幕上。

除此之外,我还想在屏幕上的某处绘制一个小矩形,将其颜色从黑色变为白色,反之亦然。当图像出现时,它应该从白色切换到黑色,并在下一张图像出现之前的某个预定义时间切换回黑色。 现在我正在使用纹理来加载图像(来自 QImage 对象),使用

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

这是我的paintGL() 重载:

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
drawTexture(QRect(0,0,1,1),texture,GL_TEXTURE_2D);
swapBuffers();
glDisable(GL_TEXTURE_2D);

我想知道是否可以在小部件上绘制并使其同时呈现矩形和图像。我尝试过使用 QPainter,但一直绘制矩形使图像消失(矩形不应该在图像上,而是在小部件的某个角落,现在什么都没有绘制)。

不胜感激!

【问题讨论】:

  • 如果使用QPainter,它假定拥有对OpenGL状态的独占访问权。如果直接使用 OpenGL API,在调用QPainter-API 之前必须恢复某些状态。通过这种方式,我解决了在使用 OpenGL 渲染 3d 场景后使用 QPainter 渲染 HUD 的问题。
  • 您可能不应该调用swapBuffers();,因为这应该由QGLWidget 完成。 (我不得不查看我的源代码以提供有关此的更多详细信息。)
  • 您必须知道QOpenGLFunctions 方法的使用和调用GL 函数(来自任何非Qt 库)是不同的。这是可能的,特别是在文档中考虑。例如QGLWidgetClass。如果调用“非 Qt”OpenGL 函数,这可能会绕过 Qt 中的内部状态跟踪。
  • 您注意到我在答案末尾添加的关于GL_TEXTURE_MIN_FILTER 和GL_TEXTURE_MAG_FILTER 的提示了吗?

标签: c++ qt opengl rendering


【解决方案1】:

这是一个最小的示例应用程序,它在绘图处理程序中混合了 OpenGL 代码和 QPainter:

#include <QtWidgets>
#include <QOpenGLFunctions_1_1>

// manually added types (normally provided by glib)
typedef unsigned guint;
typedef unsigned char guint8;

extern const struct Image {
  guint      width;
  guint      height;
  guint      bytes_per_pixel; /* 3:RGB, 4:RGBA */
  guint8     pixel_data[1];
} fluffyCat;

class GLWidget: public QOpenGLWidget, protected QOpenGLFunctions_1_1 {
  private:
    float _step;
    GLuint _idTex;
    QTimer _qTimer;
  public:
    GLWidget(QWidget *parent = 0):
      QOpenGLWidget(parent),
      _step(0.0f), _idTex(0)
    {
      _qTimer.setInterval(100); // 100 ms -> 10 Hz
      QObject::connect(&_qTimer, &QTimer::timeout,
        this, &GLWidget::timeout);
    }
  protected:
    virtual void initializeGL();
    virtual void paintGL();
  private:
    void timeout();
};

void GLWidget::initializeGL()
{
  initializeOpenGLFunctions();
  glClearColor(0.525, 0.733f, 0.851, 1.0);
  glGenTextures(1, &_idTex);
  glBindTexture(GL_TEXTURE_2D, _idTex);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, fluffyCat.width, fluffyCat.height, 0,
    GL_RGB, GL_UNSIGNED_BYTE, fluffyCat.pixel_data);
  glBindTexture(GL_TEXTURE_2D, 0);
  _qTimer.start();
}

void GLWidget::paintGL()
{
  // prepare OpenGL rendering
  QPainter qPainter(this);
  qPainter.beginNativePainting();
  // do OpenGL rendering
  glColor3f(1.0f, 1.0f, 1.0f);
  bool tex2dOld = glIsEnabled(GL_TEXTURE_2D);
  glEnable(GL_TEXTURE_2D);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  static GLfloat envColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor);
  glBindTexture(GL_TEXTURE_2D, _idTex);
  float x = sin(_step) * 0.5f, y = cos(_step) * 0.5f;
#if 0 // does not work (no tex-coords)
  glRectf(x - 0.5f, y - 0.5f, x + 0.5f, y + 0.5f);
#else // (not) 0
  glBegin(GL_QUADS);
  glColor3f(1.0f, 1.0f, 1.0f);
  glTexCoord2i(0, 1);
  glVertex2f(x - 0.5f, y - 0.5f);
  glTexCoord2i(1, 1);
  glVertex2f(x + 0.5f, y - 0.5f);
  glTexCoord2i(1, 0);
  glVertex2f(x + 0.5f, y + 0.5f);
  glTexCoord2i(0, 0);
  glVertex2f(x - 0.5f, y + 0.5f);
  glEnd();
#endif // 0
  glBindTexture(GL_TEXTURE_2D, 0);
  //if (!tex2dOld) glDisable(GL_TEXTURE_2D);
  // prepare Qt painting
  qPainter.endNativePainting();
  // do Qt painting (HUD)
  QPen qPen;
  qPen.setWidth(1);
  qPen.setColor(QColor(Qt::black));
  qPen.setStyle(Qt::SolidLine);
  qPainter.resetMatrix();
  qPainter.setPen(qPen);
  qPainter.drawLine(0, 0, width(), height());
  qPainter.drawLine(0, height(), width(), 0);
}

void GLWidget::timeout()
{
  _step = fmod(_step + 0.1, 2 * 3.141);
  update(); // force redraw
}

int main(int argc, char **argv)
{
  QApplication app(argc, argv);
  QMainWindow win;
  GLWidget view3d;
  win.setCentralWidget(&view3d);
  win.show();
  return app.exec();
}

以及纹理图像的来源:

/* GIMP RGB C-Source image dump (fluffyCat.cc) */

// manually added types (normally provided by glib)
typedef unsigned guint;
typedef unsigned char guint8;

struct Image {
  guint      width;
  guint      height;
  guint      bytes_per_pixel; /* 3:RGB, 4:RGBA */ 
  guint8     pixel_data[16 * 16 * 3 + 1];
};
extern const Image fluffyCat;
const Image fluffyCat = {
  16, 16, 3,
  "x\211s\215\232\200gw`fx`at[cx^cw^fu\\itZerWn|ap~cv\204jnzedq^fr^kzfhv^Ra"
  "GRbMWdR\\jXer^qw_\311\256\226\271\253\235\275\264\252\315\277\260\304\255"
  "\231u~i\213\225\207l{fly`jx\\^nRlz_z\206nlx`t~i\221\211s\372\276\243\375"
  "\336\275\376\352\340\356\312\301\235\216\212judgwcl~f\212\226u}\206h\212"
  "\224q\231\237z\232\236{\216\225v\225\230\200\306\274\244\376\360\327\376"
  "\361\331\376\360\341\326\275\272\253\240\244{\203p\202\220xp~e{\204^\222"
  "\230n\212\217g\240\242{\234\236z\214\222r\270\271\247\360\353\340\376\370"
  "\336\376\363\334\375\357\336\310\254\262\232\223\234\\gRfrX\204\220z\212"
  "\225g\225\232j\254\255\177\252\250{\225\226u\304\302\265\374\365\351\376"
  "\375\366\376\367\341\376\361\320\374\346\324\306\241\242\237\232\235n{fj"
  "xckyfu~fUX@VZCfnT\231\231\207\374\374\371\377\372\354\376\376\374\376\376"
  "\372\376\362\332\375\340\301\341\300\264\260\253\262jvdbq\\XkVJTDNTCCG8O"
  "TE\322\321\313\377\377\375\376\376\373\376\377\376\376\376\375\376\374\362"
  "\376\360\342\344\311\306\250\244\254R_PL^HXkT<@2OP@`dP\217\220\177\374\374"
  "\370\377\377\374\376\375\371\377\377\376\376\374\360\377\367\336\376\350"
  "\316\342\303\274\246\236\245jtbXdQTdNQYGU\\KchV\317\315\302\377\376\372\377"
  "\376\367\376\373\360\377\376\367\376\366\337\376\355\312\374\331\271\323"
  "\263\251\216\214\214\\hTP^HL\\FR[LMXI^dW\355\352\342\376\375\366\377\374"
  "\360\376\374\361\376\374\361\376\356\321\374\331\264\374\330\266\330\270"
  "\260\200||Y`SLVE>K9BJ<CN?VYP\347\330\322\376\366\345\376\363\330\376\367"
  "\337\377\372\350\374\342\314\326\243\210\375\350\314\352\317\304shc^`TV`"
  "RVbT>B4IS?PTD\244\232\216\374\355\320\376\354\311\376\351\306\376\362\332"
  "\374\344\321\267\206u\375\362\337\326\274\272\\POMNBT]LNZH:<*<A*TV>OI;\242"
  "\222\207\340\304\243\375\335\262\372\336\272\376\361\334\320\241\212\374"
  "\352\322\266\233\237c\\WFH;MR>\\`F~xP\220\214[pqE\211\202\\g]=\230\214`\313"
  "\266\207\344\303\240\362\336\274\323\257\201\333\304\240\305\252\204\254"
  "\232p\216\206\\\206\203U\232\224b\234\244b\246\257m\220\232`\224\227h~\202"
  "W\206\213]\204\210W\227\227i|\177RvzNlsGrtJwtLz}N{\204RlxF",
};

(抱歉,图像质量低。本网站的高分辨率图片太大了。)

这两个文件必须编译并链接在一起。 (我没有使用标题,而是简单地(重新)在另一个文件开头的 fluffyCat.cc 中声明了变量。)

Qt项目文件testQGLWidgetHUD.pro:

SOURCES = testQGLWidgetHUD.cc fluffyCat.cc

QT += widgets opengl

顺便说一句,我没有意识到 OP 要求的是QGLWidget。该示例使用自 Qt5+ 以来推荐的新 QOpenGLWidget。

QTimer 用于非常简单的动画类型(表示已完成定期绘画)。

顺便说一句。我偶然发现了一个错误(这不是第一次袭击我......) 设置 GL_TEXTURE_MIN_FILTER 和 GL_TEXTURE_MAG_FILTER 很重要,因为这两个是罕见的 OpenGL 状态,如果保留默认值,它们将不起作用。

【讨论】:

  • 当我刚刚创建 Qpainter(使用 QPainter qPainter(this))时,它会覆盖我正在绘制的纹理,即使我没有调用任何其他绘画指令。任何想法为什么?整个代码块我也试过了,还是不行,只画对角线。
  • @JLev 我明确要求QOpenGLFunctions_1_1 像你一样使用OpenGL 1.1。默认的QOpenGLFunctions 不再提供glColor3f() 和glRectf()。 (在 OpenGL 3+ 中已弃用。)也许,您的 OpenGL 驱动程序不支持请求的 OpenGL 1.1 函数(尽管 - 这很难相信......)
  • @JLev 我试图记住如果QOpenGLFunctionsxx 无法绑定请求的OpenGL 函数会发生什么。我在 Qt QOpenGLFunctions doc 中找不到任何成功检索功能。我想,在这种情况下它只会崩溃。 (我曾经在合作者的 Windows 计算机上的驱动程序更新失败并退回到没有适当 OpenGL 支持的通用驱动程序时看到这种情况。关于 Linux 我不知道。)
  • 我尝试切换到 QopenGlwidget,但无法初始化 QOpenGLFunctions。我不需要它,你在哪里看到我在使用它?
  • QOpenGLFunctions 是 OpenGL API,它是 Qt 的一部分。 Qt 推荐使用它,但它不是必须的。在我们的(公司)项目中,我们从 QOpenGLFunctions 开始,但后来切换到自己的 OpenGL C 绑定,因为我们也想独立于 Qt 使用我们的 GL 渲染代码。它确实有效,但并非没有一些额外的努力。正如我已经说过的,如果 GL 状态发生变化,Qt 可能会在内部跟踪这些状态,如果在执行“非 Qt”OpenGL 渲染代码后未恢复这些状态,Qt 代码可能会崩溃。顺便提一句。 Qt 也可以对 2d 小部件使用 OpenGL 渲染(取决于配置)。
【解决方案2】:

好吧,最后这可以添加一个小矩形 -

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
QPainter qPainter(this);
QPainterPath path;
path.addRect(10, 10, 30,30);
QPen pen(Qt::black, 1);
qPainter.setPen(pen);
qPainter.fillPath(path, Qt::black);
qPainter.drawPath(path);
qPainter.end();
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glShadeModel( GL_FLAT );
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_TEXTURE_2D);
glColor3f(0.5, 0.5, 0);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.5f, -0.5f);  // vertex 1
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.5f, 0.5f); // vertex 2
glTexCoord2f(1.0f, 0.0f); glVertex2f(-0.5f, 0.5f); // vertex 3
glTexCoord2f(1.0f, 1.0f); glVertex2f(-0.5f, -0.5f); // vertex 4
glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);

【讨论】:

    猜你喜欢
    • 2015-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多