QOpenGLWindow 、QOpenGLWidget 和 QPainter混合渲染方法初探

该方法不存在普遍性。别按照此方法了


我用的是OpenGL 3.3 ,Qt 5.4.0

先说QWindow 和 QPainter 结合,这个Qt有现成的例子。就是 那个openglWindow那个例子。

这个基本直接照搬代码:

.h

#include 
#include 
#include 
#include 
class OpenGLWindow : public QWindow,protected QOpenGLFunctions_3_3_Core
{
    Q_OBJECT

public:
    OpenGLWindow(QWindow *parent = 0);
    ~OpenGLWindow();
    virtual void render();
    virtual void initialize();
public slots:
    void renderLater();
    void renderNow();

protected:
    bool event(QEvent *event) Q_DECL_OVERRIDE;

    void exposeEvent(QExposeEvent *event) Q_DECL_OVERRIDE;

private:
    bool m_update_pending;
    bool m_animating;

    QOpenGLContext *m_context;
    QOpenGLPaintDevice *m_device;
    QOpenGLBuffer * vbo;
    QOpenGLVertexArrayObject * vao;
    QOpenGLShaderProgram *m_program;
    QTimer * timer;
    float frame;

};

#endif // OPENGLWINDOW_H

.cpp

#include "openglwindow.h"
#include 
#include 
static const char *vertexShaderSource =
    "#version 330 core \n"
    "in vec4 posAttr;\n"
    "uniform mat4 matrix;\n"
    "void main() {\n"
    "   gl_Position = matrix * posAttr;\n"
    "}\n";

static const char *fragmentShaderSource =
    "#version 330 core \n"
    "out vec4 col;\n"
    "void main() {\n"
    "   col = vec4(1.0f,0.0f,0.0f,1.0f);\n"
    "}\n";
OpenGLWindow::OpenGLWindow(QWindow *parent)
    : QWindow(parent), m_update_pending(false)
    , m_context(0)
    , m_device(0)
{
    setSurfaceType(QWindow::OpenGLSurface);
    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    //format.setVersion(3,3);
    format.setProfile(QSurfaceFormat::CoreProfile);
    setFormat(format);
    timer = new QTimer;
    connect(timer,SIGNAL(timeout()),this,SLOT(renderNow()));
    timer->start(50);
    frame =0 ;
//    m_context = new QOpenGLContext;
//    m_context->setFormat(format);
//    m_context->create();
}

OpenGLWindow::~OpenGLWindow()
{

}
void OpenGLWindow::initialize()
{
    m_program = new QOpenGLShaderProgram(this);
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
    m_program->link();
}
void OpenGLWindow::render()
{
    m_program->bind();
    QMatrix4x4 matrix;
    matrix.perspective(60.0f, float(width())/float(height()), 0.1f, 100.0f);
    matrix.rotate(frame, 0, 1, 0);
    GLfloat vertices[] = {
        0.0f, 0.707f,-1.0f,1.0f,
        -0.5f, -0.5f,-1.0f,1.0f,
        0.5f, -0.5f,-1.0f,1.0f
    };

    glClearColor(0.5f,0.5f,0.5f,1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    QOpenGLVertexArrayObject vao;
    vao.create();
    vao.bind();

    QOpenGLBuffer vertex;
    vertex.create();
    vertex.bind();
    vertex .setUsagePattern(QOpenGLBuffer::StaticDraw);
    vertex.allocate(vertices,sizeof(vertices));
    m_program->enableAttributeArray(0);
    m_program->setAttributeBuffer(0,GL_FLOAT,0,4,0);

    m_program->setUniformValue("matrix",matrix);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    frame++;
}

void OpenGLWindow::renderLater()
{
    if (!m_update_pending) {
        m_update_pending = true;
        QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
    }
}
bool OpenGLWindow::event(QEvent *event)
{
    switch (event->type()) {
    case QEvent::UpdateRequest:
        m_update_pending = false;
        renderNow();
        return true;
    default:
        return QWindow::event(event);
    }
}
void OpenGLWindow::exposeEvent(QExposeEvent *event)
{
    Q_UNUSED(event);

    if (isExposed())
        renderNow();
}

void OpenGLWindow::renderNow()
{
    if (!isExposed())
        return;

    bool needsInitialize = false;

    if (!m_context) {
        m_context = new QOpenGLContext(this);
        m_context->setFormat(requestedFormat());
        m_context->create();

        needsInitialize = true;
    }

    m_context->makeCurrent(this);

    if (needsInitialize) {
        initializeOpenGLFunctions();
        initialize();
    }

    if (!m_device)
        m_device = new QOpenGLPaintDevice;
     m_device->setSize(size());
    QPainter painter(m_device);


    painter.beginNativePainting();
    render();
    painter.endNativePainting();
    QPen pen;
    pen.setColor(Qt::green);
    painter.setPen(pen);
    painter.setFont(QFont("微软雅黑"));
    painter.drawText(20,50,"frame:"+QString::number(frame));
    painter.drawEllipse(100,100,50,80);
    painter.end();
    m_context->swapBuffers(this);

    QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
}

QOpenGLWindow 、QOpenGLWidget 和 QPainter混合渲染方法初探_第1张图片


2 QOpenGLWidget 和 QOpenGLWindow


这个我原来按照一篇博客 叫“

Qt Weekly #20: Completing the offering: QOpenGLWindow and QRasterWindow

结果总是不成功,多方发帖询问未果。


后来自己研究了下,基本实现了混合渲染,但是有个缺点就是只能在OpenGL上面绘制图形。具体做法:


那个Qt博客中说,只要在虚函数paintGL()中写上QPainter,然后就可以混合渲染了,但是我按照他的做法没有成功过。我的做法是不再重写 paintGL(),而是重写paintEvent()。

原来的paintEvent()是会自动调用paintGL()的,重写以后的paintEvent如下代码:

void Render::paintEvent(QPaintEvent *e)
{
    makeCurrent();
    paintGL();
    QPainter pter(this);

    QImage pic;
    pic.load("../Select/timg.jpg");

    pter.setPen(Qt::blue);
    pter.drawText(20,50,"This is a Text!");


    pter.drawEllipse(80,100,40,50);
    pter.drawImage(200,40,pic);

    pter.end();
    update();

}

paintGL()中还是OpenGL代码。


其次还要注意的时,在类中构造函数中要设置好 format,我试着加入format的版本信息

format.setVersion(3,3);
format.setProfile(QSurfaceFormat::CoreProfile);

QOpenGLWindow 、QOpenGLWidget 和 QPainter混合渲染方法初探_第2张图片

但是这样会导致QPainter不起作用。我是在main函数中设置的全局format。


QOpenGLWindow 和 QOpenGLWidget 实现是一样的,就是继承的时候换一下就可以。具体代码在下面的连接可以下载。

我只是初步探索一下,肯定很多不足的地方,如果有更好的方法,记得分享呀。

QOpenGLWindow QPainter混合代码



你可能感兴趣的:(Opengl)