在傳統上,圖形硬件設計的目標是快速地執行相同的硬編譯的計算指令集。計算的步驟能夠被跳過,參數能夠被調整,但計算自己倒是固定的。因此舊式的GPU設計被稱爲是「固定功能」的。如今的趨勢是朝着通用圖形處理器的方向發展。就像CPU同樣,GPU也能夠用任意的指令序列來執行圖形計算。GPU和CPU最大的區別是,GPU的浮點數計算能力更強。編程
在OpenGL2.0以前是固定函數渲染管線,在OpenGL2.0以後就是可編程函數渲染管線了。函數
在替換掉舊的模式以前,咱們來回顧一下傳統的OpenGL渲染管線是如何運做的。在第一階段的是基於頂點操做,而後是圖元的光柵化產生片斷,最後在寫到幀緩衝區前,執行片斷的紋理,霧和其餘的操做。以下圖,下面分別討論基於頂點和基於片斷的操做。性能
基於頂點的階段以一系列頂點的屬性做爲輸入。這些輸入包括物體空間座標,法線,主顏色,輔助顏色,紋理座標。最終處理輸出的結果爲裁剪空間座標,正面和背面的主顏色和輔助顏色,霧座標,紋理座標,以及點的大小。這個處理過程被分爲四個階段。測試
在傳統的固定函數管線中,頂點座標從物體空間轉換到裁剪空間。首先乘以模型視圖矩陣轉換到視覺空間,而後再乘以投影矩陣變換到裁剪空間。與者兩個矩陣相乘是固定的程序,要「跳過」這個過程,就是把這兩個矩陣都經過glLoadIdentity設置爲單位陣。這樣就不會產生影響,輸出的結果與輸入的結果相同。編碼
爲了光照的處理,每個頂點的法線也須要進行變換,從物體空間變換到視覺空間。法線乘以倒轉置的模型視圖矩陣,在此以後可能須要從新調整尺寸或者規格化。光照須要的法線是單位長度的,因此除非你傳入的法線是單位向量並且模型視圖矩陣不會改變它的長度,不然你須要對其調整尺寸或者規格化。spa
光照把頂點的顏色、法線和座標做爲它的原始數據輸入。它的輸出是主顏色和輔助顏色、在某些狀況下正面和背面的顏色也不同。經過材料的屬性,光照的屬性和一些glEnable/glDisable的開關來控制這個過程。.net
光照是高可配置的。咱們能夠開啓多個光源,每個又能夠經過大量的參數來設置器位置,顏色,類型,也能夠經過材料屬性來模擬不一樣的表面。設計
咱們能夠關閉光照來跳過這個階段。但只要光照被開啓了固定的方程式就會被使用。詳細的參考光照那一節。索引
在這個階段咱們能夠選擇讓OpenGL爲咱們生成紋理座標。有幾種生成公式能夠選擇。咱們能夠爲每一個紋理座標成分選擇不一樣的生成方式。若是關閉紋理自動生成,那麼手工附加在頂點上的紋理座標將其做用。隨後紋理座標會通過紋理矩陣的變換。若是紋理矩陣是單位陣則紋理座標不會改變。圖片
若是通過上面的變換以後,頂點落在了可視區域以外,則將被裁剪掉。被裁減掉的頂點將被丟棄,而後根據圖元的類型生成與裁剪邊緣相交的頂點。顏色、紋理座標和其餘的頂點屬性將經過插值的方式從新賦予到新的頂點上。
在這個階段把片斷和關聯的數據做爲輸入。這些關聯的數據由插值後的線和三角形,一個或多個紋理座標,主顏色和輔助顏色,霧座標組成。每一個片斷處理後的結果是單一的顏色值,而後被傳送到隨後的深度測試,alpha混合,模板測試等操做中。這個階段也被分爲四個部分。
紋理應用是最重要的片斷操做。在這裏你把全部片斷的紋理座標和它的主顏色做爲輸入,輸出是一個新的主顏色。這個過程將受啓用那個紋理單元,紋理單元綁定的是什麼圖片,以及紋理環境。
對於每一個被啓用的紋理單位,綁定到這個單位的1D、2D、3D或立方體貼圖紋理做爲紋理查找的來源。基於單元上的紋理格式和指定的紋理函數,查找出來的紋理結果將替換或者與片斷的主顏色進行混合。
有許多的可配置的參數影響着紋理的查找,例如紋理的環繞模式,邊界顏色,過濾器,mipmap,深度紋理等。
顏色求和階段有兩個輸入:主顏色和輔助顏色,輸出是單一的顏色。若是啓用了顏色求和或者啓用了光照,那麼主顏色和輔助顏色的紅、綠、藍成分將會相加,而後截取在範圍[0,1]。若是顏色求和未被啓用,那麼主顏色及其alpha值將直接輸出,輔助顏色值和alpha值將不會被使用。
若是開啓了霧。那麼片斷的顏色將會和霧的顏色進行混合。霧顏色取決於霧因子以及三個硬編碼的公式:線性的,指數的,二次指數的。這些公式根據當前霧座標和霧因子來計算出霧顏色。
最後,若是片斷所屬的圖元開啓了反走樣例如glEnable(GL_LINE_SMOOTH)等。那麼會有一段關聯的數據是覆蓋值。這個值一般是1.0。但在光滑的點,線,面,這個覆蓋值是0.0到1.0之間,片斷的alpah值和這些覆蓋值相乘,而後進行混合來產生光滑的邊緣。
自OpenGL2.0以後就引入了新的方式來替換就到固定函數管道——着色器。着色器其實就是一段自定義的程序來替換掉固定函數管道的各階段。
下圖是用新的可編程的着色器替換掉硬編碼的固定階段。
如今頂點以及頂點的屬性將做爲頂點着色器的輸入。頂點着色器產生紋理座標,顏色,點的大小,霧座標,而後傳到裁剪器中。一個頂點着色器替換掉了固定的頂點變換,光照,紋理座標處理。
頂點的變換將再也不是固定的函數,要作什麼徹底取決於你。你能夠什麼都不作不輸出任何東西(也不會畫任何東西),若是要畫物體,那麼最小的操做是輸出裁剪座標。一般狀況下,模擬固定的函數管道的話,咱們會把頂點乘以投影矩陣和模型視圖矩陣。但這些不是必須的,若是你輸入的已是計算好的裁剪座標,那麼咱們就不須要執行這些操做,把輸入位置拷貝到輸出位置就好了。咱們也能夠在這裏把笛卡爾座標轉換成極座標,而後進行計算。
若是你並不關心頂點的顏色屬性(例如你只須要這些頂點作遮擋查詢)那麼你能夠不進行光照計算的步驟,不輸出任何顏色,在此以後都不使用這些數據(PS:若是後面使用到了這些數據,則行爲是未定義的,由於是垃圾數據)。 若是顏色不須要光照計算,咱們能夠直接把輸入的顏色拷貝到輸出的顏色。
在這裏也能夠有無窮多種方式進行顏色的變換,這取決於你的程序。
若是不須要生成紋理座標,則不用再頂點着色器對紋理座標進行編程。 若是不須要進行任何紋理座標的變換,那能夠把輸入的紋理座標拷貝到輸出的部分。這個過程能夠儘可能的精簡,不浪費資源去作無用功。例如 你的GPU支持8個紋理座標,但再後面的管道中,你只用到其中三個,但咱們就不必輸出另外的五個。
通過上面的介紹,大概瞭解了,頂點着色器的輸入和輸出,以及其中的處理環節。頂點着色器與固定函數管道相比,提供了極大的靈活性,經過良好的着色器編程,咱們能夠節省資源,提升性能,並獲得咱們想要的效果。
在頂點着色器和片斷着色器之間,還有一組固定的功能階段,來鏈接着兩個着色器。在執行頂點着色器以後,須要對其輸出進行裁剪,在裁剪的過程當中,去移除在可視區域以外的頂點,並添加一些頂點。而後進行透視除法,把座標變成規格化座標,而後進行視口變換和深度範圍的變換,最後產出屏幕空間的座標。而後進行光柵化。
光柵化是一個固定的階段,把處理後的圖元上的頂點光柵化成片斷。不管點,線或多邊形圖元都會在這個階段產出片斷,並插入合適的顏色和紋理座標到片斷中。
在高度分挌化的物體中,能夠一個小三角形會被映射爲一個片斷。在絕大多數狀況下,片斷數老是比頂點數多的。但凡事都有例外。光柵化也負責製造有寬度的線和點。它也會應用線和點的點畫(stipple)模式。它還負責爲光滑的點,線和多邊形產生邊緣的覆蓋值,這些覆蓋在後面片斷着色器的alpha混合中會用到。若是須要,光柵化器會裁剪正面或者反面的多邊形,應用多邊形偏移。
除了點,線,面,光柵化也負責產生位圖和像素矩形(使用glDrawPixels繪製的)的片斷。
與固定功能管線相同的,霧座標,紋理座標和顏色可用於片斷着色器。最後輸出單一的顏色與先前的固定函數管線的霧階段輸出相同。在片斷着色器,咱們能夠選擇本身的方法來處理這些片斷。
紋理查找是片斷着色器中一項重要的功能。絕大部分與固定函數的方式相同,在紋理着色器外,設置紋理的狀態和紋理環境,以及紋理的圖片。主要的不一樣是,你能夠在着色器中決定什麼時候、是否執行紋理查找,以及紋理座標如何使用。
第1個紋理座標不必定用於索引第1個紋理圖片。你能夠在不一樣的紋理中使用同一個紋理座標,也能夠在同一個紋理中使用不一樣的紋理座標。甚至,你能夠在運行時去計算紋理座標。這種靈活性在固定函數的方式是不可能實現的。
在以前的固定函數的方式中,紋理環境的設置中包含了一項決定如何進行片斷的顏色和紋理查找結果混合。如(glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV, GL_DECAL))。這個在片斷着色器中被忽略了。如何進行混合徹底取決於你的片斷着色器的操做。固然片斷着色器也能夠不作事情,只是簡單的把輸入的主顏色拷貝到輸出的顏色中。
這個階段的處理很是簡單,僅僅是把主顏色和輔助顏色相加。若是咱們不使用輔助顏色,就直接忽略它。
霧的應用也是簡單的。首先咱們根據公式用霧座標和霧濃度的常量來計算霧因子。在固定的函數管線中,有幾個固定編碼的方程式,線性的,指數的,二次指數的方程。但在着色器中你能夠編寫本身的方程式來計算霧因子。若是咱們不使用霧,那咱們就不須要在着色器中添加任何關於霧的指令。
OpenGL着色器語言的簡單的例子
頂點着色器:
void main(void)
{
//輸入的頂點執行變換,變換到裁剪座標
vec4 clipCoord = gl_ModelViewProjectionMatrix * gl_Vertex;
//複製到輸出的位置
gl_Position = clipCoord;
//複製主顏色
gl_FrontColor = gl_Color;
vec3 ndc = clipCoord.xyz / clipCoord.w;
// 輸出前把[-1,1]映射到[0,1]
gl_SecondaryColor = (ndc * 0.5) + 0.5;
}
片斷着色器
void main(void)
{
//混合主顏色和輔助顏色
gl_FragColor = mix(gl_Color, vec4(vec3(gl_SecondaryColor), 1.0), 0.5);
}
上面的着色器簡單的模擬了一些固定函數管道的一些功能。其中以gl_爲前綴的是GLSL內置的變量。其中gl_Vertex表明輸入的頂點,gl_ModelViewProjectionMatrix是模型視圖矩陣和投影矩陣的結合,咱們用gl_ModelViewProjectionMatrix * gl_Vertex; 就能夠獲得裁剪的座標了。 gl_Position是輸出的頂點的位置。 gl_Color在頂點着色器和片斷着色器中有着不一樣的含義。在頂點着色器中gl_Color表明着用戶的輸入,即經過glColor等方式的輸入。而在片斷着色器中的gl_Color表明通過插值的片斷的顏色。
在編寫完上面兩個着色器,並編譯鏈接應用後,每一個頂點及其附屬的屬性都會通過頂點着色器的處理器,而後裁剪,光柵化成片斷,而後片斷再通過片斷着色器的處理。
後面再詳細介紹GLSL語言。。。