Qt:glClear 不适用于 OpenGL 上的过度绘制

Qt: glClear does not work with overpainting on OpenGL

问题

glClear之后创建QPainter时,后者无效。

描述

我使用 Qt 5.7.1。我在 Linux 上使用 gcc,在 Windows.

上使用 vc++ 得到相同的结果

我在派生自 QGLWidget 的小部件中有以下内容:

void CanvasWidget::initializeGL()
{
    qglClearColor(m_backgroundColor);
}

V1:

void CanvasWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    QPainter painter(this);
    painter.drawLine(0, 0, 1000, 1000);
}

产生:

V2:

void CanvasWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
}

产生:

我想要的是:

这可以通过 hack 来完成:

void CanvasWidget::paintGL()
{
    QPainter painter(this);
    qglClearColor(m_backgroundColor);
    glClear(GL_COLOR_BUFFER_BIT);
    painter.drawLine(0, 0, 1000, 1000);
}

问题

这是怎么回事?为什么 glCleanQPainter 不能一起工作?为什么我不能用V1获取它?

最小可重现示例

main.cpp

#include "MainWindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow mainwindow;
    mainwindow.show();
    return app.exec();
}

MainWindow.h

#pragma once

#include "CanvasWidget.h"
#include <QMainWindow>
#include <memory>

class MainWindow : public QMainWindow
{
public:
    explicit MainWindow(QWidget *parent = 0);

    MainWindow(const MainWindow &) = delete;
    MainWindow & operator= (const MainWindow &) = delete;
    virtual ~MainWindow() = default;

private:
    std::unique_ptr<CanvasWidget> m_canvasWidget;
};

MainWindow.cpp

#include "MainWindow.h"
#include <QHBoxLayout>

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , m_canvasWidget(new CanvasWidget(parent))
{
    setCentralWidget(m_canvasWidget.get());
}

CanvasWidget.h

#pragma once

#include <QGLWidget>

class CanvasWidget : public QGLWidget
{
    Q_OBJECT
public:
    CanvasWidget(QWidget* parent = 0, const QGLWidget* shareWidget = 0, Qt::WindowFlags f = 0);
private:
    virtual void initializeGL() override;
    virtual void paintGL() override;
private:
    QColor m_backgroundColor;
};

CanvasWidget.cpp

#include "CanvasWidget.h"
#include <QMessageBox>
#include <QWheelEvent>

CanvasWidget::CanvasWidget(
    QWidget* parent /*= 0*/,
    const QGLWidget* shareWidget /*= 0*/,
    Qt::WindowFlags f /*= 0 */)
    : QGLWidget(parent, shareWidget, f)
    , m_backgroundColor(0, 93, 196)
{}

void CanvasWidget::initializeGL()
{
    qglClearColor(m_backgroundColor);
}

void CanvasWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    QPainter painter(this);
    painter.drawLine(0, 0, 1000, 1000);
}

Qt tutorial中关于使用 QPainter 覆盖 OpenGL 的内容是这样说的:

When overpainting 2D content onto 3D content, we need to use a QPainter and make OpenGL calls to achieve the desired effect. Since QPainter itself uses OpenGL calls when used on a QGLWidget subclass, we need to preserve the state of various OpenGL stacks when we perform our own calls

因此,查看您在 V1 中的代码,我假设 QPainter 设置了自己的清晰颜色状态,如果您没有明确设置 glClearColor,您将获得 QPainter 对象设置的内容。 我还建议您使用 RenderDoc or gDebugger 之类的工具来跟踪您应用程序的 GL 命令,以准确了解幕后情况。

CanvasWidget 构造函数中添加 setAutoFillBackground(false) 解决了问题。

所有功劳归于@G.M。