OpenGL紋理API簡(jiǎn)介

紋素和紋理坐標(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表示,如下圖所示:


紋理坐標(biāo).png

通過(guò)指定紋理坐標(biāo),可以映射到紋素。例如一個(gè)256x256大小的二維紋理,坐標(biāo)(0.5,1.0)對(duì)應(yīng)的紋素即是(128,256)。

紋理映射時(shí)只需要為物體的頂點(diǎn)指定紋理坐標(biāo)即可,其余部分由片元著色器插值完成,如下圖所示:


紋理映射.png

紋素到像素轉(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)系如下圖所示:


紋理單元和紋理對(duì)象對(duì)應(yīng)關(guān)系圖.png

著色器通過(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ù)指針
像素格式.png
像素?cái)?shù)據(jù)的數(shù)據(jù)格式.png
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);
    
  • 紋理隧道Demo

參考:
https://blog.csdn.net/wangdingqiaoit/article/details/51457675

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文首發(fā)于個(gè)人博客:Lam's Blog - 【OpenGL-ES】二維紋理,文章由MarkDown語(yǔ)法編寫(xiě),可能...
    格子林ll閱讀 3,963評(píng)論 0 9
  • 一、紋理基礎(chǔ) 3D圖形渲染中最基本的操作就是對(duì)一個(gè)表面應(yīng)用紋理。紋理可以表現(xiàn)只從網(wǎng)格的幾何形狀無(wú)法得到的附加細(xì)節(jié)。...
    cain_huang閱讀 9,172評(píng)論 0 7
  • 1.從TGA?文件中讀取像素圖 GLbyte *gltReadTGABits(const char *szFile...
    如意神王閱讀 1,974評(píng)論 0 1
  • 紋理(Textures) 我們已經(jīng)了解到,我們可以為每個(gè)頂點(diǎn)使用顏色來(lái)增加圖形的細(xì)節(jié),從而創(chuàng)建出有趣的圖像。但是通...
    IceMJ閱讀 5,839評(píng)論 2 13
  • http://blog.csdn.net/wangdingqiaoit/article/details/51457...
    jerryhigh閱讀 5,551評(píng)論 0 8

友情鏈接更多精彩內(nèi)容