OpenGL-12-紋理、紋理API及紋理坐標(biāo)

一、了解紋理

在OpenGL中,紋理是一種圖形數(shù)據(jù),主要用于包裝不同的物體。
我們來舉個例子:裝修房子時,各個房間需要貼不同的墻紙。這里的墻紙就是我們說的紋理。

  • 圖片要在屏幕上顯示,其實都是通過解碼成位圖,然后進行顯示的。一個圖像在幀緩沖區(qū)的存儲空間大小,可以用這個公式進行計算:
    圖像存儲空間 = 圖像的高 * 圖像的寬 * 每個像素的字節(jié)數(shù)
  • 在OpenGL中,紋理一般是.TGA文件。在實際iOS開發(fā)中,我們使用的是OpenGL ES,可以直接使用png、jpg格式的壓縮圖片來作為紋理數(shù)據(jù)。因為系統(tǒng)會把壓縮圖片通過解碼還原成位圖供紋理使用,位圖每一個像素點都會有其顏色空間。

二、紋理相關(guān)API

我們先把API中用到的數(shù)據(jù)表放在前面,方便查閱

像素格式表 和 像素數(shù)據(jù)類型表

像素格式-format表
像素數(shù)據(jù)類型-type表
舉例解讀type表

紋理的使用步驟: 讀取文件數(shù)據(jù)、載入紋理、生成紋理對象,設(shè)置紋理相關(guān)參數(shù)

1、讀取紋理數(shù)據(jù)

1.1 從顏?緩沖區(qū)中讀取文件數(shù)據(jù)
void glReadPixels(GLint x,GLint y,GLSizei width,GLSizei height, GLenum format, GLenum type,const void * pixels);
/*
//參數(shù)1:x,矩形左下?的窗?坐標(biāo)
//參數(shù)2:y,矩形左下?的窗?坐標(biāo)
//參數(shù)3:width,矩形的寬,以像素為單位
//參數(shù)4:height,矩形的?,以像素為單位
//參數(shù)5:format,OpenGL 的像素格式,如RGBA。參考:像素格式-format表
//參數(shù)6:type,解釋參數(shù)pixels指向的數(shù)據(jù),告訴OpenGL 使?緩存區(qū)中的什么數(shù)據(jù)類型來存儲顏?分量,像素數(shù)據(jù)的數(shù)據(jù)類型,參考:像素數(shù)據(jù)類型-type表
//參數(shù)7:pixels,指向圖形數(shù)據(jù)的指針
*/
//指定讀取的緩存 
glReadBuffer(mode);
//指定寫?的緩存
glWriteBuffer(mode); 
1.2 從TGA文件中讀取紋理數(shù)據(jù)
/*
     參數(shù)1:紋理文件名稱
     參數(shù)2:文件寬度地址
     參數(shù)3:文件高度地址
     參數(shù)4:文件組件地址
     參數(shù)5:文件格式地址
     返回值:pBits,指向圖像數(shù)據(jù)的指針
     */
    gltReadTGABits(<#const char *szFileName#>, <#GLint *iWidth#>, <#GLint *iHeight#>, <#GLint *iComponents#>, <#GLenum *eFormat#>)

2、載入紋理

一般使用 glTexImage2D

//width
void glTexImage1D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLint border,GLenum format,GLenum type,void *data);
//width + height
void glTexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,void * data);
//width + height + depth
void glTexImage3D(GLenum target,GLint level,GLint internalformat,GLSizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,void *data);
/*
* target:`GL_TEXTURE_1D`、`GL_TEXTURE_2D`、`GL_TEXTURE_3D`。 
* Level:指定所加載的mip貼圖層次。?般我們都把這個參數(shù)設(shè)置為0。
* internalformat:每個紋理單元中存儲多少顏?成分。
* width、height、depth參數(shù):指加載紋理的寬度、?度、深度。
==注意!==這些值必須是2的整數(shù)次?。(這是因為OpenGL 舊版本上的遺留下的?個要求。當(dāng)然現(xiàn)在已經(jīng)可以?持不是2的整數(shù)次?。但是開發(fā)者們還是習(xí)慣使?以2的整數(shù)次?去設(shè)置這些參數(shù)。)

* border參數(shù):允許為紋理貼圖指定?個邊界寬度。
* format、type、data參數(shù):與上面一樣
*/

3、生成紋理

生成紋理有兩步:
1、申請分配紋理對象。glGenTextures
2、綁定紋理狀態(tài)。glBindTexture

