在OpenGL中使用各異向性紋理過濾
在OpenGL中使用各異向性紋理過濾
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
1.基本的紋理過濾
紋理是資料的簡單矩陣排列——例如,顏色資料、亮度資料或者顏色和alpha(透明度)資料。紋理陣列中的每一個獨立的數值通常稱為一個紋理單元。紋理對映是一種將紋理影象應用於物體表面的技術(就是把影象貼到構成物體表面的多邊形上去),就像該影象是一種貼畫紙或玻璃紙附著於物體的表面上。
那麼什麼是紋理過濾呢?當三維空間裡面的多邊形經過座標變換、投影、光柵化等過程,變成二維螢幕上的一組象素的時候,對每個象素需要到相應紋理影象中進行取樣,這個過程就稱為紋理過濾。
紋理過濾通常分為2種情況:
a)紋理被縮小比如說一個8 x 8的紋理貼到一個平行於xy平面的正方形上,最後該正方形在螢幕上只佔4 x 4的象素矩陣,這種情況下一個象素對應著多個紋理單元。
b)紋理被放大這種情況剛好跟上面相反,假如我們放大該正方形,最後正方形在螢幕上佔了一個16 x 16的象素矩陣,這樣就變成一個紋理單元對應著多個象素。
通常的紋理過濾的方法有2種:線性過濾和三線性過濾。也可以設定不進行任何過濾操作。(OpenGL允許為上面兩種情況分別設定不同的過濾方法)
a)不進行任何過濾操作的速度最快也最簡單,只是針對每一個象素對最接近它的紋理單元進行取樣,可用於上面兩種情況。但是這種紋理過濾方法的效果最差,在螢幕顯示的影象會顯得十分模糊。
b)線性過濾也比較簡單,每個象素要對最接近它的2 x 2的紋理單元矩陣進行取樣,取4個紋理單元的平均值,也可用於上面的兩種情況。這種紋理過濾方法的效果比上面的要好很多。
c)三線性過濾相對的比較複雜,它只能用於紋理被縮小的情況,需要先構造紋理影象的mipmap,mip的意思是“在狹窄的地方里的許多東西”,mipmap就是對最初的紋理影象構造的一系列解析度減少並且預先過濾的紋理圖。對於一個8 x 8的紋理來說需要為它構造4 x 4、2 x 2、1 x 1這三個mipmap。如果正方形被縮小到在螢幕上佔6 x 6的象素矩陣,一個象素的取樣過程就變成這樣,首先是到8 x 8的紋理圖中進行對最接近它
2.各異向性紋理過濾
各異向性紋理過濾不是單獨使用而是和前面所述的其他過濾方法結合一起使用的。
假設Px為紋理在x座標方向上的縮放的比例因子;Py為紋理在y座標方向上的縮放的比例因子;Pmax為Px和Py中的最大值;Pmin為Px和Py中的最小值。當Pmax/Pmin等於1時,也就是說Px等於Py,紋理的縮放是各同向的;但是如果Pmax/Pmin不等於1而是大於1,Px不等於Py,也就是說紋理在x座標方向和在y座標方向縮放的比例不一樣,紋理的縮放是各異向的,Pmax/Pmin代表了各異向的程度。
舉個例子來說,64 x 64的紋理貼到一個開始平行於xy平面的正方形上,但是正方形繞y軸旋轉60度,最後投影到螢幕上佔了16 x 32的象素矩陣。紋理在x座標方向上縮放的比例因子為64/16等於4,在y座標方向縮放的比例因子為64/32等於2,Pmax等於4,Pmin等於2。縮放的各異向程度為2。當把各異向性過濾和線性過濾結合起來的時候,應該是對最接近象素的4 x 2的紋理單元矩陣取樣才合理,因為一個象素在x座標方向上對應了更多的紋理單元(Px > Py)。即使是紋理在一個軸方向上縮小而在另一個軸方向上放大,處理的過程也是一樣的(注意的是如果紋理在一個軸方向上縮小而在另一個軸方向上放大,OpenGL仍然把它當作是紋理被縮小的情況,將採用為紋理縮小情況設定的過濾方法為基本過濾方法,然後再加上各異向性過濾)。假設被貼圖的正方形最後在螢幕上佔了一個128 x 32 的象素矩陣,紋理在x座標方向上縮放的比例因子為64/128等於0.5,在y座標方向縮放的比例因子為64/32等於2,由於Py > Px 且 Pmax/Pmin等於4,所以當把各異向性過濾和線性過濾結合起來的時候,應該對最接近象素的2 x 8的紋理單元矩陣進行取樣。三線性過濾和各異向性過濾結合的過濾方法的步驟跟前面單獨的三線性過濾方法大致是一樣的,只是前面兩步採用了各異向性過濾和線性過濾結合的方法。
通常情況下采取線性過濾或者三線性過濾就可以得不錯的效果,但是在某些特殊的情況下,特別是把一個都是線狀條紋的紋理圖貼到一個繞x或者是y軸旋轉角度很大的多邊形上的時候,比如將人的頭髮紋理貼到構成人的頭頂的多邊形,即使是三線性過濾的效果也不能令人滿意,只有將各異向過濾方法和三線性過濾或者線性過濾的方法結合起來才能得到完美的效果。
3.怎樣在OpenGL中使用各異向性紋理過濾
在OpenGL裡面使用各異向性紋理過濾首先要系統執行的OpenGL實現支援EXT_texture_filter_anisotropic 這個OpenGL擴充套件。
OpenGL裡面的各異向性紋理過濾的引數設定是獨立於紋理縮小和放大這兩種情況的,也就是說不需要為這兩種情況進行分別設定。引數設定十分簡單,只有一個引數就是最大各異向程度(TEXTURE_MAX_ANISOTROPY_EXT)。因為紋理縮放的各異向程度越大,就需要對更多的紋理單元進行取樣,這樣在處理速度上是不可接受的,所以必須設定一個最大各異向程度,當OpenGL進行各異向性過濾的時候,採用的各異向程度引數為紋理縮放的各異向程度和最大各異向程度之間的最小值,也就是說當紋理縮放的各異向程度大於設定的最大各異向程度時,將使用設定的最大各異向程度作為過濾使用的引數。顯然可見,當該引數設定為1的時候就是不進行各異向性過濾,1也是OpenGL為這個引數設定的預設設定。另外還可以通過查詢MAX_TEXTURE_MAX_ANISOTROPY_EXT獲得該OpenGL實現支援的最大各異向程度。
下面是一段示例程式:
//假設這是一個二維紋理並且已經設定了mipmap
//獲得執行的OpenGL實現支援的最大各異向程度
Glfloat largest_supported_anisotropy;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,
&largest_supported_anisotropy);
//設定紋理縮小時採用的過濾方法,這裡設定的是三線性過濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
//設定紋理放大時採用的過濾方法,這裡設定的是線性過濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
//用OpenGL實現支援的最大各異向程度設定最大各異向程度引數
glTexParameterf(GL_TEXTURE_MAX_ANISOTROPY_EXT,
largest_supported_anisotropy);