本文主要整理簡紹來自互聯網的各項異性濾波的知識。
原文鏈接:http://www.linuxgraphics.cn/graphics/using_anisotropic_texture_filtering_in_opengl.html
主要的紋理過濾
紋理是數據的簡單矩陣排列——比如。顏色數據、亮度數據或者顏色和alpha(透明度)數據。紋理數組中的每個獨立的數值通常稱為一個紋理單元。
紋理映射是一種將紋理圖像應用於物體表面的技術(就是把圖像貼到構成物體表面的多邊形上去),就像該圖像是一種貼畫紙或玻璃紙附着於物體的表面上。
那么什么是紋理過濾呢?當三維空間里面的多邊形經過坐標變換、投影、光柵化等過程,變成二維屏幕上的一組象素的時候。對每一個象素須要到對應紋理圖像中進行採樣,這個過程就稱為紋理過濾。
紋理過濾通常分為2種情況:
- 紋理被縮小。比方說一個8 x 8的紋理貼到一個平行於xy平面的正方形上,最后該正方形在屏幕上僅僅占4 x 4的象素矩陣,這樣的情況下一個象素相應着多個紋理單元。
- 紋理被放大。
這樣的情況剛好跟上面相反。假如我們放大該正方形,最后正方形在屏幕上占了一個16 x 16的象素矩陣,這樣就變成一個紋理單元相應着多個象素。
通常的紋理過濾的方法有2種:線性過濾和三線性過濾。也能夠設置不進行不論什么過濾操作。(OpenGL同意為上面兩種情況分別設置不同的過濾方法)
- 不進行不論什么過濾操作的速度最快也最簡單。僅僅是針對每個象素對最接近它的紋理單元進行採樣。可用於上面兩種情況。
可是這樣的紋理過濾方法的效果最差,在屏幕顯示的圖像會顯得十分模糊。
- 線性過濾也比較簡單。每個象素要對最接近它的2 x 2的紋理單元矩陣進行採樣,取4個紋理單元的平均值。也可用於上面的兩種情況。這樣的紋理過濾方法的效果比上面的要好非常多。
- 三線性過濾相對的比較復雜,它僅僅能用於紋理被縮小的情況,須要先構造紋理圖像的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的紋理圖中反復上面的過程;接着把上面兩次採樣的結果進行加權平均,得到最后的採樣數據。能夠看出整個過程一共進行了三次的線性過濾。所以這樣的方法叫做三線性過濾,它的效果是三種紋理過濾方法里面最好的。
各異向性紋理過濾
各異向性紋理過濾不是單獨使用而是和前面所述的其它過濾方法結合一起使用的。
如果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中使用各異向性紋理過濾
在OpenGL里面使用各異向性紋理過濾首先要系統執行的OpenGL實現支持EXT_texture_filter_anisotropic 這個OpenGL擴展。
OpenGL里面的各異向性紋理過濾的參數設置是獨立於紋理縮小和放大這兩種情況的。也就是說不須要為這兩種情況進行分別設置。參數設置十分簡單,僅僅有一個參數就是最大各異向程度(TEXTURE_MAX_ANISOTROPY_EXT)。由於紋理縮放的各異向程度越大,就須要對很多其它的紋理單元進行採樣,這樣在處理速度上是不可接受的,所以必須設置一個最大各異向程度。當OpenGL進行各異向性過濾的時候,採用的各異向程度參數為紋理縮放的各異向程度和最大各異向程度之間的最小值。也就是說當紋理縮放的各異向程度大於設置的最大各異向程度時。將使用設置的最大各異向程度作為過濾使用的參數。
顯然可見,當該參數設置為1的時候就是不進行各異向性過濾。1也是OpenGL為這個參數設定的缺省設置。另外還能夠通過查詢MAX_TEXTURE_MAX_ANISOTROPY_EXT獲得該OpenGL實現支持的最大各異向程度。
以下是使用各異向性紋理過濾的演示樣例代碼:
glGenTextures(1, &texture_id));
glBindTexture(GL_TEXTURE_2D, texture_id);
//Create a 2D texture with Mipmap
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, m_width, m_height, GL_RGB, GL_UNSIGNED_BYTE, image_data);
//獲得執行的 Opengl 實現支持的最大各異向程度.
GLfloat largest_supported_anisotropic;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropic);
//設置紋理縮小時採用的過濾方法。這里設置的是三線性過濾
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_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropic);
各向異性過濾讓表面傾斜物體紋理更加清晰銳利同一時候看上去非常密集。透明度又讓密集的紋理變得模糊平緩。
傳統的雙線性和三線性過濾技術都是指“Isotropy”(各向同性)的,其各方向上矢量值是一致的,就像正方形和正方體。三線性過濾原理同雙線性過濾一樣。都是是將相鄰像素及彼此之間的相對關系都記憶下來。然后在視角改變的時候繪制出來。
僅僅只是三線性過濾的採集范圍更大。計算更精確,畫面更細膩。
這就須要一個“非正多邊形”的過濾單元。來保證准確的透視關系和透明度。不然,假設在某個軸上的紋理部分有大量信息。或是某個方向上的圖象和紋理有個傾角,那么得到的終於紋理就會變得非常滑稽,比例也會失調。當視角為90度,或是處理物體邊緣紋理時。情況會更糟。
1、 為什么在紋理採樣時須要texture filter(紋理過濾)。
我們的紋理是要貼到三維圖形表面的,而三維圖形上的pixel中心和紋理上的texel中心並不一至(pixel不一定相應texture上的採樣中心texel)。大小也不一定一至。
當紋理大於三維圖形表面時,導至一個像素被映射到很多紋理像素上;當維理小於三維圖形表面時。很多個象素都映射到同一紋理。
當這些情況發生時,貼圖就會變得模糊或發生錯位,馬賽克。要解決此類問題。必須通過技術平滑texel和pixel之間的相應。
這樣的技術就是紋理濾波。
不同的過濾模式。計算復雜度不一樣,會得到不同的效果。過濾模式由簡單到復雜包含:Nearest Point Sampling(近期點採樣)。Bilinear(雙線性過濾)、Trilinear(三線性過濾)、Anisotropic Filtering(各向異性過濾)。
在了解這些之前,有必要了解什么是MipMap和什么時各向同性。各向異性。
2、 什么是MipMap?
Mipmap由Lance Williams 在1983的一篇文章“Pyramidal parametrics”中提出。Wiki中有非常具體的介紹( http://en.wikipedia.org/wiki/Mipmap ) . 比方一張256X256的圖,在長和寬方向每次降低一倍,生成:128X128,64X64,32X32,16X16,8X8,4X4,2X2,1X1。八張圖,組成MipMap,例如以下圖示。
Mipmap早已被硬件支持,硬件會自己主動為創建的Texture生成mipmap的各級。在D3D的API:CreateTexture中有一個參數levels,就是用於指定生成mipmap到哪個級別,當不指定時就一直生成到1X1。
3、 什么是各向同性和各向異性?
當須要貼圖的三維表面平行於屏幕(viewport),則是各向同性的。當要貼圖的三維表面與屏幕有一定角度的傾斜,則是各向異性的。
也能夠這樣理解。當一個texture貼到三維表面上從Camera看來沒有變形。投射到屏幕空間中后U方向和V方向比例仍然是一樣的,便能夠理解成各向同性。
反之則覺得是各向異性。
4、 Nearest Point Sampling(近期點採樣)
這個最簡單,每一個像素的紋理坐標,並非剛好相應Texture上的一個採樣點texel。怎么辦呢?近期點採樣取最接近的texel進行採樣。
當紋理的大小與貼圖的三維圖形的大小幾乎相同時,這樣的方法很有效和快捷。假設大小不同,紋理就須要進行放大或縮小。這樣,結果就會變得矮胖、變形或模糊。
5、 Bilinear(雙線性過濾)
雙線性過濾以pixel相應的紋理坐標為中心,採該紋理坐標周圍4個texel的像素,再取平均,以平均值作為採樣值。
雙線性過濾像素之間的過渡更加平滑,可是它僅僅作用於一個MipMap Level,它選取texel和pixel之間大小最接近的那一層MipMap進行採樣。當和pixel大小匹配的texel大小在兩層Mipmap level之間時,雙線性過濾在有些情況效果就不太好。於是就有了三線性過濾。
6、 Trilinear(三線性過濾)
三線性過濾以雙線性過濾為基礎。會對pixel大小與texel大小最接近的兩層Mipmap level分別進行雙線性過濾,然后再對兩層得到的結果進生線性插值。
三線性過濾在普通情況下效果很理想了。可是到眼下為止,我們均是如果是texture投射到屏幕空間是各向同性的。可是當各向異性的情況時,效果仍然不理想。於是產生了Anisotropic Filtering(各向異性過濾)。
7、 Anisotropic Filtering(各向異性過濾)
各向同性的過濾在採樣的時候。是對正方形區域里行採樣。
各向異性過濾把紋理與屏幕空間的角度這個因素考慮時去。簡單地說,它會考濾一個pixel(x:y=1:1)相應到紋理空間中在u和v方向上u和v的比例關系,當u:v不是1:1時,將會按比例在各方向上採樣不同數量的點來計算終於的結果(這時採樣就有可能是長方形區域)。
我們一般指的Anisotropic Filtering(AF)均是基於三線過濾的Anisotropic Filtering,因此當u:v不為1:1時,則Anisotropic Filtering比Trilinear須要採樣很多其它的點,詳細要採多少,取決於是多少X的AF,如今的顯卡最多技持到16X AF。
當開啟16X AF的時候,硬件並非對全部的texture採樣都用16X AF。而是須要先計算屏幕空間與紋理空間的夾角(量化后便是上面所說的u:v),僅僅有當夾角大到須要16X時,才會真正使用16X.
假設想了解AF的實現原理,能夠查閱此篇Paper: “Implementing an anisotropic texture filter”. 如今AF都是硬件實現,因此僅僅有少數人才清楚AF就盡是如何實現了(事實上細節我也沒搞清楚),事實上全然能夠由Pixel Shader來實現AF,當然性能和由硬件做是沒得比的。
8、 各過濾模式性能比較。
下表是各種過濾模式採一個pixel須要sample的次數:
|
|
Sample Number |
| Nearest Point Sampling |
1 |
| Bilinear |
4 |
| Trilinear |
8 |
| Anisotropic Filtering 4X |
32 |
| Anisotropic Filtering 16X |
128 |
4X是三次過濾的四倍,是以三次過濾為基准進行比較的。
Anisotropic Filtering 16X效果最好。可是顯卡Performance會下降非常多,當然也是測試你手中顯卡Texture Unit的好方法。假設你認為你的顯卡夠牛。那么就把AA和AF都打到最高再試試吧:)
各項異性過濾(AF)是一種通用的紋理質量增強技術。可影響紋理在非正交視角下的外觀。
紋理是包括各種數據的圖像,比方顏色、透明度、反射率和平滑度(法線)。
這些數據映射到物體並經過GPU處理。以便於在屏幕上呈現真實的外觀。但就其原始維度來說,大多數紋理都由於計算開銷過大而不能在場景中無限制重用。由於物體的紋素(1像素紋理)與照相機之間的相對距離會影響細節的可見程度。這常常會導致浪費大量處理時間來獲取3D場景中不成比例的小曲面上應用的多重紋理樣本。
為了同一時候保證性能和圖像質量,AF使用了mipmap;mipmap是以較低分辨率呈現的主紋理副本。當對應曲面與照相機之間的距離達到指點值時。圖形引擎便可調用它。經過適當過濾之后。在一個場景中使用多種mipmap水平不僅不會對其外觀造成的太大的影響,同一時候還能夠極大地優化性能。
作為雙線過濾的視覺連續方法,三線過濾能夠連續對目標紋素的相鄰mipmap採樣和拉平紋理數據,因此在mipmap之間提供了平滑的轉換。
但這樣的方法與雙線過濾都假定紋理在照相機前顯示為方塊。從而影響紋理在較小視角下的質量。其原因在於紋素比mipmap樣本長或寬會分別造成過度採樣或採樣不足,從而導致圖像模糊。
各項異性過濾的目的是在各種情況下都能提供出色的圖像質量,同一時候將性能開銷控制在較低的水平。
依據計算機科學的定義,各項異性是處理同一空間中相異坐標的質量,這適用於在顯示時未與照相機絕對正交的紋理。
如前所述。當採樣紋理與照相機斜交時。雙線和三線過濾終於都會造成質量丟失,由於兩種方法在從mipmap獲取紋理採樣時都假定映射紋理在所呈現的空間中為絕對的方形。這非常少能產生真實的效果。
mipmap的等方性(即使用同樣的維度)也是造成質量丟失的還有一個原因,因此當紋素為梯形時就無法在兩個方向上充足採樣。為了解決此問題,各項異性過濾將依據紋理的角度扭曲程度按比例擴展mipmap的高度和寬度。該比例取決於所指定的最大採樣值。然后將運行適當的採樣。
AF支持的各項異性水平范圍是1(無擴展)到16,這些值定義了mipmap可擴展的最大程度,但AF為用戶提供的擴展水平通常為2的冪:即2x、4x、8x和16x。
這些設置之間的差別在於AF過濾紋理的最大角度不同。
舉例來說,4x過濾紋理的角度比2x陡兩倍。但仍然在2x范圍內對紋理運行標准2x過濾來優化性能。使用的AF設置越高,能獲得的收益也會更小,由於它們所適用的角度會呈指數形式降低。

