OpenGL_Qt學習筆記之_04(3D圖形的繪製和旋轉)
繪製四稜錐
四稜錐由5個面構成一個封閉的立體圖,其中4個共頂點的側面是三角形,底面是個四邊形。如果我們要繪製一個3D的四稜錐只需要繪製這5個面即可,繪製的方法和前一篇文章OpenGL_Qt學習筆記之_03(平面圖形的著色和旋轉)的相同。只不過這裡的頂點座標是3維的,所以影象深度那一維不一定為0。因此我們可以事先計算好四稜錐各個頂點的座標,這對學過立體幾何的人來說應該是小case了。然後繪製每個面就可以。
注意,在opengl中繪製每個面時,所有面給出的頂點的順序都要按照逆時針或者順時針(我這裡採用的是逆時針),這樣才能保證所繪製出來的影象時正確的。
現在我們在paintGL中開始繪製四稜錐,如果按照NeHe的教程,它只是繪製了個金字塔,並沒有底面,只有4個側面,這裡,我採用它的方法,程式碼如下:
/*下面開始畫四稜錐*/ glLoadIdentity();//重置當前的模型觀察矩陣 glTranslatef(-0.5, 0.0, -0.5);//將繪製平面移動到螢幕的左半平面和裡面 glRotatef(x_rotate, 0.2, 0.2, 0.0); glBegin(GL_TRIANGLES); /*前正面的繪製*/ glColor3f(1.0, 0.0, 0.0);//上頂點紅色 glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0, 0.0, 1.0);//左下點藍色 glVertex3f(-0.3, -0.3, 0.3); glColor3f(0.0, 1.0, 0.0);//右下角綠色 glVertex3f(0.3, -0.3, 0.3); /*右側面的繪製*/ glColor3f(1.0, 0.0, 0.0);//上頂點紅色 glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0, 0.0, 1.0);//左下點藍色 glVertex3f(0.3, -0.3, 0.3); glColor3f(0.0, 1.0, 0.0);//右下角綠色 glVertex3f(0.3, -0.3, -0.3); /*後側面的繪製*/ glColor3f(1.0, 0.0, 0.0);//上頂點紅色 glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0, 0.0, 1.0);//左下點藍色 glVertex3f(0.3, -0.3, -0.3); glColor3f(0.0, 1.0, 0.0);//右下角綠色 glVertex3f(-0.3, -0.3, -0.3); /*左側面的繪製*/ glColor3f(1.0, 0.0, 0.0);//上頂點紅色 glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0, 0.0, 1.0);//左下點藍色 glVertex3f(-0.3, -0.3, -0.3); glColor3f(0.0, 1.0, 0.0);//右下角綠色 glVertex3f(-0.3, -0.3, 0.3); x_rotate_angle1 += 3.0; glEnd();
在繪製完金子塔後,把它沿某一個方向旋轉後如下圖所示:
如果我們在後面加上程式碼,把底面補全,畫上一個四邊形,此時加入的程式碼如下:
/*底面四邊形的繪製,使四稜錐封閉起來*/ glBegin(GL_QUADS); glColor3f(0.0, 0.0, 1.0);//上頂點紅色 glVertex3f(-0.3, -0.3, 0.3); glColor3f(0.0, 1.0, 0.0);//左下點藍色 glVertex3f(0.3, -0.3, 0.3); glColor3f(0.0, 0.0, 1.0);//右下角綠色 glVertex3f(0.3, -0.3, -0.3); glColor3f(0.0, 1.0, 0.0); glVertex3f(-0.3, -0.3, -0.3); glEnd();
這時候的結果如下:
繪製立方體
繪製立方體的方法和四稜錐的方法類似,只不過這裡是由6個正方形構成的封閉體,我們依次繪製出每個面即可,同樣要注意的是繪製每個面時給出點的順序要一致,繪製每個面的順序倒不需要按照什麼逆時針或者順時針,什麼順序都行。
計算好正方體的8個頂點座標後就開始寫程式碼了,程式碼如下:
/*下面開始畫立方體*/ glLoadIdentity(); glTranslated(0.5, 0, 0.5);//將繪製平面移動到螢幕的右半平面和外面 glRotatef(rotate_angle2, -0.2, 0.2, -0.3); glBegin(GL_QUADS); //上頂面 glColor3f(0.0, 1.0, 0.0); glVertex3f(-0.3, 0.3, -0.3); glVertex3f(-0.3, 0.3, 0.3); glVertex3f(0.3, 0.3, 0.3); glVertex3f(0.3, 0.3, -0.3); //下頂面 glColor3f(0.0, 1.0, 0.0); glVertex3f(-0.3, -0.3, -0.3); glVertex3f(-0.3, -0.3, 0.3); glVertex3f(0.3, -0.3, 0.3); glVertex3f(0.3, -0.3, -0.3); //正前面 glColor3f(1.0, 0.0, 0.0); glVertex3f(-0.3, 0.3, 0.3); glVertex3f(-0.3, -0.3, 0.3); glVertex3f(0.3, -0.3, 0.3); glVertex3f(0.3, 0.3, 0.3); //右側面 glColor3f(1.0, 1.0, 0.0); glVertex3f(0.3, 0.3, 0.3); glVertex3f(0.3, -0.3, 0.3); glVertex3f(0.3, -0.3, -0.3); glVertex3f(0.3, 0.3, -0.3); //背後面 glColor3f(0.0, 1.0, 1.0); glVertex3f(-0.3, 0.3, -0.3); glVertex3f(0.3, 0.3, -0.3); glVertex3f(0.3, -0.3, -0.3); glVertex3f(-0.3, -0.3, -0.3); //左側面 glColor3f(1.0, 0.0, 1.0); glVertex3f(-0.3, 0.3, -0.3); glVertex3f(-0.3, -0.3, -0.3); glVertex3f(-0.3, -0.3, 0.3); glVertex3f(-0.3, 0.3, 0.3); rotate_angle2 -= 3; glEnd();
其效果如下:
當兩者放在一起,且經過不同軸的旋轉後圖像如下:
實驗主要部分程式碼如下(附錄有工程code下載地址):
#include "glwidget.h" #include "ui_glwidget.h" #include <QtGui> #include <QtCore> #include <QtOpenGL> GLWidget::GLWidget(QGLWidget *parent) : QGLWidget(parent), ui(new Ui::GLWidget) { // setCaption("The Opengl for Qt Framework"); ui->setupUi(this); fullscreen = false; rotate_angle1 = 0.0; rotate_angle2 = 0.0; } //這是對虛擬函式,這裡是重寫該函式 void GLWidget::initializeGL() { setGeometry(300, 150, 640, 480);//設定視窗初始位置和大小 glShadeModel(GL_SMOOTH);//設定陰影平滑模式 glClearColor(0.0, 0.0, 0.0, 0);//改變視窗的背景顏色,不過我這裡貌似設定後並沒有什麼效果 glClearDepth(1.0);//設定深度快取 glEnable(GL_DEPTH_TEST);//允許深度測試 glDepthFunc(GL_LEQUAL);//設定深度測試型別 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//進行透視校正 } void GLWidget::paintGL() { //glClear()函式在這裡就是對initializeGL()函式中設定的顏色和快取深度等起作用 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /*下面開始畫四稜錐*/ glLoadIdentity();//重置當前的模型觀察矩陣 glTranslatef(-0.5, 0.0, -0.5);//將繪製平面移動到螢幕的左半平面和裡面 glRotatef(rotate_angle1, 0.2, 0.2, 0.0); glBegin(GL_TRIANGLES); /*前正面的繪製*/ glColor3f(1.0, 0.0, 0.0);//上頂點紅色 glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0, 0.0, 1.0);//左下點藍色 glVertex3f(-0.3, -0.3, 0.3); glColor3f(0.0, 1.0, 0.0);//右下角綠色 glVertex3f(0.3, -0.3, 0.3); /*右側面的繪製*/ glColor3f(1.0, 0.0, 0.0);//上頂點紅色 glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0, 0.0, 1.0);//左下點藍色 glVertex3f(0.3, -0.3, 0.3); glColor3f(0.0, 1.0, 0.0);//右下角綠色 glVertex3f(0.3, -0.3, -0.3); /*後側面的繪製*/ glColor3f(1.0, 0.0, 0.0);//上頂點紅色 glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0, 0.0, 1.0);//左下點藍色 glVertex3f(0.3, -0.3, -0.3); glColor3f(0.0, 1.0, 0.0);//右下角綠色 glVertex3f(-0.3, -0.3, -0.3); /*左側面的繪製*/ glColor3f(1.0, 0.0, 0.0);//上頂點紅色 glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0, 0.0, 1.0);//左下點藍色 glVertex3f(-0.3, -0.3, -0.3); glColor3f(0.0, 1.0, 0.0);//右下角綠色 glVertex3f(-0.3, -0.3, 0.3); rotate_angle1 += 3.0; glEnd(); /*底面四邊形的繪製,使四稜錐封閉起來*/ glBegin(GL_QUADS); glColor3f(0.0, 0.0, 1.0);//上頂點紅色 glVertex3f(-0.3, -0.3, 0.3); glColor3f(0.0, 1.0, 0.0);//左下點藍色 glVertex3f(0.3, -0.3, 0.3); glColor3f(0.0, 0.0, 1.0);//右下角綠色 glVertex3f(0.3, -0.3, -0.3); glColor3f(0.0, 1.0, 0.0); glVertex3f(-0.3, -0.3, -0.3); glEnd(); /*下面開始畫立方體*/ glLoadIdentity(); glTranslated(0.5, 0, 0.5);//將繪製平面移動到螢幕的右半平面和外面 glRotatef(rotate_angle2, -0.2, 0.2, -0.3); glBegin(GL_QUADS); //上頂面 glColor3f(0.0, 1.0, 0.0); glVertex3f(-0.3, 0.3, -0.3); glVertex3f(-0.3, 0.3, 0.3); glVertex3f(0.3, 0.3, 0.3); glVertex3f(0.3, 0.3, -0.3); //下頂面 glColor3f(0.0, 1.0, 0.0); glVertex3f(-0.3, -0.3, -0.3); glVertex3f(-0.3, -0.3, 0.3); glVertex3f(0.3, -0.3, 0.3); glVertex3f(0.3, -0.3, -0.3); //正前面 glColor3f(1.0, 0.0, 0.0); glVertex3f(-0.3, 0.3, 0.3); glVertex3f(-0.3, -0.3, 0.3); glVertex3f(0.3, -0.3, 0.3); glVertex3f(0.3, 0.3, 0.3); //右側面 glColor3f(1.0, 1.0, 0.0); glVertex3f(0.3, 0.3, 0.3); glVertex3f(0.3, -0.3, 0.3); glVertex3f(0.3, -0.3, -0.3); glVertex3f(0.3, 0.3, -0.3); //背後面 glColor3f(0.0, 1.0, 1.0); glVertex3f(-0.3, 0.3, -0.3); glVertex3f(0.3, 0.3, -0.3); glVertex3f(0.3, -0.3, -0.3); glVertex3f(-0.3, -0.3, -0.3); //左側面 glColor3f(1.0, 0.0, 1.0); glVertex3f(-0.3, 0.3, -0.3); glVertex3f(-0.3, -0.3, -0.3); glVertex3f(-0.3, -0.3, 0.3); glVertex3f(-0.3, 0.3, 0.3); rotate_angle2 -= 3; glEnd(); } //該程式是設定opengl場景透檢視,程式中至少被執行一次(程式啟動時). void GLWidget::resizeGL(int width, int height) { if(0 == height) height = 1;//防止一條邊為0 glViewport(0, 0, (GLint)width, (GLint)height);//重置當前視口,本身不是重置視窗的,只不過是這裡被Qt給封裝好了 glMatrixMode(GL_PROJECTION);//選擇投影矩陣 glLoadIdentity();//重置選擇好的投影矩陣 // gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);//建立透視投影矩陣 glMatrixMode(GL_MODELVIEW);//以下2句和上面出現的解釋一樣 glLoadIdentity(); } void GLWidget::keyPressEvent(QKeyEvent *e) { switch(e->key()) { //F1鍵為全屏和普通屏顯示切換鍵 case Qt::Key_F1: fullscreen = !fullscreen; if(fullscreen) showFullScreen(); else { setGeometry(300, 150, 640, 480); showNormal(); } updateGL(); break; //Ese為退出程式鍵 case Qt::Key_Escape: close(); } } GLWidget::~GLWidget() { delete ui; }
總結:本文在前面文章繪製2D影象和旋轉的基礎上,增加一維的座標就可以繪製出3D圖形即旋轉了。在畫3D圖時,必須將OpenGL螢幕想象成一張很大的畫紙,後面還帶著許多透明的層。差不多就是個由大量的點組成的立方體。這些點從左至右、從上至下、從前到後的佈滿了這個3D圖的表面。
參考資料:
附錄:
相關推薦
OpenGL_Qt學習筆記之_04(3D圖形的繪製和旋轉)
繪製四稜錐 四稜錐由5個面構成一個封閉的立體圖,其中4個共頂點的側面是三角形,底面是個四邊形。如果我們要繪製一個3D的四稜錐只需要繪製這5個面即可,繪製的方法和前一篇文章OpenGL_Qt學習筆記之_03(平面圖形的著色和旋轉)的相同。只不過這裡的頂點座標是3維的,所以影象深度那一維不
OpenGL_Qt學習筆記之_02(繪製簡單平面幾何圖形)
#include "glwidget.h" #include "ui_glwidget.h" #include <QtGui> #include <QtCore> #include <QtOpenGL> #ifndef GL_MULTISAMPLE #define
【學習筆記之Openlayers3】要素繪製篇(第三篇)
直接以專案例項來進行講解要素繪製 需求(假如): 1.實現在地圖上畫點線面功能 2.自定義其樣式 3.支援編輯功能 需要用到的openlayers3中的ol.interaction.Draw 類。這是openlayers3提供的內建互動方式,除了這
OpenGL_Qt學習筆記之_07(閃爍的星星)
這一小節我們要完成的任務是:將一張背景是黑色,中間是白亮色的星星圖片和五顏六色的顏色進行色彩融合,變成一顆彩色的星星。並且讓這些星星自轉和公轉,可以控制自轉和公轉的速度,另外也能控制所有的星星是否能夠閃爍。 實驗基礎 色彩融合知識: 剛開始提到由黑白的星星變成彩色的星
Spark 學習筆記之 Standalone與Yarn啟動和運行時間測試
span ima 上傳 運行 yarn erl 技術分享 word wordcount Standalone與Yarn啟動和運行時間測試: 寫一個簡單的wordcount: 打包上傳運行: Standalone啟動: 運行時間:
R語言可視化學習筆記之添加p-value和顯著性標記--轉載
let run compare tac rod 學習 line 需要 abs https://www.jianshu.com/p/b7274afff14f?from=timeline #先加載包 library(ggpubr) #加載數據集ToothGrowth dat
《Android開發藝術探索》學習筆記之Android的執行緒和執行緒池
一、概述 1、主執行緒與子執行緒 主執行緒 又叫UI執行緒 主要作用是執行四大元件以及處理它們和使用者的互動,主要用來處理和介面相關的事情 子執行緒 執行耗時任務,比如網路請求、I/O操作等
DSP——DSP/BIOS學習筆記之(三)——TSK和MBX
1、它們都是任務間通訊的手段,但是應用場合不同 訊號量用作任務同步或者資源的互斥訪問 至於郵箱,名副其實的,可以“郵寄”一些東東給別的任務 舉個例子的話,我覺得可以說訊號量就像別人打你電話只響一下(具體代表什麼含義在於你們之間的約定),而郵箱就像簡訊哇,寫啥都行。當然,二進位制訊號量也可以用郵箱實現。 2、
spark學習筆記之二:寬依賴和窄依賴
1.如果父RDD裡的一個partition只去向一個子RDD裡的partition為窄依賴,否則為寬依賴(只要是shuffle操作)。 2.spark根據運算元判斷寬窄依賴: 窄依賴:map
吳恩達機器學習 學習筆記 之 二 :代價函式和梯度下降演算法
二、 2-1 Model Representation 我們學習的第一個演算法是線性迴歸,接下來會講什麼樣的模型更重要,監督學習的過程是什麼樣子。 首先舉一個需要做預測的例子:住房價格上漲,預測房價,我們擁有某一城市的住房價格資料。基於這些資料,繪製圖形。 在已有房價資
ElasticSearch學習筆記之九 複雜資料型別和巢狀物件
複雜資料型別 除了前面說到的簡單資料型別,Elasticsearch還支援JSON 的null ,陣列,和物件. 空域 欄位取值可以為空,當然,陣列也可以為空。 然而,在 Lucene 中是不能儲存 null 值的,所以我們認為存在 null 值的域為空域。
學習筆記之linux多執行緒和多程序優缺點
Linux下的多執行緒 執行緒和程序相比的缺點和優點 優點: 多執行緒對資源的需求少,建立的代價比程序小 缺點:除錯困難,非常容易出錯 執行緒擁有獨立的程式計數器,獨立的棧空間,共享程序的全域性記憶體和堆記憶體,共享檔案描述符,共享虛擬記憶體。繼承訊號的處理可以訪問程序
Lucene學習筆記之(一)簡介和向文件寫索引並讀取文件
什麼是lucene? lucene就是一個全文檢索的工具包。 Lucene的能幹什麼? 1. 獲取內容(Acquire Content) Lucene不提供爬蟲功能,如果需要獲取內容需要自己建立爬蟲應用。 Lucene只做索引和搜尋工作。 2.建立文件(Buil
Introduction to 3D Game Programming with DirectX 12 學習筆記之 --- 第七章:在Direct3D中繪製(二)
程式碼工程地址: https://github.com/jiabaodan/Direct12BookReadingNotes 學習目標 理解本章中針對命令佇列的更新(不再需要每幀都flush命令佇列),提高效能; 理解其他兩種型別的根訊號引數型別:根描述
Introduction to 3D Game Programming with DirectX 12 學習筆記之 --- 第六章:在Direct3D中繪製
程式碼工程地址: https://github.com/jiabaodan/Direct12BookReadingNotes 學習目標 熟悉Direct3D介面的定義,儲存和繪製幾何資料 ; 學習編寫基本的頂點和畫素著色器; 學習使用渲染流水線狀態
Introduction to 3D Game Programming with DirectX 12 學習筆記之 --- 第五章:渲染流水線
學習目標 瞭解幾個用以表達真實場景的標誌和2D影象的深度空間; 學習在Direct3D中如何表示3D物體; 學習如何模擬虛擬攝像機; 理解渲染流水線:如何用幾何描述的3D場景渲染出2D影象; 1 3D幻覺 如何在2D平面(顯示器)上產生
Introduction to 3D Game Programming with DirectX 12 學習筆記之 --- 第四章:Direct 3D初始化
學習目標 對Direct 3D程式設計在3D硬體中扮演的角色有基本瞭解; 理解COM在Direct 3D中扮演的角色; 學習基本的圖形學概念,比如儲存2D影象、頁面切換,深度緩衝、多重紋理對映和CPU與GPU如何互動; 學習如何使用效能計數函式讀取高精度時間;
Introduction to 3D Game Programming with DirectX 12 學習筆記之 --- 第三章:變換
學習目標 理解如何用矩陣表示線性變換和仿射變換; 學習在座標系中縮放,旋轉和移動幾何體; 學習利用矩陣的乘法合併幾個變換矩陣; 學習如何在座標系之間轉換,並且表示為轉換矩陣;斜體樣式 學習如何利用DirectX Math庫提供的方法構造轉換矩陣。
Introduction to 3D Game Programming with DirectX 12 學習筆記之 --- 第二章:矩陣代數
學習目標: 理解矩陣和與它相關的運算; 理解矩陣的乘法如何被看成是線性組合; 理解單位矩陣、轉置矩陣、矩陣的行列式和逆矩陣; 熟悉DirectX Math庫中矩陣相關的類和函式; 1 矩陣的定義 一個m x n的矩陣M是一個有實陣列成的
Introduction to 3D Game Programming with DirectX 12 學習筆記之 --- 第一章:向量代數
學習目標: 學習如何使用幾何學和數字描述 Vector; 學習 Vector 的運算方法及其在幾何學上的應用; 熟悉在 DirectXMath library 中的 Vector 相關的類和函式。 1 向量 一個向量代表的是一個擁有大小和方向