紋理是什么
?紋理(TEXTURE),即物體表面的樣子嫩挤。在計算機(jī)的世界中害幅,我們能夠繪制的僅僅是一些非常基礎(chǔ)的形狀岂昭,比如點以现、線、三角形约啊,這些基礎(chǔ)顯然是無法將一個現(xiàn)實世界中的物體很好的描述在屏幕上的邑遏。通常我們通過紋理映射將物體表面圖片貼到物體的幾何圖形上面,完成貼圖的過程恰矩,將物體從現(xiàn)實世界中模擬到虛擬世界中记盒。
?紋理的基礎(chǔ)單元是紋素(Texel,即texture element或texture pixel的合成字)外傅,亦如屏幕的基礎(chǔ)單元是像素纪吮。屏幕上有自己的坐標(biāo)系俩檬,紋理也有,即紋理坐標(biāo)碾盟,一個維度稱為 s棚辽,另一個維度稱為 t,其范圍都在 [0,1]之間巷疼。紋理坐標(biāo)上晚胡,是紋素。
?如上圖所示嚼沿,在 OpenGL的二維世界中估盘,本質(zhì)上,紋理就是一個二維數(shù)組(圖像數(shù)據(jù))骡尽,而紋素就是這個二維數(shù)組中的值遣妥。
紋理映射到屏幕
?接下來,首先我們討論下圖像數(shù)據(jù)是如何從紋理坐標(biāo)下被投射到屏幕上的攀细。
坐標(biāo)映射
?上面我們就講過紋理坐標(biāo)系箫踩。兩個維度,范圍都在[0,1]之間谭贪。無論是使用純色渲染境钟,還是圖片渲染,實際上都是在進(jìn)行顏色渲染俭识,最終慨削,都需要將那塊顏色映射到歸一化坐標(biāo)系中。而歸一化坐標(biāo)系中兩個維度都是在[-1,1]之間套媚。
?由于這種坐標(biāo)系的不一致缚态,就需要將紋理坐標(biāo)系中的圖片映射到歸一化坐標(biāo)系中。這里堤瘤,首先我們會遇到兩個問題:
- 將紋理坐標(biāo)系中的哪個區(qū)域塊取出來進(jìn)行映射玫芦。
-
取出來的區(qū)域塊又該如何如何對應(yīng)到歸一化坐標(biāo)系中通過頂點定義的外形中。
?如上圖所示本辐,我們可以得到以下幾點:
- 要選取圖片中的哪個區(qū)域是由我們通過紋理頂點坐標(biāo)定義的桥帆。上圖中,我們通過定義(0,0),(0,1),(1,1),(1,0)慎皱,實際上選取了整個圖片部分作為貼片环葵。
- 要進(jìn)行貼圖的部分定義好了,它所要貼到的地方宝冕,實際上和我們定義的頂點坐標(biāo)按照定義順序一一對應(yīng)(映射)。即邓萨,我們定義的第一個紋理頂點坐標(biāo)地梨,對應(yīng)我們定義的第一個頂點坐標(biāo)菊卷。
?最終,我們可以得到:
?為了明顯起見宝剖,這里再給出一張圖(改變頂點定義的順序):
紋理過濾(Texture Filtering)
?紋理坐標(biāo)和歸一化坐標(biāo)通常并不能實現(xiàn)一比一的映射關(guān)系洁闰,紋理可能會比歸一化坐標(biāo)系中的幾何圖形大,也可能更小万细。這樣就帶來了這樣的問題:在不能實現(xiàn)一比一映射的時候扑眉,該如何在紋理坐標(biāo)中采樣顯示到歸一化坐標(biāo)中。這就是紋理過濾赖钞,實際上是在處理放大和縮小紋理的操作腰素。
?常見的過濾方式有兩種:最鄰近過濾和雙線性過濾。
?對于最鄰近過濾雪营,顧名思義弓千,是為每個片段選擇最近的紋素;而雙線性過濾献起,使用雙線性插值平滑像素之間的過濾洋访。如下圖所示,顯然線性過濾會有更好的效果谴餐,但是也會消耗更多的計算能力:
?我們可以看到姻政,對于雙線性過濾這種方式,特別是在進(jìn)行縮小采樣的時候岂嗓,當(dāng)縮小比例過大汁展,會丟掉很多的細(xì)節(jié),因為不管這個比例如何摄闸,它只會選取周圍的四個點(即四個紋理元素)善镰。為了解決這樣的問題,可以使用 MIP 貼圖的方式解決年枕。關(guān)于 MIP 更多信息可以參考這里
紋理環(huán)繞(Texture Wrapping)
?上面坐標(biāo)中炫欺,我們指定的紋理坐標(biāo)范圍均是在 [0,1]之間,但是如果超出了這個范圍熏兄, 此時刻品洛,我們選擇的紋理區(qū)域大于了實際圖片大小,紋理區(qū)域空白部分該如何處理摩桶,就是紋理環(huán)繞問題桥状。下圖參考
?綜上,我們了解了紋理坐標(biāo)及其映射硝清。下面辅斟,我們可以進(jìn)行實際地編碼工作了。
在程序中使用紋理
?通常芦拿,我們在程序中使用紋理的步驟是這樣的:
- 定義頂點以及渲染程序士飒。其中查邢,在 glsl 程序中使用的 attribute 、uniform酵幕、varying 區(qū)別可參考
private static final String VERTEX_SHADER =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_texCoord;" +
"varying vec2 v_texCoord;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
" v_texCoord = a_texCoord;" +
"}";
private static final String FRAGMENT_SHADER =
"precision mediump float;" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"void main() {" +
" gl_FragColor = texture2D(s_texture, v_texCoord);" +
"}";
private static final float[] TEX_VERTEX = { // in clockwise order:
0, 1f, // top left
1f, 0, // bottom right
0, 0, // bottom left
};
private static final float[] VERTEX = { // in counterclockwise order:
-1, -1f, 0, // bottom left
1, 1, 0, // top right
-1, 1, 0, // top left
};
- 加載圖片扰藕,創(chuàng)建 texture 紋理,然后將圖片指定在紋理上芳撒。
GLES20.glGenTextures(1, texNames, 0);
mTexName = texNames[0];
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.cat);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexName);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
- 指定紋理參數(shù)邓深,主要包括紋理過濾和紋理環(huán)繞方式。
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_MIRRORED_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_MIRRORED_REPEAT);
- 為幾何頂點指定相應(yīng)的紋理坐標(biāo)中的頂點
mTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_texCoord");
GLES20.glEnableVertexAttribArray(mTexCoordHandle);
GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT, false, 0,
mTexVertexBuffer);
- 繪制
GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);
?完整代碼MyRender.java
?需要注意的一點笔刹,上述代碼中我們定義的順序芥备。實際上,在計算機(jī)中圖片都是原點在左上角徘熔,x軸向右延伸门躯,y軸向下延伸,如下圖所示酷师。
小結(jié)
?本節(jié)中讶凉,我們對 OpenGL 中的紋理進(jìn)行了解和應(yīng)用。在現(xiàn)實世界中物體有太多的細(xì)節(jié)山孔,紋理給我們提供了一種方式將這些細(xì)節(jié)通過圖片的方式貼在屏幕上的幾何物體上懂讯。這對于二維平面來說,從效果上來說可能不具有太多吸引力台颠,因為我們的圖片本來就是二維的褐望,但是 OpenGL 也能對其進(jìn)行一些變換(剪切、翻轉(zhuǎn)串前、平移等等)瘫里,而且這些變換是運行在 GPU 上。下面荡碾,我們將進(jìn)入三維的世界谨读。
參考鏈接
Texture Mapping
Texture Mapping
OPENGL ES 2.0:紋理
Mipmap
Textures objects and parameters