1. 程式人生 > >OpenGL之紋理過濾的四種方式

OpenGL之紋理過濾的四種方式

I.紋理過濾:

當三維空間裡面的多邊形經過座標變換、投影、光柵化等過程,變成二維螢幕上的一組象素的時候,對每個象素需要到相應紋理影象中進行取樣,這個過程就稱為紋理過濾。

II.紋理過濾通常分為2種情況:
a) 紋理被縮小 GL_TEXTURE_MIN_FILTER
比如說一個8 x 8的紋理貼到一個平行於xy平面的正方形上,最後該正方形在螢幕上只佔4 x 4的象素矩陣,這種情況下一個象素對應著多個紋理單元。
b) 紋理被放大 GL_TEXTURE_MAG_FILTER
紋理被放大這種情況剛好跟上面相反,假如我們放大該正方形,最後正方形在螢幕上佔了一個16 x 16的象素矩陣,這樣就變成一個紋理單元對應著多個象素。

III.幾種不同的紋理過濾方式:


1.最近點取樣 GL_NEAREST
2.線性紋理過濾(雙線性過濾)GL_LINEAR
3.mipmap紋理過濾(三線性過濾) GL_LINEAR_MIPMAP_LINEAR
4.各向異性過濾

a) 最近點取樣
最近點取樣,不進行任何過濾操作的速度最快也最簡單,只是針對每一個象素對最接近它的紋理單元進行取樣,可用於上面兩種情況。但是這種紋理過濾方法的效果最差,在螢幕顯示的影象會顯得十分模糊。
 

b)雙線性過濾 Bilinear Interpolation
線性過濾也比較簡單,每個象素要對最接近它的2 x 2的紋理單元矩陣進行取樣,取4個紋理單元的平均值,也可用於上面的兩種情況。這種紋理過濾方法的效果比上面的要好很多。
這是一種較好的材質影像插補的處理方式,會先找出最接近畫素的四個圖素,然後在它們之間作差補效果,最後產生的結果才會被貼到畫素的位置上,這樣不會看到“馬賽克”現象。這種處理方式較適用於有一定景深的靜態影像,不過無法提供最佳品質。其最大問題在於,當三維物體變得非常小時,一種被稱為Depth Aliasing artifacts(深度贗樣鋸齒),也不適用於移動中的物件。
 

c)三線性過濾 Trilinear Interpolation
三線性過濾相對的比較複雜,它只能用於紋理被縮小的情況,需要先構造紋理影象的mipmap,mip的意思是“在狹窄的地方里的許多東西”,mipmap就是對最初的紋理影象構造的一系列解析度減少並且預先過濾的紋理圖。對於一個8 x 8的紋理來說需要為它構造4 x 4、2 x 2、1 x 1這三個mipmap。如果正方形被縮小到在螢幕上佔6 x 6的象素矩陣,一個象素的取樣過程就變成這樣,首先是到8 x 8的紋理圖中進行對最接近它2 x 2的紋理單元矩陣進行取樣(也就是上面的線性過濾);其次是到4 x 4的紋理圖中重複上面的過程;接著把上面兩次取樣的結果進行加權平均,得到最後的取樣資料。可以看出整個過程一共進行了三次的線性過濾,所以這種方法叫做三線性過濾,它的效果是三種紋理過濾方法裡面最好的。
這是一種更復雜材質影像插補處理方式,會用到相當多的材質影像,而每張的大小恰好會是另一張的四分之一。例如有一張材質影像是512×512個圖素,第二張就會是256×256個圖素,第三張就會是128×128個圖素等等,總之最小的一張是1×1.憑藉這些多重解析度的材質影像,當遇到景深極大的場景時(如飛行模擬),就能提供高品質的貼圖效果。一個“雙線過濾”需要三次混合,而“三線過濾”就得作七次混合處理,所以每個畫素就需要多用21/3倍以上的計算時間。還需要兩倍大的儲存器時鐘頻寬。但是“三線過濾”可以提供最高的貼圖品質,會去除材質的“閃爍”效果。對於需要動態物體或景深很大的場景應用方面而言,只有“三線過濾”才能提供可接受的材質品質。

d)各向異性過濾 Anisotropic Interpolation
各向異性過濾是最新型的過濾方法,它需要對對映點周圍方形8個或更多的畫素進行取樣,獲得平均值後對映到畫素點上。對於許多3D加速卡來說,採用8個以上畫素取樣的各向異性過濾幾乎是不可能的,因為它比三線性過濾需要更多的畫素填充率。但是對於3D遊戲來說,各向異性過濾則是很重要的一個功能,因為它可以使畫面更加逼真,自然處理起來也比三線性過濾會更慢。
各異向性紋理過濾不是單獨使用而是和前面所述的其他過濾方法結合一起使用的。它在取樣時候,會取8個甚至更多的畫素來加以處理,所得到的質量最好。
假設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軸旋轉角度很大的多邊形上的時候,比如將人的頭髮紋理貼到構成人的頭頂的多邊形,即使是三線性過濾的效果也不能令人滿意,只有將各異向過濾方法和三線性過濾或者線性過濾的方法結合起來才能得到完美的效果。

  //用OpenGL實現支援的最大各異向程度設定最大各異向程度引數
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, xxx);
  // 注意:這裡的 xxx 代表 各向異性過濾 的異向程度引數
  // 你可以設定為:4 , 8 , 16 等。這裡也可以在 InitGL() 驅動 OpenGL 函式裡寫上
  int LrgSupAni;
  glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &LrgSupAni);
  那麼 xxx 就得小於或等於 LrgSupAni。