1.理解紋理
?
OpenGL中的紋理能夠用來表示圖像。照片,甚至由一個數學算法生成的分形數據。每一個二維的紋理都由很多小的紋理元素組成。它們是小塊的數據,類似于我們前面討論過的片段和像素。要使用紋理,最經常使用的方式是直接從一個圖像文件載入數據。
?
每一個二維紋理都有其自己的坐標空間,其范圍是從一個拐角的(0,0)到還有一個拐角的(1。1)。依照慣例,一個維度叫做S,而還有一個稱為T。當我們想要把一個紋理應用于一個三角形或一組三角形的時候。我們要為每一個頂點指定一組ST紋理坐標,以便OpenGL知道須要用那個紋理的哪個部分畫到每一個三角形上。
這些紋理坐標有時也會被稱為UV紋理坐標。如圖:
圖1 ?OpenGL二維紋理坐標
?
對一個OpenGL紋理來說,它沒有內在的方向性,因此我們能夠使用不同的坐標把它定向到不論什么我們喜歡的方向上。
然而,大多數計算機圖像都有一個默認的方向。它們通常被規定為Y軸向下,Y的值隨著向圖像的底部移動而添加。僅僅要我們記住,假設想用正確的方向觀察圖像,那紋理坐標就必需要考慮這點。這就不會給我們帶來不論什么麻煩。
?
在標準OpenGL?ES?2.0中。紋理不必是正方形,可是每一個維度都應該是2的冪(POT)。
這就意味著每一個維度都是這種一個數字,如128,256,512等。這樣規定的原因在于非POT紋理能夠被使用的場合很有限,而POT紋理使用于各種情況。
?
紋理的尺寸也有一個最大值,它依據不同的實現而變化。可是通常都比較大,比方2048*2048。
?
2.理解紋理過濾
?
當紋理的大小被擴大或者縮小時,我們還須要使用紋理過濾明白說明會發生什么。當我們在渲染表面上繪制一個紋理時,那個紋理的紋理元素可能無法精確地映射到OpenGL生成的片段上。
有兩種情況:縮小和放大。
當我們盡力把幾個紋理元素擠進一個片段時,縮小就發生了;當我們把一個紋理元素擴展到很多片段時。方法就發生了。針對每一種情況,我們能夠配置OpenGL使用一個紋理過濾器。
?
首先。講述兩個主要的過濾模式:近期鄰過濾和雙線性插值。還有其它的過濾模式,以后的博文會解說。我們會使用以下的圖像闡述每一種過濾模式。
?
近期鄰過濾
?
這個方式為每一個片段選擇近期的紋理元素。當我們放大紋理時,它的鋸齒效果看起來相當明顯,例如以下圖所看到的。
?
每一個紋理單元都清楚的顯示為一個小方塊。
?
當我們縮小紋理時。由于沒有足夠的片段用來繪制全部的紋理單元,很多細節將會丟失。
?
雙線性過濾
?
雙線性過濾使用雙線性插值平滑像素之間的過渡。而不是為每一個片段使用近期的紋理元素。OpenGL會使用四個鄰接的紋理元素。并在它們之間用一個線性插值算法做插值,這個算法與前面所講的平滑坐在著色一樣。我們之所以稱它為雙線性插值。是由于它是沿著兩個維度插值的。以下是使用雙線性差值放大后的圖像。它採用的紋理與前面的同樣。
這個紋理如今看起來比曾經平滑多了。
但還是有些鋸齒顯現出來,由于我們把這個紋理擴展得太多。可是鋸齒不像使用近期鄰過濾那么明顯。
?
MIP貼圖
雖然雙線性過濾非常適合處理放大,可是對于縮小到超過一定的大小時,它就不好用了。一個紋理在渲染表面所占大小降低得越多。就會有越多的紋理元素擁擠到每個片段上。
由于OpenGL的雙線性過濾僅僅給每個片段使用四個紋理元素。我們將會丟失非常多細節。
由于每一幀都要選擇不同的紋理元素。這還會引起噪音以及移動中的物體閃爍。
?
為了克服這些缺陷。能夠使用MIP貼圖技術,它能夠用來生成一組優化過的不同大小的紋理。當生成這組紋理的時候,OpenGL會使用全部的紋理元素生成每一個級別的紋理,當過濾紋理時,還要確保全部的紋理元素都能被使用。在渲染時,OpenGL會依據每一個片段的紋理元素數量為每一個片段選擇最合適的級別。
?
下圖是一組MIP貼圖的紋理,把它們合并在一當個圖上是為了方便對照。
? 圖2 MIP貼圖的紋理
使用MIP貼圖。會占用很多其它的內存,可是渲染也會更快,這是由于較小級別的紋理在GPU的紋理緩存中占用較少的空間。
?
為了更好地理解MIP貼圖是怎樣提高縮小情況下的質量,我們比較一下那個可愛的機器人。使用雙線性過濾把紋理元素尺寸縮小到其原來的12.5%。例如以下圖:
? 圖3 使用雙線性過濾縮小
就這樣的質量,可能還不如近期鄰過濾。看一下當我們增加MIP貼圖時會得到什么。例如以下圖:
? 圖4 使用MIP貼圖縮小
隨著MIP貼圖的使用。OpenGL將選擇最合適的紋理級別。然后用優化過的紋理做雙線性插值。每一個級別的紋理都是用來自全部紋理元素的信息構建的。因此得到的圖形看起來更好些。保留了很多其它的細節。
?
三線性過濾
?
假設OpenGL在不同的MIP貼圖級別之間來回切換,當我們用雙線性插值來使用MIP貼圖時。在其渲染的場景中,在不同級別的MIP貼圖切換時。我們有時候能看到明顯的跳躍或者線條。我們能夠切換到三線性插值。這樣。每一個片段總共要使用8個紋理元素插值。
這有助于消除每一個MIP貼圖級別之間的過渡,而且得到一個更平滑的圖像。
?
3.程序中紋理參數表
方法GLES20.glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_FILTER。“紋理過濾模式”)。第二個參數指放大的情況。
方法GLES20.glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,“紋理過濾模式”);第二個參數指縮小的情況。
第一個參數是告訴OpenGL這應該被作為一個二維紋理對待。
表1 ?OpenGL紋理過濾模式
GL_NEAREST | 近期鄰過濾 |
? ? ? ? ? ? ? ? ? ? ? ? GL_NEAREST_MIPMAP_NEAREST | ? ? ? ? ? ? ? ? ? ? 使用MIP貼圖的近期鄰過濾 |
? ? ? ? GL_NEAREST_MIPMAP_LINEAR | ? ? ? 使用MIP貼圖級別之間插值的近期鄰過濾 |
? ? ? ? ? ? ? ? ? ? ? GL_LINEAR | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 雙線性插值 |
?GL_LINEAR_MIPMAP_NEAREST | 使用MIP貼圖的雙線性插值 |
?GL_LINEAR_MIPMAP_LINEAR | 三線性插值(使用MIP貼圖級別之間插值的雙線性過濾) |
表2 ?每種情況同意的紋理過濾模式
縮小 | GL_NEAREST GL_NEAREST_MIPMAP_NEAREST GL_NEAREST_MIPMAP_LINEAR GL_LINEAR GL_LINEAR_MIPMAP_NEAREST GL_LINEAR_MIPMAP_LINEAR |
放大 | GL_NEAREST GL_LINEAR |
下一篇紋理的應用效果圖例如以下: