1. 程式人生 > >分析一個別人的qt+opengl例子

分析一個別人的qt+opengl例子

      最近學習OpenGL,雖然說Qt可以使用原生OpenGL的API,但是Qt也提供了封裝的QOpenGL系列。我用原生的和封裝的分別實現了一次簡單渲染(都是渲染兩個有深度和顏色的三角形)。

0_1455269566819_upload-0d1bbdea-3f41-4724-81d0-ea7026e3ff90

       原生的OpenGL用法我就不贅述了(主要是總結不好TvT,而且有很多資料可查)。(PS:兩個程式的原始碼附在最後了)
       主要說一下封裝的QOpenGL幾個注意的地方
一、 QOpenGLBuffer類
在使用前,建構函式處可指定Buffer型別。預設為VertexBuffer。
0_1455269596523_upload-b062e1b9-be25-4642-a3d2-f8486b778375
在使用之前先要create(),之後bind到當前的OpenGL context上。
使用allocate()分配儲存空間,同時可以用某個資料來初始化分配的空間。

0_1455269616250_upload-bb5bcfbf-7ef3-4352-b245-be6078a68579
相當於原生API中:

<code class="hljs" style="display: inline-block; padding: 0.5em; background-color: rgb(35, 35, 35); color: rgb(230, 225, 220); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; overflow-x: auto; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">glGenBuffers();
glBindBuffer();
glBufferData();
</code>

二、 QOpenGLShader類
可以在建構函式的地方選擇shader的型別。可以有多種方式新增原始碼,詳情參見Qt幫助文件,很簡單。
0_1455269642132_upload-085b29bb-6d54-463b-8b4c-a2ae92cf84fc
相當於原生API中:
0_1455269655462_upload-4e389e98-1405-4485-87cd-7e1eb8c6a9cd
三、 QOpenGLShaderProgram類
可以直接從檔案、原始碼之類的新增Shader。也可以使用addShader新增現有的Shader。需要呼叫link()將新增到這個program的shader都連結起來。之後呼叫bind()使該program成為當前唯一繫結到OpenGL Context上的其它porgram將被釋放(release)掉。
0_1455269673552_upload-f0c7e6ce-0dac-47cc-8cb6-dc3bd8ab55cc
相當於原生API中:
0_1455269683068_upload-add75868-51a0-43fb-b2eb-9ac7a11d3f78
之後使用enableAttributeArray來啟用相應的頂點屬性陣列(Enables the vertex array at location in this shader program so that the value set by setAttributeArray() on location will be used by the shader program.)

0_1455269705195_upload-0abb70b2-1e80-4427-8668-07e20c23503b
相當於原生API中:
0_1455269721629_upload-9da766a0-bbd4-4075-81c3-c5d0f31a15c7

由於程式很簡單,沒有涉及QOpenGLContext類和其他一些類的介紹~感興趣可以去翻閱他人的部落格之類的。。。(PS:我還是喜歡用原生的。。。)

       不過我是看不出來有什麼深度,

 main.cpp

#include"mainwindow.h"
#include<QApplication>
intmain(intargc,char*argv[])
{
QApplicationa(argc,argv);
MainWindoww;
w.show();
returna.exec();
}
mainwindow.h
#ifndefMAINWINDOW_H
#defineMAINWINDOW_H
#include<QMainWindow>
namespaceUi{
classMainWindow;
}
classMainWindow:publicQMainWindow
{
Q_OBJECT
public:
explicitMainWindow(QWidget*parent=0);
~MainWindow();
private:
Ui::MainWindow*ui;
};
#endif//MAINWINDOW_H

mainwindow.cpp

#include"mainwindow.h"
#include"ui_mainwindow.h"
MainWindow::MainWindow(QWidget*parent):
QMainWindow(parent),
ui(newUi::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
deleteui;
}

      看到這裡,是不是感到很奇怪,就一個普通的QMainWindow,opengl的內容在哪呼叫?

      這個倒是看到了以前沒碰到多的方法,在mainwindow.ui中

      <widgetclass="xiaoGLWidget"name="openGLWidget">
<propertyname="sizePolicy">
<sizepolicyhsizetype="Expanding"vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
      在UI佈局中使用了一個自定義的widget,不知道他是怎麼拖出來的,很神奇。

xiaoglwidget.h

#ifndefXIAOGLWIDGET_H
#defineXIAOGLWIDGET_H
#include<QOpenGLWidget>
#include<QOpenGLFunctions_4_3_Compatibility>
#include<QOpenGLShader>
#include<QOpenGLShaderProgram>
#include<QOpenGLBuffer>
classxiaoGLWidget:publicQOpenGLWidget,protectedQOpenGLFunctions_4_3_Compatibility
{
public:
xiaoGLWidget(QWidget*parent);
virtual~xiaoGLWidget();
voidinstallShader();
voidsendDataToOpenGL();
protected:
voidinitializeGL();
voidpaintGL();
voidresizeGL(intw,inth);
private:
QOpenGLShaderProgramm_program;
QOpenGLBufferm_vertexBuf;
QOpenGLBufferm_indexBuf;
};
#endif//XIAOGLWIDGET_H

xiaoglwidget.cpp

#include"xiaoglwidget.h"
externconstchar*vertexShaderCode;
externconstchar*fragmentShaderCode;
xiaoGLWidget::xiaoGLWidget(QWidget*parent):m_program(this),m_indexBuf(QOpenGLBuffer::IndexBuffer)
{
}
xiaoGLWidget::~xiaoGLWidget()
{
m_vertexBuf.destroy();
m_indexBuf.destroy();
}
voidxiaoGLWidget::initializeGL()
{
initializeOpenGLFunctions();
installShader();
sendDataToOpenGL();
glEnable(GL_DEPTH_TEST);
}
voidxiaoGLWidget::paintGL()
{
initializeOpenGLFunctions();
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,NULL);
}
voidxiaoGLWidget::resizeGL(intw,inth)
{
}
voidxiaoGLWidget::sendDataToOpenGL()
{
initializeOpenGLFunctions();
constGLfloatRED_TRIANGLE_DEPTH=-0.5f;
constGLfloatBLUE_TRIANGLE_DEPTH=0.5f;
GLfloatverts[]={
+0.0f,-1.0f,RED_TRIANGLE_DEPTH,
+1.0f,+0.0f,+0.0f,
+1.0f,+1.0f,RED_TRIANGLE_DEPTH,
+1.0f,+0.0f,+0.0f,
-1.0f,+1.0f,RED_TRIANGLE_DEPTH,
+1.0f,+0.0f,+0.0f,
+0.0f,+1.0f,BLUE_TRIANGLE_DEPTH,
+0.0f,+0.0f,+1.0f,
-1.0f,-1.0f,BLUE_TRIANGLE_DEPTH,
+0.0f,+0.0f,+1.0f,
+1.0f,-1.0f,BLUE_TRIANGLE_DEPTH,
+0.0f,+0.0f,+1.0f,
};
GLushortindices[]={0,1,2,3,4,5};
this->m_vertexBuf.create();
this->m_indexBuf.create();
this->m_vertexBuf.bind();
this->m_indexBuf.bind();
this->m_vertexBuf.allocate(verts,sizeof(verts));
this->m_indexBuf.allocate(indices,sizeof(indices));
m_program.enableAttributeArray(0);
m_program.setAttributeBuffer(0,GL_FLOAT,0,3,sizeof(float)*6);
m_program.enableAttributeArray(1);
m_program.setAttributeBuffer(1,GL_FLOAT,sizeof(float)*3,3,sizeof(float)*6);
}
voidxiaoGLWidget::installShader()
{
QOpenGLShadervertexShader(QOpenGLShader::Vertex);
vertexShader.compileSourceCode(vertexShaderCode);
QOpenGLShaderfragmentShader(QOpenGLShader::Fragment);
fragmentShader.compileSourceCode(fragmentShaderCode);
m_program.addShader(&vertexShader);
m_program.addShader(&fragmentShader);
m_program.link();
m_program.bind();
}

shadercode.cpp

constchar*vertexShaderCode=
"#version430\r\n"
""
"inlayout(location=0)vec3position;"
"inlayout(location=1)vec3vertexColor;"
""
"outvec3theColor;"
""
"voidmain()"
"{"
"gl_Position=vec4(position,1.0);"
"theColor=vertexColor;"
"}";
constchar*fragmentShaderCode=
"#version430\r\n"
""
"outvec4daColor;"
"invec3theColor;"
""
"voidmain()"
"{"
"daColor=vec4(theColor,1.0);"
"}";

       定義了一個widget,

classxiaoGLWidget:publicQOpenGLWidget,protectedQOpenGLFunctions_4_3_Compatibility

      繼承自QOpenGLWidget,然後初始化opengl functions api。

      關於shader,就和我前面的第二個程式寫法不同了。

QOpenGLShadervertexShader(QOpenGLShader::Vertex);
QOpenGLShaderfragmentShader(QOpenGLShader::Fragment);
      建立了兩個著色器之後,使用compileSourceCode來載入程式

      而之前的我是先建立一個專案物件,用專案物件的addShaderFromSourceCode來載入程式

      去看下qt的原始碼實現,就是呼叫者和被呼叫者的關係。

      然後呼叫addShader載入進去

      之後就是link、bind

