一、OpenGL介紹
OpenGL是一個用來加速渲染顯示2D、3D 矢量圖形的編程接口。這個接口底層依賴于硬件GPU,底層硬件接口的驅動都是由GPU廠家提供。
openGl也支持跨平臺,windows、Linux、MAC 平臺都可以使用。
QT封裝有QOpenGLWidget可以更加方便的調用GPU 來渲染圖片。
下面例子代碼就介紹QOpenGLWidget類的使用說明,并編寫一個例子代碼,調用GPU加速渲染一張QImage加載的圖片。
二、QOpenGLWidget類介紹
下面是來至官方幫助的文檔的介紹,我這里做了簡單的調整,并翻譯了一下:
QOpenGLWidget類是一個用于呈現OpenGL圖形的小部件。
QOpenGLWidget提供了顯示集成到Qt應用程序中的OpenGL圖形的功能。它的使用非常簡單:使你的類繼承自它,并像任何其他QWidget一樣使用子類,但你可以選擇使用QPaint和標準OpenGL渲染命令。
QOpenGLWidget提供了三個方便的虛擬函數,你可以在子類中重新實現這些函數以執行典型的OpenGL任務:
paintGL()-渲染OpenGL場景。每當小部件需要更新時調用。
resizeGL()-設置OpenGL視口、投影等。每當小部件調整大小時(以及首次顯示時,因為所有新創建的小部件都會自動獲得調整大小事件),都會調用該小部件。
initializeGL()-設置OpenGL資源和狀態。在第一次調用resizeGL()或paintGL()之前調用一次。
如果需要從paintGL()以外的位置觸發重新繪制(典型示例是使用計時器設置場景動畫),則應調用小部件的update()函數來安排更新。
調用paintGL()、resizeGL()或initializeGL()時,小部件的OpenGL呈現上下文將變為當前。如果需要從其他位置(例如,在小部件的構造函數或自己的繪制函數中)調用標準OpenGL API函數,則必須首先調用makeCurrent()。
所有渲染都發生在OpenGL幀緩沖區對象中。makeCurrent()確保它在上下文中綁定。在paintGL()中的渲染代碼中創建和綁定其他幀緩沖區對象時,請記住這一點。永遠不要重新綁定ID為0的幀緩沖區。相反,調用defaultFramebufferObject()獲取應該綁定的ID。
QOpenGLWidget允許在平臺支持時使用不同的OpenGL版本和配置文件。只需通過setFormat()設置請求的格式。但是請記住,在同一窗口中有多個QOpenGLWidget實例需要它們都使用相同的格式,或者至少使用不會使上下文不可共享的格式。要解決此問題,請首選使用QSurfaceFormat::setDefaultFormat()而不是setFormat()。
注意:在某些平臺(例如macOS)上,當請求OpenGL核心概要文件上下文時,在構造QApplication實例之前調用QSurfaceFormat::setDefaultFormat()是必需的。這是為了確保上下文之間的資源共享保持功能,因為所有內部上下文都是使用正確的版本和概要文件創建的。
繪畫技巧
如上所述,子類QOpenGLWidget以以下方式呈現純3D內容:
重新實現initializeGL()和resizeGL()函數,以設置OpenGL狀態并提供透視轉換。
重新實現paintGL()以繪制3D場景,僅調用OpenGL函數。
還可以使用QPaint在QOpenGLWidget子類上繪制2D圖形:
在paintGL()中,不要發出OpenGL命令,而是構造一個QPainter對象以在小部件上使用。
使用QPaint的成員函數繪制基本體。仍然可以發出直接的OpenGL命令。但是,你必須確保調用畫家的BeginativePainting()和endNativePainting()來包含這些內容。
當僅使用QPaint執行繪制時,也可以像對普通小部件一樣執行繪制:通過重新實現paintEvent()。
重新實現paintEvent()函數。構造一個針對小部件的QPaint對象。將小部件傳遞給構造函數或QPaint::begin()函數。
使用QPaint的成員函數繪制基本體。繪制完成后,QPaint實例將被銷毀。或者,顯式調用QPaint::end()。

