OpenGL中的紋理能夠用來表示圖像,照片,甚至由一個數學算法生成的分形數據。每一個二維的紋理都由許多小的紋理元素組成,它們是小塊的數據,相似於咱們前面討論過的片斷和像素。要使用紋理,最經常使用的方式是直接從一個圖像文件加載數據。算法
每一個二維紋理都有其本身的座標空間,其範圍是從一個拐角的(0,0)到另外一個拐角的(1,1)。按照慣例,一個維度叫作S,而另外一個稱爲T。當咱們想要把一個紋理應用於一個三角形或一組三角形的時候,咱們要爲每一個頂點指定一組ST紋理座標,以便OpenGL知道須要用那個紋理的哪一個部分畫到每一個三角形上。這些紋理座標有時也會被稱爲UV紋理座標。如圖:緩存
圖1 OpenGL二維紋理座標優化
對一個OpenGL紋理來講,它沒有內在的方向性,所以咱們可使用不一樣的座標把它定向到任何咱們喜歡的方向上。然而,大多數計算機圖像都有一個默認的方向,它們一般被規定爲Y軸向下,Y的值隨着向圖像的底部移動而增長。只要咱們記住,若是想用正確的方向觀察圖像,那紋理座標就必需要考慮這點,這就不會給咱們帶來任何麻煩。spa
在標準OpenGL ES 2.0中,紋理沒必要是正方形,可是每一個維度都應該是2的冪(POT)。這就意味着每一個維度都是這樣的一個數字,如128,256,512等。這樣規定的緣由在於非POT紋理能夠被使用的場合很是有限,而POT紋理使用於各類狀況。內存
紋理的尺寸也有一個最大值,它根據不一樣的實現而變化,可是一般都比較大,好比2048*2048。ci
當紋理的大小被擴大或者縮小時,咱們還須要使用紋理過濾明確說明會發生什麼。當咱們在渲染表面上繪製一個紋理時,那個紋理的紋理元素可能沒法精確地映射到OpenGL生成的片斷上。有兩種狀況:縮小和放大。當咱們盡力把幾個紋理元素擠進一個片斷時,縮小就發生了;當咱們把一個紋理元素擴展到許多片斷時,方法就發生了。針對每一種狀況,咱們能夠配置OpenGL使用一個紋理過濾器。數學
首先,講述兩個基本的過濾模式:最近鄰過濾和雙線性插值。還有其餘的過濾模式,之後的博文會講解。咱們會使用下面的圖像闡述每一種過濾模式。it
最近鄰過濾table
這個方式爲每一個片斷選擇最近的紋理元素。當咱們放大紋理時,它的鋸齒效果看起來至關明顯,以下圖所示。擴展
每一個紋理單元都清楚的顯示爲一個小方塊。
當咱們縮小紋理時,由於沒有足夠的片斷用來繪製全部的紋理單元,許多細節將會丟失。
雙線性過濾
雙線性過濾使用雙線性插值平滑像素之間的過渡,而不是爲每一個片斷使用最近的紋理元素,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貼圖級別之間的過渡,而且獲得一個更平滑的圖像。
方法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 |
下一篇紋理的應用效果圖以下: