1. 程式人生 > >QOpenGLWindow 、QOpenGLWidget 和 QPainter混合渲染方法初探

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

該方法不存在普遍性。別按照此方法了

我用的是OpenGL 3.3 ,Qt 5.4.0

先說QWindow 和 QPainter 結合,這個Qt有現成的例子。就是 那個openglWindow那個例子。

這個基本直接照搬程式碼:

.h

#include <QSurfaceFormat>
#include <QOpenGLContext>
#include <QOpenGLShaderProgram>
#include <QTimer>
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 <QCoreApplication>
#include <QMatrix4x4>
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));
}


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


但是這樣會導致QPainter不起作用。我是在main函式中設定的全域性format。

QOpenGLWindow 和 QOpenGLWidget 實現是一樣的,就是繼承的時候換一下就可以。具體程式碼在下面的連線可以下載。

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

相關推薦

QOpenGLWindow QOpenGLWidget QPainter混合渲染方法初探

該方法不存在普遍性。別按照此方法了 我用的是OpenGL 3.3 ,Qt 5.4.0 先說QWindow 和 QPainter 結合,這個Qt有現成的例子。就是 那個openglWindow那個例子。 這個基本直接照搬程式碼: .h #include <QSurf

在Qt5.4中如何實現QOpenGLWidgetQPainter混合程式設計

在Qt5.4的Example中,有一個例子qopenglwidget,介紹了QOpenGLWidget和QPainter,但是在使用過程中,需要注意哪些方面呢?我在最初使用的時候就遇到兩者不能同時使用

setInterval()clearInterval()setTimeout()clearTimeout() js計數器方法

動作 strong 整數 code function tin 是個 style font 用法是會用,但是之前一直以為接函數的 var a = setInterval(function(){},1000) 比如a是函數名,最近才發現它是一個ID, var intervalI

Eclipse 插件安裝升級卸載的方法

文本文 選擇 pda 文本文件 conf 安裝插件 nag 是否 進入 Eclipse 的插件可以裝在內部,也可以裝在外部,裝在內部的方法很簡單:把插件的features和plugins目錄copy到eclipse的安裝目錄即可。 eclipse和其插件升級比較頻繁,用過e

python中hasattrgetattrsetattr的使用方法

hasattr(object, name)判斷一個物件裡面是否有name屬性或者name方法,返回BOOL值,有name特性返回True, 否則返回False。需要注意的是name要用括號括起來 1 >>> class test(): 2 ...

Android實現修改狀態列背景字型圖示顏色的方法

前言: Android開發,對於狀態列的修改,實在是不友好,沒什麼api可以用,不像ios那麼方便.但是ui又喜歡只搞ios一套.沒辦法.各種翻原始碼,寫反射.真的蛋疼. 需求場景: 當toolbar及狀態列需要為白色或淺色時(如簡書),狀態列由於用的Light風格Theme,字型,

openCV-影象ROI疊加線性混合

程式碼參考自《openCV3 程式設計入門》毛星雲,冷雪飛等編著 影象的線性混合可以通過改變引數使融合得更逼真。 1. 影象的ROI //【2】定義一個Mat型別並給其設定ROI區域 Mat i

CUDASUMPIMadagascar混合程式設計的Makefile檔案配置

本人從事地震勘探的科研工作,在Ubuntu系統中用CUDA、SU、MPI和Madagascar做C語言的混合程式設計。多語言混合程式設計,關鍵之處在於Makefile檔案的配置Makefile檔案的配置。在此給出一個簡單的示例,供大家參考。 Makefile檔案

C#:區分:重寫覆蓋過載以及虛方法抽象方法

(一)重寫和覆蓋: 重寫: 在宣告時,父類的方法前面加上virtual關鍵字,子類的方法前面加上override關鍵字,且與父類方法同名,表示父類的方法可以被子類進行修改和重新定義。 覆蓋: 在宣告子類方法的時候,新增new關鍵字,定義與父類同名的方法,

JSHTMLCSS的註釋方法及作用

JS的註釋: //:表示單行註釋   如: // alert(typeof ("176")); /* *xxxx *xxxx */:表示多行註釋   如: /* * 定義一個放大的

matlabc++混合程式設計---方法步驟

  摘要:Matlab具有很強的數值計算和分析等能力,而C/C++是目前最為流行的高階程式設計語言,兩者互補結合的混合程式設計在科學研究和工程實踐中具有非常重要的意義。從Matlab呼叫C/C++程式碼及C/C++呼叫m檔案兩方面,深入地研究了它們之間混合程式設計的原理和

基於SNMP協議發現網路中路由器交換機印表機的簡單方法

在網路拓撲發現中,如何發現裝置的型別。如果一個裝置支援SNMP,就按照下面的步驟進行:   路由器發現:    決定一個裝置是否是一個路由器,通過SNMP查詢改裝置中的MIB-II中的ipAddrEntry表,如果沒有返回,就可以初步認定該裝置不是路由器,繼續通過其他

PHP實現連線裝置通訊傳送命令的方法

/** * 採用php socket技術使用TCP/IP連線裝置 * @param string $service_port 連線埠 * @param string $address 傳送IP地址 * @param string $in 傳送命令 * @return

QOPenGLWidgetQPainter混合程式設計--繪製文字

前言:QOPenGLWidget取代了之前的QGLWidget類,用以在Qt中提供Opengl的程式設計介面。在QGLWidget類中,我們可以通過方法drawTexture來繪製文字。但是在QOPenGLWidget類的時候,這個方法沒有提供了。官方文件

JAVA學習(七):方法重載與方法重寫thiskeywordsuperkeyword

格式 hello new 初始 per 而且 方法重寫 學習 方式 方法重載與方法重寫、thiskeyword和superkeyword 1、方法重載 重載可以使具有同樣名稱但不同數目和類型參數的類傳遞給方法。 註: 一是重載方法的參數列表必須與被重載的方法不同

C++QML混合的QT程序調試方法

cti 卡死 xxx 按鈕 conn 應用 混合 簡單 config 以前調試只是QML或者只是C++的QT程序很簡單,斷點打上,直接debug按鈕一點,喝一口水,自然就停在斷點了。 這次遇到C++和QML混合的程序,把CONFIG+=declarative_debugCO

關於堆方法

內存 線程 包含 信息 執行 引用 基礎 -s 只有一個 JAVA的JVM的內存可分為3個區:堆(heap)、棧(stack)和方法區(method)   堆區:   1.存儲的全部是對象,每個對象都包含一個與之對應的class的信息。(class的目的是得到操作指令)

iOS開發核心語言Objective C —— 面向對象思維settergetter方法及點語法

才幹 各路 alt .net 行為 變量的作用域 fadein 格式 讀取 本分享是面向有意向從事iOS開發的夥伴們。或者已經從事了iOS的開發人員。假設您對iOS開發有極高的興趣,能夠與我一起探討iOS開發。一起學習,共同進步。假設您是零基礎,建議您先

python基礎之多態與多態性綁定方法非綁定方法

info lib img 感知 animal user save python基礎 assm 多態與多態性 多態 多態並不是一個新的知識 多態是指一類事物有多種形態,在類裏就是指一個抽象類有多個子類,因而多態的概念依賴於繼承 舉個栗子:動物有多種形態,人、狗、貓、豬等,py

SQL ServerOracleMySQL判斷NULL的方法

ron gin round exp style ref int 宋體 oat SQL Server、Oracle和MySQL判斷NULL的方法本文講述SQL Server、Oracle、MySQL查出值為NULL的替換。 在SQL Server Oracle MySQL當數