1. 程式人生 > >OpenGL_Qt學習筆記之_04(3D圖形的繪製和旋轉)

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學習筆記(三)——TSKMBX

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 向量 一個向量代表的是一個擁有大小和方向