3.1 申請分配紋理對象
//使?函數(shù)分配紋理對象
//指定紋理對象的數(shù)量 和 指針(指針指向?個?符號整形數(shù)組,由紋理對象標(biāo)識符填充)。
void glGenTextures(GLsizei n,GLuint * textTures);
//例如:
glGenTextures(1, &textureID);
3.2 綁定紋理狀態(tài)
//綁定紋理狀態(tài)
//參數(shù)target:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
//參數(shù)texture:需要綁定的紋理對象
void glBindTexture(GLenum target,GLunit texture);
//例如:
glBindTexture(GL_TEXTURE_2D, textureID);
3.3 刪除紋理對象
//刪除綁定紋理對象
//紋理對象 以及 紋理對象指針(指針指向?個?符號整形數(shù)組,由紋理對象標(biāo)識符填充)。
void glDeleteTextures(GLsizei n,GLuint *textures);
//例如:
glDeleteTextures(1, &textureID);
3.4 測試紋理對象是否有效
//測試紋理對象是否有效
//如果texture是?個已經(jīng)分配空間的紋理對象,那么這個函數(shù)會返回GL_TRUE,否則會返回GL_FALSE。 
GLboolean glIsTexture(GLuint texture);
//例如:
glIsTexture(textureID);

4、設(shè)置紋理參數(shù)

主要是設(shè)置紋理在縮小和放大時的過濾方式、x/y軸上的環(huán)繞方式。這些都是通過指定參數(shù)之,并對應(yīng)的設(shè)置

/*
參數(shù)1:target,指定這些參數(shù)將要應(yīng)?在那個紋理模式上,?如GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D。
參數(shù)2:pname,指定需要設(shè)置那個紋理參數(shù)
參數(shù)3:param,設(shè)定特定的紋理參數(shù)的值
*/
void glTexParameterf(GLenum target,GLenum pname,GLFloat param);
void glTexParameteri(GLenum target,GLenum pname,GLint param);
void glTexParameterfv(GLenum target,GLenum pname,GLFloat *param);
void glTexParameteriv(GLenum target,GLenum pname,GLint *param);

4.1 過濾方式

常用的有兩種:鄰近過濾、線性過濾。

  • 鄰近過濾(GL_NEAREST):就是選擇離當(dāng)前位置最近的顏色
  • 線性過濾(GL_LINEAR):當(dāng)前位置周圍的所有顏色進行一系列混合計算得到的綜合顏色
  • 建議:紋理縮小時,使用鄰近過濾,紋理放大時,使用線性過濾


    image.png
//放大時,用鄰近過濾
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
//縮小時,用鄰近過濾
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
//放大時,用線性過濾
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
//縮小時,用線性過濾
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
2種過濾方式比較
4.2 環(huán)繞方式

環(huán)繞方式是指當(dāng)紋理坐標(biāo)超出默認范圍時,邊緣的顯示形式
環(huán)繞方式的設(shè)置主要是針對x、y軸設(shè)置的,而在紋理的描述中使用并不是x、y,而是 s、t
注意:紋理中的 s, t, r, q 對應(yīng)坐標(biāo)系中的 x, y, z, w

環(huán)繞方式:

  • GL_REPEAT:默認,重復(fù)紋理圖像
  • GL_MIRRORED_REPEAT:重復(fù)紋理圖像,每次重復(fù)圖片是鏡像放置的
  • GL_CLAMP_TO_EDGE:紋理坐標(biāo)會被約束在0-1之間,超出的部分會重復(fù)紋理坐標(biāo)的邊緣,產(chǎn)生一種邊緣被拉伸的效果
  • GL_CLAMP_TO_BORDER:超出的坐標(biāo)為用戶指定的邊緣顏色
/*
參數(shù)1:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
參數(shù)2:GL_TEXTURE_WRAP_S、GL_TEXTURE_T、GL_TEXTURE_R,針對s,t,r坐標(biāo)
參數(shù)3:GL_REPEAT、GL_CLAMP、GL_CLAMP_TO_EDGE、GL_CLAMP_TO_BORDER
 */
glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_S,GL_CLAMP_TO_EDGE);
glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_T,GL_CLAMP_TO_EDGE);
4種環(huán)繞方式比較

接下來繼續(xù)介紹一下其他的API

5、紋理像素的存儲方式

//改變像素存儲?式
void glPixelStorei(GLenum pname,GLint param);
//恢復(fù)像素存儲?式
void glPixelStoref(GLenum pname,GLfloat param);
/*
舉例:
參數(shù)1:GL_UNPACK_ALIGNMENT 指定OpenGL 如何從數(shù)據(jù)緩存區(qū)中解包圖像數(shù)據(jù)
GL_UNPACK_ALIGNMENT 指內(nèi)存中每個像素?起點的排列請求,允許設(shè)置為:
1 (byte排列)、
2(排列為偶數(shù)byte的?)、
4(字word排列)、
8(?從雙字節(jié)邊界開始)

參數(shù)2:表示參數(shù)GL_UNPACK_ALIGNMENT 設(shè)置的值
*/
glPixelStorei(GL_UNPACK_ALIGNMENT,1);