constGLfloatRED_TRIANGLE_DEPTH=-0.5f;
constGLfloatBLUE_TRIANGLE_DEPTH=0.5f;

      z軸正向指向裡,所以負數的會在正數上方,也就是紅色在藍色上方,哦,這就是他說的深度。

GLfloatverts[]={
+0.0f,-1.0f,RED_TRIANGLE_DEPTH,
+1.0f,+0.0f,+0.0f,
+1.0f,+1.0f,RED_TRIANGLE_DEPTH,
+1.0f,+0.0f,+0.0f,
-1.0f,+1.0f,RED_TRIANGLE_DEPTH,
+1.0f,+0.0f,+0.0f,
+0.0f,+1.0f,BLUE_TRIANGLE_DEPTH,
+0.0f,+0.0f,+1.0f,
-1.0f,-1.0f,BLUE_TRIANGLE_DEPTH,
+0.0f,+0.0f,+1.0f,
+1.0f,-1.0f,BLUE_TRIANGLE_DEPTH,
+0.0f,+0.0f,+1.0f,
};
      這裡定義了12組,為什麼定義這麼多?
this->m_vertexBuf.create();
this->m_indexBuf.create();

     這裡有兩個buf,幹什麼用的?

GLushortindices[]={0,1,2,3,4,5};
this->m_vertexBuf.allocate(verts,sizeof(verts));
this->m_indexBuf.allocate(indices,sizeof(indices));
    一個存放頂點資料,一個存放索引 ?
m_program.enableAttributeArray(0);
m_program.enableAttributeArray(1);

      使能了,那要先看下著色器,先看片段的

constchar*fragmentShaderCode=
"#version430\r\n"
""
"outvec4daColor;"
"invec3theColor;"
""
"voidmain()"
"{"
"daColor=vec4(theColor,1.0);"
"}";
      有了之前的基礎,看著就簡單了,之前就知道了 120之後就沒有了gl_FragColor,所以要自己定義一個輸出,設定為輸入的顏色,alpha為1.0f,輸入即頂點著色器的顏色輸出
constchar*vertexShaderCode=
"#version430\r\n"
""
"inlayout(location=0)vec3position;"
"inlayout(location=1)vec3vertexColor;"
""
"outvec3theColor;"
""
"voidmain()"
"{"
"gl_Position=vec4(position,1.0);"
"theColor=vertexColor;"
"}";
      顏色設定為輸入的vertexColor顏色

     他這裡直接使用layout(location=0)定義了位置

     使能後裝載

m_program.setAttributeBuffer(0,GL_FLOAT,0,3,sizeof(float)*6);
m_program.setAttributeBuffer(1, GL_FLOAT, sizeof(float)*3, 3, sizeof(float)*6);
     (之前的我是用glVertexAttribPointer裝載頂點和顏色資料的)

     這裡裝載前面的buffer

voidsetAttributeBuffer(intlocation,GLenumtype,intoffset,inttupleSize,intstride=0);
void glVertexAttribPointer(GLuintindx,GLintsize,GLenumtype,GLbooleannormalized,GLsizeistride,constvoid*ptr)

     使能深度測試

glEnable(GL_DEPTH_TEST);

     繪製     

glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);

      沒有看到buffer使用的地方

在使用之前先要create(),之後bind到當前的OpenGL context上。
使用allocate()分配儲存空間,同時可以用某個資料來初始化分配的空間

     十二組資料,是一組頂點資料,一組顏色資料,那怎麼區分的呢

setAttributeBuffer(0,GL_FLOAT,0,3,sizeof(float)*6);
      offset = 0,第一組開始,

      tuplesize = 3,三個資料,就是第一組三個資料

      stride = sizeof(float) * 6,步幅這麼長,下次去就是6個數據之後,就是第三組資料開始

setAttributeBuffer(1, GL_FLOAT, sizeof(float)*3, 3, sizeof(float)*6);
     offset = sizeof(float) * 3, 就是第二組資料的開始,

     tuplesize = 3,也就是第二組三個資料,

     stride = sizeof(float) * 6,步幅這麼長,下次去就是6個數據之後,就是第四組資料開始

     取的順序呢,indices[]={0,1,2,3,4

相關推薦

分析一個別人qt+opengl例子

      最近學習OpenGL,雖然說Qt可以使用原生OpenGL的API,但是Qt也提供了封裝的QOpenGL系列。我用原生的和封裝的分別實現了一次簡單渲染(都是渲染兩個有深度和顏色的三角形)。        原生的OpenGL用法我就不贅述了(主要是總結

OpenGL VS2012環境搭建以及第一個OpenGL例子 WIN7 64位系統

                學習OpenGL是想在Coocs2d-x中加入讀取Maya等軟體做出來的動畫檔案。 在W

qt opengl lesson2 繪製一個三角形和一個正方形

在lesson1的基礎上加入一個三角形和一個正方形。 #------------------------------------------------- # # Project created by QtCreator 2017-01-19T20:33:38 # #--

Qt OpenGL教程】01:建立一個OpenGL視窗

void MyGLWidget::resizeGL(int w, int h) //重置OpenGL視窗的大小 { glViewport(0, 0, (GLint)w, (GLint)h); //重置當前的視口 glMatrixMod

今天終於將qt-opengl一個簡單的程式寫出來了,

在建立的時候大家一定注意 在它的管理檔案中一定要新增一句 QT+=openglwidgets 在構建之前一定要記得執行以下 qmake 個是配置工程檔案的 未配置的 時候可能會出現link 2019 的錯誤

一個ArcGIS網路分析的最短路徑例子||A Network Analyst Shortest Route of ArcGIS

這是我前幾年利用ArcMap,ArcCatalog做的最短路徑查詢時候實現的步驟說明記錄,留作後用,時代久遠,很容易忘記,適當做個記錄算是個好習慣吧。 例子是以上海地鐵線路換乘的。 可以實現任意兩點之間的地鐵路線查詢。 主要內容:ArcMap,ArcCatalog,Netw

一個基於QT簡單登錄對話框(帶驗證碼功能)

oid mov rim cat pla .sh end qpainter turn 1. 對話框樣式 2. 源代碼 ①. main.cpp #include <QtGui/QApplication> #include "QLoginDialog.h

第三組 典型場景分析 一個追求滿星通關的用戶

嘗試 獲得 想要 分析 了無 原因 功能 障礙 沒有 場景:用戶進行遊戲1.背景1)典型用戶:張某2)用戶的需求/迫切需要解決的問題;a.自身水平有限,無法完成全部問題或無法實現滿星通關;b.出於虛榮心/探索欲/求知欲/強迫癥等各種原因想要獲得滿星通關。3)假設:a.遊戲提

一個vue.js的例子

note css tps data doctype bsp script https 建立 1.使用notepad建立一個網頁文件demo.html, <!DOCTYPE html><html><head><meta charset

QT blockingmaster例子學習

qwidget 等待 cit 數據 nec 為什麽 star nullptr 同步 dialog.h: #ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include "masterthread.

溫習一個簡單的HTML例子

.html tex tle left html html網頁 idt blue red <!--程序ch02_1.html--> <html>   <head>     <title>第一個HTML網頁</title&g

練習創建一個單例模式例子

eve jpg closed div 使用 htm stop http pla 昨天有寫過一個單例模式的練習。《單例模式(C#)》 寫得較為復雜,今天再使用另外的方法來實現: class Au { private static

break的一個不常用的例子

() pub == style com stat 多層 rgs package package com.huoshan.threadTest; public class MyTest { public static void main(String[] args)

利用Chrome的Heap Snapshot功能分析一個時間段內的內存占用率

-i 獲取 logs post ges summary ima 下拉菜單 allocated 在下圖測試代碼第13行和第16行設斷點. 以調試方式運行,首先斷點在第13行處觸發: 打開Chrome開發者工具,點擊Profiles tab, 再點擊按鈕"Take Snaps

45.Qt openGL實現三維繪圖

窗口 err lin span protected 調用 event header 實現 main.cpp #include <QApplication> #include <iostream> #include "tetrahea

優化器跟蹤分析一個很怪異的現象

rac 不同 得來 完全 png users from mys bsp 工作中遇到一則很奇怪的真實案例,有一個統計sql,統計結果在190-200之間時,耗時基本上維持在1.6S,統計結果在此數據範圍外的統計耗時,基本上維持在0.1-0.3S之間, 按照慣例,explain

給出一個jdbc的transaction例子

who statement 但是 The font mat prim apt pri 7.jdbc的transaction例子:(視頻下載) (全部書籍)import java.sql.*;public class MySQlTransaction1 { public s

數據結構與算法學習筆記之如何分析一個排序算法?

編號 height href eight 代碼 [] www. 價值 它的 前言 現在IT這塊找工作,不會幾個算法都不好意思出門,排序算法恰巧是其中最簡單的,我接觸的第一個算法就是它,但是你知道怎麽分析一個排序算法麽?有很多時間復雜度相同的排序算法,在實際編碼中,那又如何

spring boot 整合redis 以一個熱門房產為例子

1.新增redis依賴 就是jedis redis.clients jedis 2.9.0 2.每次點選房屋詳情熱度加一 呼叫此方法 recommandService.increase(id);//每次點選房屋熱度加1 3.recommandService如何寫主要

一個記憶體洩漏的例子

記憶體洩漏 看一個例子: class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16;