紋素和紋理坐標(biāo)
紋理對(duì)象通常是通過(guò)紋理圖片讀取到的,這個(gè)數(shù)據(jù)保存到一個(gè)二維數(shù)組中,這個(gè)數(shù)組中的元素成為紋素(texel),紋素包含顏色值和alpha值。紋理對(duì)象的大小的寬度和高度應(yīng)該為2的整數(shù)冪,例如16,32,64。要想獲取紋理對(duì)象中的紋素,需要使用紋理坐標(biāo)(texture coordinate)指定。
紋理坐標(biāo)應(yīng)該與紋理對(duì)象大小無(wú)關(guān),這樣指定的紋理坐標(biāo)當(dāng)紋理對(duì)象大小變更時(shí),依然能夠工作,比如從256x256大小的紋理,換到512x256時(shí),紋理坐標(biāo)依然能夠工作。因此紋理坐標(biāo)使用規(guī)范化的值,大小范圍為[0,1],紋理坐標(biāo)使用uv表示,如下圖所示:

通過(guò)指定紋理坐標(biāo),可以映射到紋素。例如一個(gè)256x256大小的二維紋理,坐標(biāo)(0.5,1.0)對(duì)應(yīng)的紋素即是(128,256)。
紋理映射時(shí)只需要為物體的頂點(diǎn)指定紋理坐標(biāo)即可,其余部分由片元著色器插值完成,如下圖所示:

紋素到像素轉(zhuǎn)換問(wèn)題
一個(gè)紋素最終對(duì)應(yīng)屏幕上的多個(gè)像素稱(chēng)為放大(magnification)
一個(gè)紋素對(duì)應(yīng)屏幕上的一個(gè)像素 這種情況不需要濾波方法
-
一個(gè)紋素對(duì)應(yīng)少于一個(gè)像素,或者說(shuō)多個(gè)紋素對(duì)應(yīng)屏幕上的一個(gè)像素稱(chēng)為縮小(minification)
放大縮小示意圖.png
Mipmaps
當(dāng)物體在場(chǎng)景中離觀察者很遠(yuǎn),最終只用一個(gè)屏幕像素來(lái)顯示時(shí),這個(gè)像素該如何通過(guò)紋素確定呢?如果使用最近鄰濾波來(lái)獲取這個(gè)紋素,那么顯示效果并不理想。需要使用紋素的均值來(lái)反映物體在場(chǎng)景中離我們很遠(yuǎn)這個(gè)效果,對(duì)于一個(gè) 256×256的紋理,計(jì)算平均值是一個(gè)耗時(shí)工作,不能實(shí)時(shí)計(jì)算,因此可以通過(guò)提前計(jì)算一組這樣的紋理用來(lái)滿(mǎn)足這種需求。這組提前計(jì)算的按比例縮小的紋理就是Mipmaps。Mipmaps紋理大小每級(jí)是前一等級(jí)的一半,按大小遞減順序排列為:
- 原始紋理 256×256
- Mip 1 = 128×128
- Mip 2 = 64×64
- Mip 3 = 32×32
- Mip 4 = 16×16
- Mip 5 = 8×8
- Mip 6 = 4×4
- Mip 7 = 2×2
- Mip 8 = 1×1
OpenGL中通過(guò)函數(shù)glGenerateMipmap(GL_TEXTURE_2D);來(lái)生成Mipmap,前提是已經(jīng)指定了原始紋理。
如果直接在不同等級(jí)的MipMap之間切換,會(huì)形成明顯的邊緣,因此對(duì)于Mipmap也可以同紋素一樣使用濾波方法在不同等級(jí)的Mipmap之間濾波。要在不同等級(jí)的MipMap之間濾波,需要將之前設(shè)置的GL_TEXTURE_MIN_FILTER選項(xiàng)更改為以下選項(xiàng)之一:
- GL_NEAREST_MIPMAP_NEAREST: 使用最接近像素大小的Mipmap,紋理內(nèi)部使用最近鄰濾波。
- GL_LINEAR_MIPMAP_NEAREST: 使用最接近像素大小的Mipmap,紋理內(nèi)部使用線性濾波。
- GL_NEAREST_MIPMAP_LINEAR: 在兩個(gè)最接近像素大小的Mipmap中做線性插值,紋理內(nèi)部使用最近鄰濾波。
- GL_LINEAR_MIPMAP_LINEAR: 在兩個(gè)最接近像素大小的Mipmap中做線性插值,紋理內(nèi)部使用線性濾波。
使用使用glGenerateMipmap(GL_TEXTURE_2D)產(chǎn)生Mipmap的前提是你已經(jīng)加載了原始的紋理對(duì)象。使用MipMap時(shí)設(shè)置GL_TEXTURE_MIN_FILTER選項(xiàng)才能起作用,設(shè)置GL_TEXTURE_MAG_FILTER的Mipmap選項(xiàng)將會(huì)導(dǎo)致無(wú)效操作,OpenGL錯(cuò)誤碼為GL_INVALID_ENUM。
片元著色器中使用紋理對(duì)象
在頂點(diǎn)著色器中我們傳遞了紋理坐標(biāo),有了紋理坐標(biāo),獲取最終的紋素使用是在片元著色器中完成的。由于紋理對(duì)象通過(guò)使用uniform變量來(lái)向片元著色器傳遞,實(shí)際上這里傳遞的是對(duì)應(yīng)紋理單元(texture unit)的索引號(hào)。紋理單元、紋理對(duì)象對(duì)應(yīng)關(guān)系如下圖所示:

著色器通過(guò)紋理單元的索引號(hào)索引紋理單元,每個(gè)紋理單元可以綁定多個(gè)紋理到不同的目標(biāo)(1D,2D)。OpenGL可以支持的紋理單元數(shù)目,一般至少有16個(gè),依次為GL_TEXTURE0 到GL_TEXTURE15,紋理單元最大支持?jǐn)?shù)目可以通過(guò)查詢(xún)GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS常量獲取。這些常量值是按照順序定義的,因此可以采用 GL_TEXTURE0 + i 的形式書(shū)寫(xiě)常量,其中整數(shù)i在[0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)范圍內(nèi)。
紋理對(duì)象不僅包含紋理數(shù)據(jù),還包含采樣參數(shù),這些采樣參數(shù)稱(chēng)之為采樣狀態(tài)(sampling state)。而采樣對(duì)象(sampler object)就是只包含采樣參數(shù)的對(duì)象,將它綁定到紋理單元時(shí),它會(huì)覆蓋紋理對(duì)象中的采樣狀態(tài),從而重新配置采樣方式。
要使用紋理必須在使用之前激活對(duì)應(yīng)的紋理單元,默認(rèn)狀態(tài)下0號(hào)紋理單元是激活的,因此即使沒(méi)有顯式地激活也能工作。激活并使用紋理的代碼如下:
```
glActiveTexture(GL_TEXTURE0)
```
紋理API
- 讀取文件
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
format: 像素格式
type: 解釋參數(shù)pixels指向的數(shù)據(jù),告訴OpenGL使用緩存區(qū)中的什么數(shù)據(jù)類(lèi)型來(lái)存儲(chǔ)顏色分量。像素?cái)?shù)據(jù)的數(shù)據(jù)類(lèi)型
pixels: 圖形數(shù)據(jù)指針


GLbyte *gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat);
szFileName: 紋理文件名
iWidth: 寬度地址
iHeight: 高度地址
iComponents: 組件地址
eFormat: 格式地址
- 載入紋理
void glTextImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, void *data)
target: `GLTETURE_1D` `GL_TEXTURE_2D` `GL_TEXTURE_3D`
level: 指定所加載的mip貼圖層次,一般設(shè)置為0
internalformat: 每個(gè)紋理單元中存儲(chǔ)多少顏色成分
format: 像素格式(如: GL_RGBA)
type: 像素?cái)?shù)據(jù)的數(shù)據(jù)類(lèi)型(GL_UNSIGNED_BYTE, 每個(gè)顏色分量都是一個(gè)8位無(wú)符號(hào)整數(shù))
data: 指向紋理圖像數(shù)據(jù)的指針
-
紋理對(duì)象
-
分配紋理對(duì)象
glGenTextures(GLsizi n, GLuint *textures); -
綁定紋理狀態(tài)
glBindTexture(GLenum target, GLuint texture); -
刪除綁定紋理
void glDelteTextures(GLsizei n, GLuint *textures); -
測(cè)試紋理對(duì)象是否有效
GLboolean glIsTexture(GLuint texture);
-
設(shè)置紋理的相關(guān)參數(shù)
glTexParameteri(GLenum target, GLenum pname, GLint param);
-
過(guò)濾方式
-
鄰近過(guò)濾(GL_NEAREST)
// 紋理縮小時(shí),使用鄰近過(guò)濾 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -
線性過(guò)濾(GL_LINEAR)
// 紋理放大時(shí),使用線性過(guò)濾 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-
環(huán)繞方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
參考:
https://blog.csdn.net/wangdingqiaoit/article/details/51457675
