在OpenGL中任何事物都在3D空間中,但是屏幕和窗口是一個2D像素陣列,所以OpenGL的大部分工作都是關於如何把3D坐標轉變為適應你屏幕的2D像素。3D坐標轉為2D坐標的處理過程是由OpenGL的圖形渲染管線完成的。圖像渲染管線可以被划分為兩個主要部分:第一個部分把你的3D坐標轉換為2D坐標,第二部分是把2D坐標轉變為實際的有顏色的像素。
渲染管線接收一組3D坐標,然后把它們轉變為你屏幕上的有色2D像素。渲染管線可以被划分為幾個階段,每個階段需要把前一階段的輸出作為輸入。所有這些階段都是高度專門化的,它們能簡單地並行執行。由於它們的並行執行的特征,當今大多數顯卡都有成千上萬的小處理核心GPU,在GPU上為每一個階段運行各自的小程序,從而在圖形輸送管道中快速處理你的數據。這些小程序叫做着色器。有些着色器允許開發者自己配置,用我們自己寫的着色器替換默認存在的。這樣我們就可以更細致地控制渲染管線的特定部分,因為它們運行在GPU上,所以它們也會節約寶貴的CPU時間。着色器是用OpenGL着色器語言(OpenGL Shading Language)GLSL寫成的。
下圖顯示了渲染管線中各個階段主要完成的工作,藍色部分代表的是我們可以定義自己的着色器。

在上圖中,我們以數組的形式傳遞3個3D坐標作為渲染管線的輸入,用它來表示一個三角形,這個數組叫做頂點數據(Vertex Data);這里頂點數據是幾個頂點的集合。每個頂點是用頂點屬性(vertex attributes)表示的,它可以包含任何我們希望用的數據,下面我們來看看渲染管線中各個階段主要完成的工作:
- 渲染管線的第一個部分是頂點着色器(vertex shader),它把一個單獨的頂點作為輸入。頂點着色器主要的目的是把3D坐標轉為另一種3D坐標(投影坐標),同時頂點着色器允許我們對頂點屬性進行一些基本處理。
- 圖元組裝(primitive assembly)階段把頂點着色器的表示為基本圖形的所有頂點作為輸入,把所有點組裝為特定的基本圖形的形狀;上圖中是一個三角形。
- 圖元組裝階段的輸出會傳遞給幾何着色器(geometry shader)。幾何着色器把基本圖形形成的一系列頂點的集合作為輸入,它可以通過產生新頂點構造出新的(或是其他的)基本圖形來生成其他形狀。
- 細分着色器(tessellation shaders)擁有把給定基本圖形細分為更多小基本圖形的能力。這樣我們就能在物體更接近玩家的時候通過創建更多的三角形的方式創建出更加平滑的視覺效果。
- 細分着色器的輸出會進入光柵化(rasterization)階段,這里它會把基本圖形映射為屏幕上相應的像素,生成供像素着色器(fragment shader)使用的fragment(OpenGL中的一個fragment是OpenGL渲染一個獨立像素所需的所有數據。)。在像素着色器運行之前,會執行裁切(clipping)。裁切會丟棄超出你的視圖以外的那些像素,來提升執行效率。
- 像素着色器的主要目的是計算一個像素的最終顏色,這也是OpenGL高級效果產生的地方。通常,像素着色器包含用來計算像素最終顏色的3D場景的一些數據(比如光照、陰影、光的顏色等等)。
- 在所有相應顏色值確定以后,最終它會傳到另一個階段,我們叫做alpha測試和混合(blending)階段。這個階段檢測像素的相應的深度(和stencil)值,使用這些來檢查這個像素是否在另一個物體的前面或后面,如此做到相應取舍。這個階段也會查看alpha值(alpha值是一個物體的透明度值)和物體之間的混合(blend)。所以即使在像素着色器中計算出來了一個像素所輸出的顏色,最后的像素顏色在渲染多個三角形的時候也可能完全不同。
雖然渲染管線有多個階段,每個階段都需要對應的着色器,但其實對於大多數場合,我們必須做的只是頂點和像素着色器,幾何着色器和細分着色器是可選的,通常使用默認的着色器就行了。現在的OpenGL中,我們必須定義至少一個頂點着色器和一個像素着色器(因為GPU中沒有默認的頂點/像素着色器)。