三、例子代碼
3.1 頭文件: 重載QOpenGLWidget
#ifndef MYGLWIDGET_H #define MYGLWIDGET_H #include #include #include #include #include #include #include #include #include class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: explicit MyGLWidget(QWidget *parent = 0); signals: public slots: void initializeGL() Q_DECL_OVERRIDE; void resizeGL(int w, int h) Q_DECL_OVERRIDE; void paintGL() Q_DECL_OVERRIDE; void setImage(const QImage &image); void initTextures(); void initShaders(); private: QVector vertices; QVector texCoords; QOpenGLShaderProgram program; QOpenGLTexture *texture; QMatrix4x4 projection; }; #endif // MYGLWIDGET_H
3.2 源文件:QOpenGLWidget
#include "myglwidget.h" #include #include MyGLWidget::MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { } void MyGLWidget::initTextures() { // 加載 Avengers.jpg 圖片 texture = new QOpenGLTexture(QOpenGLTexture::Target2D); texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); texture->setMagnificationFilter(QOpenGLTexture::Linear); //重復使用紋理坐標 //紋理坐標(1.1, 1.2)與(0.1, 0.2)相同 texture->setWrapMode(QOpenGLTexture::Repeat); //設置紋理大小 texture->setSize(this->width(), this->height()); //分配儲存空間 texture->allocateStorage(); } void MyGLWidget::initShaders() { //紋理坐標 texCoords.append(QVector2D(0, 1)); //左上 texCoords.append(QVector2D(1, 1)); //右上 texCoords.append(QVector2D(0, 0)); //左下 texCoords.append(QVector2D(1, 0)); //右下 //頂點坐標 vertices.append(QVector3D(-1, -1, 1));//左下 vertices.append(QVector3D(1, -1, 1)); //右下 vertices.append(QVector3D(-1, 1, 1)); //左上 vertices.append(QVector3D(1, 1, 1)); //右上 QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this); const char *vsrc = "attribute vec4 vertex;\n" "attribute vec2 texCoord;\n" "varying vec2 texc;\n" "void main(void)\n" "{\n" " gl_Position = vertex;\n" " texc = texCoord;\n" "}\n"; vshader->compileSourceCode(vsrc);//編譯頂點著色器代碼 QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this); const char *fsrc = "uniform sampler2D texture;\n" "varying vec2 texc;\n" "void main(void)\n" "{\n" " gl_FragColor = texture2D(texture,texc);\n" "}\n"; fshader->compileSourceCode(fsrc); //編譯紋理著色器代碼 program.addShader(vshader);//添加頂點著色器 program.addShader(fshader);//添加紋理碎片著色器 program.bindAttributeLocation("vertex", 0);//綁定頂點屬性位置 program.bindAttributeLocation("texCoord", 1);//綁定紋理屬性位置 // 鏈接著色器管道 if (!program.link()) close(); // 綁定著色器管道 if (!program.bind()) close(); } void MyGLWidget::initializeGL() { initializeOpenGLFunctions(); //初始化OPenGL功能函數 glClearColor(0, 0, 0, 0); //設置背景為黑色 glEnable(GL_TEXTURE_2D); //設置紋理2D功能可用 initTextures(); //初始化紋理設置 initShaders(); //初始化shaders } void MyGLWidget::resizeGL(int w, int h) { // 計算窗口橫縱比 qreal aspect = qreal(w) / qreal(h ? h : 1); // 設置近平面值 3.0, 遠平面值 7.0, 視場45度 const qreal zNear = 3.0, zFar = 7.0, fov = 45.0; // 重設投影 projection.setToIdentity(); // 設置透視投影 projection.perspective(fov, static_cast(aspect), zNear, zFar); } void MyGLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕緩存和深度緩沖 QMatrix4x4 matrix; matrix.translate(0.0, 0.0, -5.0); //矩陣變換 program.enableAttributeArray(0); program.enableAttributeArray(1); program.setAttributeArray(0, vertices.constData()); program.setAttributeArray(1, texCoords.constData()); program.setUniformValue("texture", 0); //將當前上下文中位置的統一變量設置為value texture->bind(); //綁定紋理 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);//繪制紋理 texture->release(); //釋放綁定的紋理 texture->destroy(); //消耗底層的紋理對象 texture->create(); } void MyGLWidget::setImage(const QImage &image) { texture->setData(image); //設置紋理圖像 //設置紋理細節 texture->setLevelofDetailBias(-1);//值越小,圖像越清晰 update(); }
3.3 主函數: 調用測試
UI界面拖一個Qwidget控件,提升為MyGLwidget類(繼承QopenGLWidget重寫的類)
#include "widget.h" #include "ui_widget.h" #include "myglwidget.h" #include Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); //this->setWindowFlags(Qt::FramelessWindowHint); //this->setWindowOpacity(0.5); connect(&timer, &QTimer::timeout, this, &Widget::slotUpdate); timer.start(40); } Widget::~Widget() { delete ui; } void Widget::slotUpdate() { ui->widget->setImage(QImage(":/image/1161.24.png")); }
GPU加速云服務器 渲染
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。