6、更新紋理

參數(shù)參考前面的API

//xOffset 
void glTexSubImage1D(GLenum target,GLint level,GLint xOffset,GLsizei width,GLenum format,GLenum type,const GLvoid *data);
//xOffset + yOffset 
void glTexSubImage2D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const GLvoid *data);
//xOffset + yOffset + zOffset
void glTexSubImage3D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLint zOffset,GLsizei width,GLsizei height,GLsizei depth,Glenum type,const GLvoid * data);

7、插入替換紋理

參數(shù)參考前面的API

//xoffset
void glCopyTexSubImage1D(GLenum target,GLint level,GLint xoffset,GLint x,GLint y,GLsizei width);
//xOffset + yOffset 
void glCopyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint x,GLint y,GLsizei width,GLsizei height);
//xOffset + yOffset + zOffset
void glCopyTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint zOffset,GLint x,GLint y,GLsizei width,GLsizei height)

8、使用顏色緩沖區(qū)加載數(shù)據(jù),形成新的紋理使用

參數(shù)x,y 在顏?緩存區(qū)中指定了開始讀取紋理數(shù)據(jù)的位置;
緩存區(qū)?的數(shù)據(jù),是源緩存區(qū)通過glReadBuffer設(shè)置的。
注意:不存在glCopyTextImage3D ,因為我們?法從2D 顏?緩存區(qū)中獲取體積數(shù)據(jù)。

//width
void glCopyTexImage1D(GLenum target,GLint level,GLenum internalformt,GLint x,GLint y,GLsizei width,GLint border);
//width + height
void glCopyTexImage2D(GLenum target,GLint level,GLenum internalformt,GLint x,GLint y,GLsizei width,GLsizei height,GLint border);

9、壓縮紋理

9.1 通?壓縮紋理格式
通?壓縮紋理格式
9.2 判斷壓縮 與 選擇壓縮?式
//根據(jù)選擇的壓縮紋理格式,選擇最快、最優(yōu)、??選擇的算法?式選擇壓縮格式。
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_FASTEST);
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_NICEST);
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_DONT_CARE);
9.3 加載壓縮紋理
//width 
void glCompressedTexImage1D(GLenum target,GLint level,GLenum internalFormat,GLsizei width,GLint border,GLsizei imageSize,void *data);
//width + heigth 
void glCompressedTexImage2D(GLenum target,GLint level,GLenum internalFormat,GLsizei width,GLint heigth,GLint border,GLsizei imageSize,void *data);
//width + heigth + depth
void glCompressedTexImage3D(GLenum target,GLint level,GLenum internalFormat,GLsizei width,GLsizei heigth,GLsizei depth,GLint border,GLsizei imageSize,void *data);
/*
 target:`GL_TEXTURE_1D`、`GL_TEXTURE_2D`、`GL_TEXTURE_3D`。
 Level:指定所加載的mip貼圖層次。?般我們都把這個參數(shù)設(shè)置為0。
internalformat:每個紋理單元中存儲多少顏?成分。
width、height、depth參數(shù):指加載紋理的寬度、?度、深度。==注意!==這些值必須是2的整數(shù)次?。(這是因為OpenGL 舊版本上的遺留下的?個要求。當(dāng)然現(xiàn)在已經(jīng)可以?持不是2的整數(shù)次?。但是開發(fā)者們還是習(xí)慣使?以2的整數(shù)次?去設(shè)置這些參數(shù)。)
border參數(shù):允許為紋理貼圖指定?個邊界寬度。
format、type、data參數(shù):與我們在講glDrawPixels 函數(shù)對于的參數(shù)相同
*/
9.4 glGetTexLevelParameter函數(shù)提取的壓縮紋理格式
image.png
9.5 GL_EXT_texture_compression_s3tc壓縮格式
image.png

三、紋理坐標(biāo)

紋理坐標(biāo)就是紋理與圖形的映射關(guān)系,圖形中每個頂點都會關(guān)聯(lián)一個紋理坐標(biāo),表示頂點需要從該位置讀取紋理圖像的數(shù)據(jù)。

  • 紋理坐標(biāo)的范圍是 0 到 1 之間,

  • 頂點坐標(biāo)一般是用( x,y,z)描述,而紋理坐標(biāo)是用( s,t,r)描述

  • 紋理坐標(biāo)默認左下角為(0,0),即:
    左上角(1,0) 右上角(1,1)
    左下角(0,0) 左下角(1,0)


    image.png
  • 另外,紋理坐標(biāo)的映射關(guān)系并不是固定的,可以根據(jù)圖片不同角度的翻轉(zhuǎn),進行不同的映射。注意:不能讓圖片的映射關(guān)系交叉。借用下網(wǎng)上找的一張很直觀的分析圖片來看以下幾種映射情況:

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

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