1. 程式人生 > >OpenGL ES 紋理設定

OpenGL ES 紋理設定

紋理過濾

紋理拉伸:重複拉伸和擷取拉伸

用於指定紋理座標超過(00.0,1.0)範圍時所發生的行為,使用glTexParameterf函式指定,GL_TEXTURE_WRAP_S 定義 s 座標超出範圍[0.0, 1.0]的情況,GL_TEXTURE_WRAP_T 設定 t 座標。

  • GL_REPEAT 重複紋理,超過1的部分其實只看它的小數部分,也就是說比如紋理座標為2.4,那麼相當於取樣0.4處的紋理值。
  • GL_CLAMP_TO_EDGE 取樣紋理邊緣,不想要任何格式的重複,應該使用 GL_CLAMP_TO_EDGE,超過1的部分都當成1.
  • GL_MIRRORED_REPEAT 重複紋理和映象,在重複的基礎上呈現映象效果。

在立方體紋理的例子上,修改一下vertices陣列,增加一個變數i

float vertices[] = new float[] {
                // 頂點             顏色            紋理座標
                //前面
                0, 0, 1,  1,1,1,0,  0.5f*i, 0.5
f*i, 1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i, -1, 1, 1, 1,0,0,0, 0.0f*i, 0.0f*i, 0, 0, 1, 1,1,1,0, 0.5f*i, 0.5f*i, -1, 1, 1, 1,0,0,0, 0.0f*i, 0.0f*i, -1,-1, 1, 1,0,0,0, 0.0f*i, 1.0f*i, 0, 0, 1, 1,1,1,0, 0.5f*i, 0.5f*i, -1
,-1, 1, 1,0,0,0, 0.0f*i, 1.0f*i, 1,-1, 1, 1,0,0,0, 1.0f*i, 1.0f*i, 0, 0, 1, 1,1,1,0, 0.5f*i, 0.5f*i, 1,-1, 1, 1,0,0,0, 1.0f*i, 1.0f*i, 1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i, //後面 0, 0,-1, 1,1,1,0, 0.5f*i, 0.5f*i, 1, 1,-1, 1,0,0,0, 1.0f*i, 0.0f*i, 1,-1,-1, 1,0,0,0, 0.0f*i, 0.0f*i, 0, 0,-1, 1,1,1,0, 0.5f*i, 0.5f*i, 1,-1,-1, 1,0,0,0, 0.0f*i, 0.0f*i, -1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, 0, 0,-1, 1,1,1,0, 0.5f*i, 0.5f*i, -1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, -1, 1,-1, 1,0,0,0, 1.0f*i, 1.0f*i, 0, 0,-1, 1,1,1,0, 0.5f*i, 0.5f*i, -1, 1,-1, 1,0,0,0, 1.0f*i, 1.0f*i, 1, 1,-1, 1,0,0,0, 1.0f*i, 0.0f*i, //左面 -1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i, -1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i, -1, 1,-1, 1,0,0,0, 0.0f*i, 0.0f*i, -1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i, -1, 1,-1, 1,0,0,0, 0.0f*i, 0.0f*i, -1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, -1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i, -1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, -1,-1, 1, 1,0,0,0, 1.0f*i, 1.0f*i, -1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i, -1,-1, 1, 1,0,0,0, 1.0f*i, 1.0f*i, -1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i, //右面 1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i, 1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i*i, 1,-1, 1, 1,0,0,0, 0.0f*i, 0.0f*i, 1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i, 1,-1, 1, 1,0,0,0, 0.0f*i, 0.0f*i, 1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, 1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i, 1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, 1, 1,-1, 1,0,0,0, 1.0f*i, 1.0f*i, 1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i, 1, 1,-1, 1,0,0,0, 1.0f*i, 1.0f*i, 1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i, //上面 0, 1, 0, 1,1,1,0, 0.5f*i, 0.5f*i, 1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i, 1, 1,-1, 1,0,0,0, 0.0f*i, 0.0f*i, 0, 1, 0, 1,1,1,0, 0.5f*i, 0.5f*i, 1, 1,-1, 1,0,0,0, 0.0f*i, 0.0f*i, -1, 1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, 0, 1, 0, 1,1,1,0, 0.5f*i, 0.5f*i, -1, 1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, -1, 1, 1, 1,0,0,0, 1.0f*i, 1.0f*i, 0, 1, 0, 1,1,1,0, 0.5f*i, 0.5f*i, -1, 1, 1, 1,0,0,0, 1.0f*i, 1.0f*i, 1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i, //下面 0,-1, 0, 1,1,1,0, 0.5f*i, 0.5f*i, 1,-1, 1, 1,0,0,0, 1.0f*i, 0.0f*i, -1,-1, 1, 1,0,0,0, 0.0f*i, 0.0f*i, 0,-1, 0, 1,1,1,0, 0.5f*i, 0.5f*i, -1,-1, 1, 1,0,0,0, 0.0f*i, 0.0f*i, -1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, 0,-1, 0, 1,1,1,0, 0.5f*i, 0.5f*i, -1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i, 1,-1,-1, 1,0,0,0, 1.0f*i, 1.0f*i, 0,-1, 0, 1,1,1,0, 0.5f*i, 0.5f*i, 1,-1,-1, 1,0,0,0, 1.0f*i, 1.0f*i, 1,-1, 1, 1,0,0,0, 1.0f*i, 0.0f*i };

設定i=2時,相當於紋理座標設定的範圍為(0,2)之間,定義紋理過濾方式為重複模式

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT);

