歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

OpenGL超級寶典學習筆記——新的模式

在傳統上,圖形硬件設計的目標是快速地執行相同的硬編譯的計算指令集。計算的步驟可以被跳過,參數可以被調整,但計算本身卻是固定的。所以舊式的GPU設計被稱為是“固定功能”的。現在的趨勢是朝著通用圖形處理器的方向發展。就像CPU一樣,GPU也可以用任意的指令序列來執行圖形計算。GPU和CPU最大的區別是,GPU的浮點數計算能力更強。

在OpenGL2.0之前是固定函數渲染管線,在OpenGL2.0之後就是可編程函數渲染管線了。

 

走出舊的模式

在替換掉舊的模式之前,我們來回顧一下傳統的OpenGL渲染管線是如何運作的。在第一階段的是基於頂點操作,然後是圖元的光柵化產生片段,最後在寫到幀緩沖區前,執行片段的紋理,霧和其他的操作。如下圖,下面分別討論基於頂點和基於片段的操作。

 

固定的頂點處理

    基於頂點的階段以一系列頂點的屬性作為輸入。這些輸入包括物體空間坐標,法線,主顏色,輔助顏色,紋理坐標。最終處理輸出的結果為裁剪空間坐標,正面和背面的主顏色和輔助顏色,霧坐標,紋理坐標,以及點的大小。這個處理過程被分為四個階段。

 

頂點變換

    在傳統的固定函數管線中,頂點坐標從物體空間轉換到裁剪空間。首先乘以模型視圖矩陣轉換到視覺空間,然後再乘以投影矩陣變換到裁剪空間。與者兩個矩陣相乘是固定的程序,要“跳過”這個過程,就是把這兩個矩陣都通過glLoadIdentity設置為單位陣。這樣就不會產生影響,輸出的結果與輸入的結果相同。

    為了光照的處理,每一個頂點的法線也需要進行變換,從物體空間變換到視覺空間。法線乘以倒轉置的模型視圖矩陣,在此之後可能需要重新調整尺寸或者規格化。光照需要的法線是單位長度的,所以除非你傳入的法線是單位向量而且模型視圖矩陣不會改變它的長度,否則你需要對其調整尺寸或者規格化。

 

光照

    光照把頂點的顏色、法線和坐標作為它的原始數據輸入。它的輸出是主顏色和輔助顏色、在某些情況下正面和背面的顏色也不一樣。通過材料的屬性,光照的屬性和一些glEnable/glDisable的開關來控制這個過程。

    光照是高可配置的。我們可以開啟多個光源,每一個又可以通過大量的參數來設置器位置,顏色,類型,也可以通過材料屬性來模擬不同的表面。

      我們可以關閉光照來跳過這個階段。但只要光照被開啟了固定的方程式就會被使用。詳細的參考光照那一節。

 

紋理坐標生成與變換

    在這個階段我們可以選擇讓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語言。。。

OpenGL超級寶典 第4版 中文版PDF+英文版+源代碼 見  http://www.linuxidc.com/Linux/2013-10/91413.htm

OpenGL編程指南(原書第7版)中文掃描版PDF 下載 http://www.linuxidc.com/Linux/2012-08/67925.htm

OpenGL 渲染篇 http://www.linuxidc.com/Linux/2011-10/45756.htm

Ubuntu 13.04 安裝 OpenGL http://www.linuxidc.com/Linux/2013-05/84815.htm

OpenGL三維球體數據生成與繪制【附源碼】 http://www.linuxidc.com/Linux/2013-04/83235.htm

Ubuntu下OpenGL編程基礎解析 http://www.linuxidc.com/Linux/2013-03/81675.htm

如何在Ubuntu使用eclipse for c++配置OpenGL http://www.linuxidc.com/Linux/2012-11/74191.htm 

更多《OpenGL超級寶典學習筆記》相關知識 見 http://www.linuxidc.com/search.aspx?where=nkey&keyword=34581

Copyright © Linux教程網 All Rights Reserved