OpenGL開發之旅基礎知識介紹

  最近因爲手機項目中須要用到OpenGL ES的知識,因此這段時間正在研究OpenGL的相關知識。由於OpenGL ES是OpenGL的剪裁版本,因此我直接從OpenGL入手,而後再去看OpenGL ES就很容易上手。今後篇開始,我將發表一系列文章來逐步深刻介紹OpenGL的相關知識,開發咱們可使用VC6.0或.NET。 html

 

  那麼今天我要介紹的是OpenGL開發之旅基礎知識介紹,這很重要,會讓咱們從總體上熟悉OpenGL的工做原理及過程。 編程

   

  1. 保持模式與當即模式:
  一般狀況下咱們編寫3D圖形時可以使用兩種不一樣的方法:
  一種方法咱們稱之爲保持模式。在保持模式中,咱們能夠向編寫的API或是工具箱提供物體及場景的描述,而後圖形包就會在屏幕上建立這個圖像,咱們須要作的就是提供命令去改變照相機或場景中其餘物體的位置和觀察方向。對於咱們開發者而言,咱們建立的可以對物體及場景的描述稱爲場景圖,場景圖是什麼呢?你們可能對這個名稱比較熟悉但卻不能說出它的準確含義。在一般狀況下,場景圖是個有向無環圖的數據結構,它包含了場景中的全部物體以及這些物體之間相互的關係,實現了對物體及場景的描述。據瞭解,如今許多的遊戲引擎及高層工具箱都使用了這種方法。這使得咱們開發人員不須要對其渲染過程進行特別精細的控制,它只須要向圖形函數庫提供一個模型或是場景,圖形函數庫就會負責進行渲染,大大減輕了咱們開發人員的工做量。 windows

 

  另外一種方法咱們稱之爲當即模式。在當即模式中,咱們不須要像保持模式同樣去提供一個模型或是場景,而是向圖形處理器發送命令,圖形處理器就會根據它的狀態及發送的命令產生當即的效果。查詢圖形學書籍得知,大多數保持模式中的API或場景圖在其內部使用一個當即模式的API執行實際的渲染任務。 數據結構

 

  2. OpenGL是什麼? 框架

  OpenGL是一套應用程序編程接口(API),藉助這個API咱們開發人員就能夠開發出對圖形硬件具備訪問的能力的程序。咱們可使用OpenGL開發出運行效率較高的圖形程序或遊戲,由於OpenGL很是接近底層硬件而且OpenGL使得咱們沒必要去關注圖形硬件的細節。既然咱們開發人員沒必要關注圖形硬件的細節,那麼咱們須要關注什麼呢?咱們須要關注OpenGL如何繪製,按照專業術語就是根據物體的規格參數及相關屬性,藉助虛擬照相機和光照生成一幅該物體的圖像。OpenGL程序與平臺是無關的,因此OpenGL API中不包含任何輸入函數或窗口函數,緣由是由於這兩種函數都要依賴於特定的平臺,例如Windows,Linux或是其餘系統。 函數

 

  OpenGL API是過程性的,不是描述性的,即OpenGL不是面向對象的,因此OpenGL沒法利用面向對象的特性,例如重載,繼承等,可是咱們可使用面向對象的程序與OpenGL的實現進行連接就能夠了。做爲開發人員來講,咱們不須要去描述場景的性質和外觀,而是去肯定一些操做步驟,爲些操做步驟是爲實現必定圖形或圖像所服務的。咱們在實現這些步驟時能夠調用OpenGL中的一些命令,能夠利用這些命令繪製點、直線、多邊形或是其它圖形,還能夠調用這些命令實現光照、着色,動畫等各類效果。 工具

 

  OpenGL的實現能夠是軟件實現,也能夠是硬件實現。軟件實現是對OpengGL函數調用時做出的響應並建立二維或三維圖像的函數庫,那麼硬件實現則是經過設置可以繪製圖形或圖像的圖形卡驅動程序。通常來講,硬件實現要比軟件實現快得多。咱們都應該熟悉,在Windows上,是由圖形設備接口將圖形或圖像顯示在屏幕上或是其餘顯示設備上的。OpenGL的實現就軟件實現來講,在Windows上會根據程序命令的要求,生成相應的圖形或圖像,而後會將這個圖形或圖像移交給圖形設備接口,由圖形設備接口將圖形或是圖像顯示在咱們的屏幕上或是其餘顯示設備。這樣一說,咱們可能會明白一點OpengGL原來是在應用程序和圖形設備接口之間運做,但我感受還不能準確地這樣說。你們看下下面的圖對OpenGL的工做原理可能會理解得更明白一點:  oop


 

  上圖是OpenGL的軟件實現的工做原理。須要注意的是上圖中的構造圖形是經過軟件進行構造的。 動畫

 

  OpenGL的硬件實現與軟件實現稍微有些不一樣,硬件實現是將OpenGL的調用傳遞給硬件驅動程序,而硬件驅動程序不會將生成的圖形或圖像傳遞給圖形設備接口,而是直接與顯示設備通訊,直接將圖形或圖像結果傳遞給顯示器或其餘顯示設備。以下圖所示: spa



  OpenGL在繪製圖形時是基於一個被稱爲流水線模型的模式。也就是說其中的幾何圖形在程序中經過描述空間位置或頂點來指定其形狀並由程序生成,這些頂點在流經一系列模塊時,每一個模塊在圖形的基本組成部分(在這裏稱爲圖元)通過時對其實施一種或多種操做。模塊負責對流經的圖元實施一種或多種操做變換,例如:旋轉、平移、縮放及對攝像機進行定位等。


  3. OpenGL的組成

  OpenGL中包含許多對圖形圖像處理的函數,主要包括如下幾種:

  圖元函數:指定要生成圖形或圖像的圖元。主要有兩種類型,一種是繪製二維或三維的幾何圖元,如點,線,多邊形等;另外一種是離散型的實體,例如:位圖。

  屬性函數:屬性函數主要是控制圖元的外觀及樣式,例如:對圖元的顏色、線型、光照及紋理等效果處理。

  觀察函數:觀察函數主要是對攝像機屬性的操做。咱們能夠操做攝像機顯示圖形或圖像近距或是遠距效果。

  控制函數:可以讓咱們啓用或是彬各類OpenGL的特性。

  查詢函數:可讓咱們查詢OpenGL狀態變量的值。

  輸入與窗口控制函數:這個自己不屬於OpenGL,可是因爲咱們會常常在程序中輸入輸出或是窗口控制操做,因此,這些函數仍是比較重要的。

 

  OpenGL函數庫通常包含在兩個庫中,分別稱爲GL或GLU。GL是OpenGL的核心庫,包含必需的OpenGL函數。GLU是OpenGL的實用庫,包含許多的新函數。下面的代碼顯示了許多的Windows程序包含的典型頭文件:

#include <GL/gl.h> #include <GL/glu.h> #include <windows.h>

 

  可是爲了實現和窗口系統的交互,通常使用以下代碼引用頭文件:

#include <GL/glut.h>

 

  GLUT表示OpenGL工具箱,體現了現代窗口系統所共有的功能函數庫。GLUT的目的就是隱藏平臺的細節,glut.h已經包含了gl.h和glu.h。使用GLUT是由於OpenGL沒有包含輸入和窗口命令,而輸入和窗口命令是由平臺所決定的,與平臺的相關性較大。可是前面說過,OpenGL是與平臺無關的,也就是說OpenGL是跨平臺的。這樣設計人員就須要專門設計一個須要和窗口系統進行交互的函數庫。

 

  爲了能使OpenGL代碼更易於從一個平臺移植到另外一個平臺,OpenGL定義了它本身的數據類型,這些數據類型均可以映射到相應的C語言數據類型中。下圖顯示其映射關係:

 

  


  4. 開發語言與編程約定

  咱們開發OpenGL目前最流行的作法是OpenGL的C語言綁定,固然也可使用其它平臺或語言,例如.NET、JAVA、Python、Perl等。我會在下一篇文章中介紹如何配置相應的環境。

 

  咱們之後會見到OpenGL的函數可能是以gl開頭,由於OpenGL的函數遵循必定的命名約定,它能夠告訴咱們這個函數來自哪一個函數庫,而且還能夠告訴咱們這個函數的參數個數和類型。

  OpenGL的函數是採用如下的書寫格式:

  <函數庫前綴><根命令><可選的參數數量><可選的參數類型>

 

  如下是一個函數標註圖:


 

  5. 座標系與變換

  在開發OpenGL程序時,須要用到兩個座標系。一個稱爲對象座標系,另外一個稱爲世界座標系。

  第一個座標系是咱們在開發中使用的座標系;第二個座標系又稱爲窗口座標系或屏幕座標系,在這個座標系中的單位是像素。

  在繪製的過程當中,OpenGL會自動實現從對象到窗口座標系的轉換,所須要的信息是屏幕中顯示窗口的尺寸和用戶但願顯示對象空間的大小。OpenGL中所須要的座標系變換由兩個矩陣決定,即模型視圖矩陣和投影矩陣,這些矩陣是OpenGL的狀態的一部分。設置這兩種矩陣的典型步驟包括如下三個步驟:

  (1) 指定咱們但願修改的矩陣。

  (2) 將矩陣設爲單位矩陣。

  (3) 修改當前矩陣爲用戶指望的矩陣。

 

  以上三個步驟分別對應如下代碼:

glMatrixMode(GL_PROJECTION) glLoadIdentity(); gluortho2D(-1.0,1.0,-1.0,1.0)

 

  6. 圖元及屬性

  圖元是圖形系統中經常使用的基本實體,主要是指:點,線,直線,多邊形,位圖和像素,咱們的2D或3D圖形均可由這幾個基本的圖元來繪製。前面四個稱爲幾何圖元,主要是構建幾何圖形;後面二個稱爲非幾何圖元。OpenGL在處理幾何圖元和非幾何圖元的方式差異比較大。

  每一個圖元都有本身的屬性,屬性決定了由OpenGL顯示的方式。好比多邊形的顏色,形狀,線條的粗細等。

  咱們在繪製基本的圖形時,老是以glBegin()函數開始,而以glEnd()函數結束,針對不一樣的圖形,glBegin()函數中的參數不同。以下所示是繪製兩條直線段:

glBegin(GL_LINES); glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, 0.5); glVertex2f(0.5, -0.5); glEnd();

 

  OpenGL在繪製圖形時有不少功能,好比:光照、消隱、紋理映射等,每一種功能都將影響繪製處理的速度,在咱們的程序中可單獨的啓用或是禁用某些功能,在不使用時要將其禁用掉以使咱們的程序更加高效。如下是啓用或是禁用某項功能的代碼:

void glEnable(GLenum feature) void glDisable(GLenum feature) //啓用點劃模式 glEnable(GL_LINE-STIPPLE)

 

  7. 狀態的保存

  OpenGL在內部就是一個狀態機,函數調用會修改其內部的狀態,OpenGL的狀態決定了圖元的行爲和繪製方式。咱們對圖元的屬性和其餘狀態變量所進行的所有修改,例如模型視圖矩陣和投影矩陣,都會改變當前的狀態。在OpenGL中提供了兩種類型的堆棧,可將當前狀態保存在堆棧中,以便之後使用。

 

  矩陣堆棧可用於保存投影矩陣和模型視圖矩陣。每種類型的堆棧只能用來容納相應類型的矩陣。所使用的矩陣由當前矩陣模式(GL_MODELVIEW或GL_PROJECTION)所決定的。可用函數glPushMatrix()和glPopMatrix()使矩陣入棧或出棧。

 

  矩陣堆棧的主要做用:一是在構建層次模型時,使用堆棧來遍歷這些層次模型的樹型數據結構;二是在進行繪製時能夠回到先前的視圖,而不須要咱們從新計算繪製。咱們會在開發過程當中常看到如下代碼:

glMatrixMode(GL_PROJECTION); glPushMatrix(); glPopMatrix();

 

  須要注意的是,入棧操做和出棧操做必須成對使用;一次出棧必須與一次入棧對應。在層次系統中,若是這對操做沒有正確的成對出現的話,將使堆棧處於一種不可預知的狀態。


  8. 單緩衝與雙緩衝

  咱們在構建圖形窗口時常常也會常常看到如下的一行代碼:

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);

 

  這行代碼告訴咱們在建立時使用何種類型的顯示模式。GLUT_SINGLE表示使用一個單緩衝的窗口;GLUT_RGBA表示使用RGBA顏色模式。

  單緩衝窗口意味着全部的繪圖命令都是在被顯示的窗口上執行的。另外一種顯示模式是雙緩衝窗口,繪圖命令其實是在一個屏幕以外的緩衝區中執行的,而後快速反應的交換到窗口的視圖上進行顯示。咱們常常用雙緩衝模式開發具備動畫效果的程序,這樣會提升咱們程序的執行效率。

 

  9. 一個簡單的示例

  好了,上面說了那麼多,有的人可能想知道OpenGL的程序究竟是什麼樣的,主框架是什麼?你們若是有C語言編程經驗的一眼就能看出來它的結構。

  接下來讓咱們看一個運行VC++環境中的OpenGL示例,代碼以下:

複製代碼
#include "StdAfx.h" #ifdef __APPLE__ #include <GLUT/glut.h> #else #include <GL/glut.h> /* glut.h 包含 gl.h和glu.h*/ #endif void display(void) { // 清除顏色緩衝區  glClear(GL_COLOR_BUFFER_BIT); // 繪製矩形  glBegin(GL_POLYGON); glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, 0.5); glVertex2f(0.5, -0.5); glEnd(); // 執行緩衝區  glFlush(); } int main(int argc, char** argv) { // 初始化窗口 glutInit(&argc,argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("繪製矩形"); glutDisplayFunc(display); glutMainLoop(); return 0; }
複製代碼

 

  這是運行在VC6.0中的一個示例,在建立項目時須要注意建立的是控制檯項目。

  怎麼樣?main函數中的代碼你能看懂它的意思嗎?我相信對你們不是難事。下面看來簡單的解釋。

 

  (1) glutCreateWindow("繪製矩形")是建立一個標題是"繪製矩形"的窗口。

  (2) glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB)函數在上面已經說過了。

  (3) glutDisplayFunc(display); 這行代碼是將前面定義的display()函數肯定爲顯示回調函數。也就是說在窗口須要被繪製時,GLUT將會調用這個函數。好比說,當窗口第一次顯示或是窗口大小改變的時候,或是窗口從被覆蓋的狀態中恢復時,就會發生這個調用。這也是咱們放置OpenGL渲染函數調用的地方。

  (4) glutInitWindowSize(500,500)和glutInitWindowPosition(0,0)則是分別設置窗口的大小和位置。

  (5) glutMainLoop() 這個函數很重要。這個函數啓動了GLUT框架的運行。該函數一經調用便再也不返回,直到程序的結束。因此,該函數在咱們的程序中只調用一次,它能處理操做系統中特定的消息及擊鍵等事件操做,直到咱們的程序結束。

 

  以上示例的效果是在窗體中繪製一個白色的矩形,效果圖以下所示:

 

  

 

  該程序演示了在OpenGL中使用GLUT建立窗口的基本原理。

  以上即是OpenGL開發中的基本原理和基礎知識。

相關文章
相關標籤/搜索