2.1.1 頂點:3D圖形的基礎
OpenGL中的基本單元是頂點。簡單來說,頂點就是空間中的一個點。在這些點上可以附加其他信息,如它如何映射到紋理,是否具有一定的重量或顏色等,但是最重要的信息是它的位置。
遊戲會把大量的時間用於發送OpenGL頂點,或者告訴OpenGL以特定的方式移動頂點等。遊戲可能首先告訴OpenGL它將要發送的全部頂點會構成三角形。此時,OpenGL將使用線把它收到的每三個頂點連接起來以創建一個多邊形,然後可能還會使用紋理或顏色填充多邊形的表面。
現代圖形硬件非常擅長處理大量的頂點,把它們構成多邊形,然後渲染到屏幕上。這個從頂點到屏幕的過程叫做流水線(pipeline)。流水線負責定位頂點和提供光照,以及進行投影變換。這個過程將把收到的3D數據變換爲2D數據,以便將其顯示到屏幕上。投影變換聽起來有點複雜,但是幾個世紀以來,畫家和藝術家們一直在利用這種變換,在平展的畫布上繪製出他們周圍的世界。
2.1.2 流水線
流水線的流程如圖2-3所示。這個流水線叫做固定功能流水線(fixed function pipeline)。當程序員爲這種流水線提供輸入後,所有的功能已被固定,無法修改。例如,在像素處理階段很容易向屏幕上添加藍色調,但是在固定功能流水線中,程序員無法直接控制這個階段。
圖2-3 基本的固定功能流水線 |
固定功能流水線包含6個主要的階段。這些階段幾乎都可以並行應用。如果硬件支持的話,每個頂點可以同時經過同一個階段。由於這個原因,圖形卡的處理速度比CPU的處理速度要快得多。
輸入階段。輸入以頂點的形式給出,頂點的屬性包括位置、顏色和紋理數據。
變換和光照。根據當前視圖變換頂點。這包括將頂點的位置由3D空間(也叫做世界空間)改爲2D空間(也叫做屏幕空間)。如果有些頂點對最終的顯示沒有影響,可以在這個階段移除它們。在這個階段也可以對每個頂點執行光照計算。
創建圖元。這是使用頂點信息創建多邊形的過程,需要根據OpenGL的狀態把頂點連接到一起。遊戲經常使用三角形或者三角帶作爲圖元。
光柵化。這是將多邊形轉換爲像素(也叫做片段)的過程。
像素處理。像素處理也叫做片段處理。這個階段將測試像素,以確定是否把它們繪製到幀緩衝區中。
幀緩衝區。幀緩衝區是一塊內存,代表特定的幀將顯示在屏幕上的部分。混合設置將決定像素如何與已經繪製的部分進行混合。
使用程序控制流水線了。將程序上傳到圖形卡以後,它們將替換固定功能流水線的默認階段。重寫流水線的特定部分的小程序叫做着色器(shader)。
圖2-4顯示了可編程流水線的階段。這裏刪除了變換和光照階段,添加了頂點和幾何着色器。像素處理階段也可以像像素着色器那樣進行編程。通過流水線的每個像素都會被應用像素着色器。像素着色器不能添加頂點,但是可以修改位置、顏色和紋理位置等屬性。
圖2-4 |
與像素着色器和頂點着色器相比,幾何着色器加入的時間較晚。幾何着色器以一個完整的圖元(如線、點或三角形組成的帶)作爲輸入,而頂點着色器針對每個圖元都會運行。幾何着色器可以創建新的頂點信息、點、線,甚至圖元。幾何着色器還可用於創建點精靈和動態鑲嵌,以及實現其他一些效果。點精靈可以快速渲染大量精靈,這種技術經常用於粒子系統,可創建類似於火焰或者煙霧效果。動態鑲嵌可以在幾何形狀中添加更多的多邊形。這種技術可以用來增加包含多邊形數較少的遊戲模型的平滑度,並在攝像機放大模型時展現更多的細節。
像素着色器會應用到被髮送到幀緩衝區的每個像素。像素着色器用於創建凹凸貼圖效果、鏡面高光和逐像素光照。凹凸貼圖效果可以給表面增加額外的高度信息。凹凸貼圖通常包含一個圖片,其中每個像素代表一個標準的法向量,該法向量描述瞭如何扭曲表面。像素着色器可以使用凹凸貼圖來爲模型提供一個更有趣的紋理,使其看上去有一定的深度感。逐像素光照用於替換OpenGL的默認的光照公式。OpenGL的光照公式可計算出每個頂點的光照,然後爲該頂點提供一種合適的顏色。逐像素光照使用更精確的光照模型,爲每個像素單獨應用光照。鏡面高光是模型中非常亮、反射大量光的區域。
2.2 變化中的OpenGL
現在是學習OpenGL的大好時機。OpenGL的當前版本非常適合學習。這個版本中包含了大量易於使用的函數,可以完成各種各樣與圖形處理有關的工作。可以把OpenGL的當前版本想象成一個帶有輔助輪的自行車,剛開始時藉助它們學習怎麼騎車,熟練之後就把它們取下來。OpenGL的下一個版本更像是一個性能強大的摩托車,沒有必要的東西都被移除了,剩下的就是不受限制的原始力量。對於有經驗的OpenGL程序員,其好處自不必言,但是初學者卻容易對其望而生畏。
可以使用的OpenGL版本要取決於系統中安裝的圖形卡驅動程序。幾乎每臺計算機都支持OpenGL 2.1,而近期生產的圖形卡會支持OpenGL 3.x。
2.2.1 OpenGL ES
OpenGL ES是用於嵌入式系統的OpenGL的新版本。它與OpenGL的近期版本相似,但是功能集更加受限。它用於高端手機,例如Android、BlackBerry和iPhone。OpenGL ES也用於軍用硬件,例如戰機上的平視顯示器。
OpenGL ES支持可編程流水線,也支持着色器。
2.2.2 WebGL
WebGL目前仍處於開發中,這個版本的OpenGL是專爲在Web上使用而設計的。使用WebGL的瀏覽器必須支持HTML 5 canvas標籤。就現在而言,還無法知道它會取得多大的成功。以前人們曾有過在Web上使用3D的嘗試,但是都失敗了。例如,VRML(Virtual Reality Modeling Language,虛擬現實建模語言)與HTML類似,但是允許用戶創建3D世界,它在學術界受到了不少關注,卻從沒有吸引過普通的用戶。
WebGL有一些強有力的支持者,許多大公司都加入了WebGL工作組,如Google、Apple和Mozilla,而且WebGL還有一些讓人印象非常深刻的演示。就目前來看,WebGL的性能還是不錯的,在成熟以後很可能可以與Flash一較高低。
2.3 OpenGL和圖形卡
OpenGL是一個允許程序員發送指令到圖形卡的庫。圖形卡是一種專用於顯示3D數據的硬件,由很多標準組件構成,包括幀緩衝區、紋理內存和GPU。GPU是圖形處理單元(Graphics Processing Unit)的縮寫,它控制着如何處理頂點並把它們顯示到屏幕上。CPU向GPU發送指令和數據,描述每一幀應該怎樣顯示到屏幕上。紋理內存通常是一塊較大的內存,用於存儲遊戲所需的大量紋理。幀緩衝區是內存中的一塊區域,存儲下一幀中將顯示到屏幕上的圖像。現代的圖形卡通常有多個GPU,每個GPU上都有許多着色器處理單元來執行大規模的並行着色器操作。分佈式應用程序(如模擬蛋白質摺疊的Folding@home)和世界各地的數十萬臺計算機都利用了這一特點。
第一個獲得流行的3D圖形卡是3dfx Voodoo 1。這是早期的一個圖形卡,有2MB的紋理內存和2MB的幀緩衝區,並且使用PCI總線,時鐘速度爲135MHz。早期的一些遊戲使用它來加速執行,例如《古墓麗影(Tomb Raider)》、Descent II、《雷神之錘(Quake)》以及《雷神之錘2(Quake 2)》的演示,從而運行得更加流暢,並且可顯示更多的細節。Voodoo 1使用一個標準的PCI總線,允許CPU以最高533MB/s的速度向圖形卡發送數據。現代的圖形卡已經從PCI轉向使用AGP(Accelerated Graphics Port,加速圖形端口),其最高數據發送速度爲2GB/s,後來又轉向使用PCI Express。當前的這一代PCI Express卡的最高數據發送速度爲8GB/s。
好像每個月都會有新的圖形卡問世,每個新圖形卡都比之前的圖形卡更快。在編寫本書時,最快的圖形卡可能是ATI Radeon HD 5970。它有兩個GPU,每個GPU都有1600個着色器處理器。它的時鐘速度爲725MHz,每秒可以處理4.64萬億次浮點運算。
大多數現代圖形卡都有專門執行新操作的特殊硬件。這種硬件通過使用擴展提供給OpenGL。當收到一個標識新擴展的字符串時,OpenGL能夠展示驅動程序和圖形卡中的功能。例如,ATI Radeon HD 5970有兩個GPU,這種情況很少見。爲了能夠充分利用兩個GPU,需要使用一些新的擴展方法,如AMD_gpu_association。這個擴展允許用戶在兩個GPU之間分配任務。如果多家供應商實現了相同的擴展,那麼擴展字符串的某個位置會有字母EXT。有時候,控制OpenGL規範的架構評審委員會可能會把某個擴展的狀態提升爲官方擴展,此時,擴展字符串中將包含字母ARB,所有的供應商都必須支持該擴展。
着色器--圖形卡上的程序
着色器(shader)這個詞帶有一定的誤導性。最初的着色器程序主要用於處理組成每個多邊形表面的像素,以便爲模型着色。但是隨着時間推移,着色器程序的功能已經被擴展,現在還可以修改頂點屬性、創建新頂點,甚至完成一般的操作。
着色器與運行在CPU上的普通程序具有不同的工作方式。着色器程序在大量的元件上同時執行,這意味着着色器程序是大規模並行程序,而運行在CPU上的程序一般則是串行運行的,一次只有一個實例運行。着色器程序非常適合對構成3D世界的像素和頂點的集合執行操作。
目前共有3類着色器,分別是頂點着色器、幾何着色器和像素着色器,每種着色器都只能執行特定的操作。頂點着色器處理頂點,像素着色器處理像素,幾何着色器處理圖元。爲了降低複雜性,並使硬件製造商可以更高效地進行優化,所有這些着色器都被一種叫統一着色器(unified shader)的着色器替代了。
着色器通過運行在圖形卡上的特殊語言進行編程。目前,這些語言比C++低級得多(更別提C#了)。OpenGL有一門叫做GLSL(OpenGL Shading Language,OpenGL着色語言)的着色語言,它與C語言有些類似,但是有大量用於處理向量和矩陣的特殊操作。DirectX也有自己的着色語言,叫做HLSL(High Level Shading Language,高級着色語言)。兩種語言十分類似。讓人更加困惑的是,除了這兩種語言以外,還有一種叫做Cg的語言,它由Microsoft和Nvidia開發,與HLSL有些類似。
遊戲中的着色器非常適合創建需要進行大量計算的特殊效果,如視差貼圖的光照。當前的技術使得着色器程序幾乎不能用於其他用途。本書主要介紹遊戲編程,由於可編程流水線是一個很大的主題,所以不會討論該技術。如果對此主題感興趣,可以參閱附錄A部分,那裏介紹了幾本非常好的書籍。
着色器的一種趨勢是用於一般性的並行編程任務,而不只是處理圖形。例如,Nvidia PhysX庫允許在GPU而非CPU上完成物理計算,從而得到更佳的性能。PhysX是用另外一種叫做CUDA的着色器語言編寫的,但是CUDA與其他着色器語言有一些不同,這種語言不怎麼關注像素和頂點,而是更關注一般目的的並行編程。假設在遊戲中要模擬一個城市,並且有一個非常新奇的並行算法可以更新城市中的全部居民,那麼這種計算在GPU上可以更快地執行,而CPU就可以被解放出來,執行其他任務。CUDA通常用於科學研究項目,因爲這是利用強大的計算能力的一種廉價的方式。使用CUDA的應用程序包括量子化學計算、心肌模擬和黑洞建模。
2.4 Tao框架
Tao框架是C#使用OpenGL庫的一種方式。Tao包裝了許多C庫(見表2-1),並使得在C#中使用這些函數變得很簡單。Tao中還綁定了Mono,所以也可以用在Linux和Mac中。
通過Tao,C#不只可以使用OpenGL,還可以使用其他一些有用的庫。
表2-1 Tao框架中包含的庫
庫 |
用途 |
Tao.OpenAl |
OpenAL是一個強大的音頻庫 |
Tao.OpenGl |
OpenGL是我們將要使用的圖形庫 |
Tao.Sdl |
SDL(Simple DirectMedia Layer),一個 構建在OpenGL之上的2D庫 |
Tao.Platform.Windows |
支持通過Windows.Forms使用OpenGL |
Tao.PhysFs |
一個I/O的包裝器,支持遊戲資源的存檔文件,如.zip文件 |
Tao.FreeGlut |
OpenGL實用程序工具包(OpenGL Utility Toolkit)是一組包裝器,用於設置OpenGL 程序和一些繪圖例程 |
Tao.Ode |
Open Dynamics Engine是在遊戲中使用的 一個實時物理引擎 |
Tao.Glfw |
OpenGL Framework是一個可以在多個平臺 上使用的輕量級的包裝器類 |
(續表)
庫 |
用途 |
Tao.DevIL |
DevIL是將各種圖片類型(bmp、tif、gif、 png等)加載到OpenGL的出色的工具 |
Tao.Cg |
Cg是一種高級着色語言 |
Tao.Lua |
Lua是遊戲業最常用的腳本語言之一 |
Tao.FreeType |
字體包 |
Tao.FFmpeg |
主要用於播放視頻 |
OpenAL代表開放音頻庫(Open Audio Library),是一個強大的開源庫。《生化奇兵(BioShock)》、《雷神之錘4(Quake 4)》、《毀滅戰士3(Doom III)》和《虛幻(Unreal)》等遊戲都使用了這個音頻庫。它採用OpenGL作爲模型,具有相同的狀態機風格的設計和擴展方法。
SDL(Simple DirectMedia Layer)是一個跨平臺的庫,支持輸入、聲音和圖形。SDL在遊戲開發商中非常流行,在獨立或者開源遊戲中使用得尤其多。使用SDL開發的最著名的開源遊戲之一是FreeCiv,它是《文明(Civilization)》的一個聯機版本。多數Linux遊戲端口中也使用了SDL。
PhysFs初看起來可能是一個物理庫,但是實際上卻是一個小型的IO庫。它可以將全部遊戲資源打包爲一個較大的二進制文件,或者幾個小的二進制文件。許多商業遊戲都有類似的系統,例如《毀滅戰士(Doom)》的wad系統或《雷神之錘(Quake)》的pak系統。它可以使遊戲在發佈後的修改和更新變得更加簡單。
FreeGLUT是OpenGL實用程序工具包的免費版本。這個庫中的函數可以讓用戶馬上就能夠使用OpenGL。它還有從鍵盤和鼠標接受輸入的方法,以及繪製各種基本形狀的方法,例如球形、立方形,甚至茶壺形(這個茶壺在計算機圖形學中非常有名,它是由Martin Newell在猶他大學求學期間進行建模的。茶壺是一個非常複雜的表面,所以在測試新的圖形技術時非常有用。動畫電影《玩具總動員》中就有一個典型的茶壺模型,DirectX甚至有自己的茶壺創建方法D3DXCreateTeapot( )。在講授OpenGL時經常用到FreeGLUT,但是它的功能很有限,很少用於真正的項目。
ODE(Open Dynamics Engine)是一個可以用在多個平臺上的物理引擎,可以完成碰撞檢測和剛體模擬。PC上的第一人稱射擊遊戲《潛行者(S.T.A.L.K.E.R)》中就使用了ODE。Glfw是可以通過Tao使用的第三個可移植的OpenGL包裝器。Glfw代表OpenGL框架(OpenGL framework),它的目的是擴展GLUT提供的功能。如果不想使用SDL,但又確實想使用框架來訪問OpenGL,就可以考慮使用Glfw。
DevIL(Developer's Image Library)是一個從磁盤加載紋理到OpenGL中的庫。DevIL與OpenGL有些類似,因爲它也是一個狀態機,並且有類似的方法名稱。DevIL是跨平臺的,支持多種(43種)不同的圖片格式。Cg是本章前面提到的一種着色器語言。通過使用Tao.Cg,可以從文本文件或字符串中加載着色器程序,進行處理,然後在OpenGL中使用。
Lua可能是遊戲開發中最流行的腳本語言。它是一種小型的、易於嵌入的語言,表達力非常強。使用Tao.Lua可以在腳本和C#程序之間傳遞函數和數據。Tao.FreeType是一個基本的字體包,可以將FreeType類型的字體轉換成一幅位圖。它的接口簡單易用。
Tao提供的最後一個庫是FFmpeg,這個名稱由MPEG(一個視頻標準)和FF(Fast Forward,快進)組成。它提供了一種播放視頻的方式。如果想要在遊戲中使用過場動畫,FFmpeg是一個不錯的選擇。
Tao提供的所有庫都是完全開源的。其中的多數庫都可以免費用在商業項目中,但還是有必要閱讀許可證中列出的具體說明。Tao是一個出色的程序包,剛開始涉足遊戲的開發商可以把它作爲一個起點。對每個庫的介紹不在本書的討論範圍之內,我們將只關注其中最重要的那些庫。從第5章開始,我們將使用OpenGL和Tao.Platform.Windows庫。第6章將討論DevIL。第9章將討論使用OpenAL播放聲音,以及使用SDL處理手柄輸入。每個庫都很有用,所以很有必要花些時間研究每個感興趣的庫。