重複過濾模式
效果圖

設定紋理過濾模式為重複映象模式

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_MIRRORED_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_MIRRORED_REPEAT);

效果圖
重複映象模式

紋理取樣

紋理取樣就是根據偏遠的紋理座標到紋理圖中提取對應位置顏色的過程,但一般而言,片元數量和紋理圖中的畫素數量並不一定相同,比如將較小的紋理圖對映到較大的圖元或者將較大的紋理圖對映到較小的圖元時就會出現這樣的狀況,通過紋理座標在紋理圖中並不一定能找到與之完全對應的畫素,這時候就要採取相應的策略在紋理圖中選取顏色了。

最近點取樣

最近點取樣的原理就是根據片元的紋理座標在紋理圖中的位置距離那個畫素近就選擇哪個畫素的顏色值作為該片元的顏色取樣值。最近點取樣計算很簡單,但存在的問題就是將較小的紋理圖對映到較大的圖元上容易產生明顯的鋸齒,同時將較大的紋理縮小的一定的程度後也就不好用了。載入紋理時設定最近點取樣的方式

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_NEAREST);

線性紋理取樣

線性紋理取樣的結果並不僅來自紋理圖中的一個畫素,在進行紋理取樣時會考慮到該片元對應的紋理座標周圍的幾個畫素,然後根據周圍幾個畫素的比例進行加權得到最終的取樣結果。由於線性取樣對多個畫素進行了加權平均,僅此將較小的圖元紋理對映到較大的圖元時,不會有鋸齒現象,而是平滑過渡。載入紋理時設定線性紋理取樣的方式

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);

因此一般來說對於縮小對映採用最近點取樣,對於放大對映來說採用線性取樣。GL_TEXTURE_MIN_FILTER表示縮小的對映,GL_TEXTURE_MAG_FILTER表示放大對映。

MIPMAP紋理

儘管用線性取樣很適合處理放大的情況,但是對於縮小到一定的大小後,它就不好用了,一個紋理在渲染表面所佔的大小減少的越多,就會有越多的紋理元素擁擠到一個片元上,一般情況下使用線性取樣,每個片元值使用了四個紋理畫素,我們就會失去很多的細節。

使用MIPMAP技術,可以用來生成一組優化過的不同大小的紋理,並且會使用所有的紋理元素來生成每個級別的紋理。當載入紋理的時候,不單單是載入一個紋理,而是載入一系列從大到小的紋理當mipmapped紋理狀態中。在渲染時,OpenGL會根據每個片元的紋理元素數量為每個片元選擇最合適的級別的紋理。

使用glGenerateMipmap函式自動生成多級紋理,對繫結的紋理呼叫glGenerateMipmap函式會產生從原始影象開始的多級紋理鏈。後續的每個紋理是上一個紋理影象的一半,一直持續到最後底部的1x1的紋理。

public static native void glGenerateMipmap(
        int target  
    );

載入MIP紋理的方式允許在設定紋理取樣方式時採用MIP方式,即param引數除了GL_NEAREST和GL_LINEAR以外,還可以使用GL_NEAREST_MIPMAP_NEAREST、GL_NEAREST_MIPMAP_LINEAR、GL_LINEAR_MIPMAP_NEAREST、GL_LINEAR_MIPMAP_LINEAR。

public static native void glTexParameterf(
        int target,
        int pname,
        float param
    );

使用GL_LINEAR_MIPMAP_LINEAR模式效果最佳。
測試各種型別的紋理取樣方式
紋理取樣演示

程式碼下載