OpenGL + OpenGL ES +Metal 系列文章彙總
圖檔在螢幕上的顯示,最終都是解碼成位圖,然後進行顯示的。
一個圖形在幀緩存區中的存儲空間,可以根據如下公式計算,
圖像存儲空間 = 圖像的高度 * 圖像寬度 * 每個像素的位元組數
紋理是一種圖形資料,主要用于在螢幕上包裝不同的物體,就像新房裝修,需要貼不同的牆紙,此時的牆紙就是我們所說的紋理。
- 在OpenGL中,紋理一般是TGA檔案
- 在實際的iOS開發中,我們一般不使用OpenGL,而是使用OpenGL ES,進而可以直接使用png、jpg的壓縮圖檔來作為紋理資料,最終都會在底層被解碼成位圖,作為紋理來進行處理。
下面介紹下紋理中常用的API
紋理常用API
紋理的使用主要有以下三個步驟
-
讀取檔案
-
載入紋理
-
生成紋理對象,設定紋理相關參數
讀取檔案
- 讀取檔案API
//參數1:x,矩形左下⻆的窗⼝坐标
//參數2:y,矩形左下⻆的窗⼝口坐标
//參數3:width,矩形的寬,以像素為機關
//參數4:height,矩形的⾼,以像素為機關
//參數5:format,OpenGL 的像素格式
//參數6:type,解釋參數pixels指向的資料,告訴OpenGL 使⽤緩存區中的什麼 資料類型來存儲顔⾊分量,像素資料的資料類型
//參數7:pixels,指向圖形資料的指針
void glReadPixels(GLint x,GLint y,GLSizei width,GLSizei
height, GLenum format, GLenum type,const void * pixels);
glReadBuffer(mode);—> 指定讀取的緩存
glWriteBuffer(mode);—> 指定寫⼊入的緩存
像素格式、像素資料類型參見下方表格内容
載入紋理
常用的一般是
glTexImage2D
,因為螢幕上的圖形時2D的。
//target:指定紋理應用的紋理模式,一般為 GL_TEXTURE_2D
//`GL_TEXTURE_1D`
//`GL_TEXTURE_2D`
//`GL_TEXTURE_3D`
//Level:指定所加載的mip貼圖層次。⼀般我們都把這個參數設定為0。
//internalformat:每個紋理單元中存儲多少顔色成分。
//width、height、depth參數:指加載紋理的寬度、⾼度、深度。==注意!==這些值必須是 2的整次⽅。(這是因為OpenGL 舊版本上的遺留下的⼀個要求。當然現在已經可以支援不是 2的整數次方。但是開發者們還是習慣使⽤以2的整數次⽅去設定這些參數。)
//border參數:允許為紋理貼圖指定⼀個邊界寬度,如果不指定,可以直接寫0。
//format參數:OpenGL 的像素格式
//type參數:解釋參數pixels指向的資料,告訴OpenGL 使⽤緩存區中的什麼 資料類型來存儲顔⾊分量,像素資料的資料類型
//pixels參數:指向圖形資料的指針
void glTexImage1D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLint border,GLenum format,GLenum type,void *data);
void glTexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,void * data);
void glTexImage3D(GLenum target,GLint level,GLint internalformat,GLSizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,void *data);
生成紋理,設定紋理相關參數
生成紋理
紋理的生成主要包括兩步
- 配置設定紋理對象
glGenTextures
,簡記為 gen
- 綁定紋理狀态
glBindTexture
,簡記為 bind
//使⽤用函數配置設定紋理理對象
//指定紋理理對象的數量量 和 指針(指針指向⼀一個⽆無符号整形數組,由紋理理對象辨別符填充)。
void glGenTextures(GLsizei n,GLuint * textTures);
//綁定紋理理狀态 //參數target:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
//參數texture:需要綁定的紋理理對象
void glBindTexture(GLenum target,GLunit texture);
設定紋理參數
主要是設定紋理的縮小/放大的過濾方式、x/y軸上的環繞方式,這些參數的設定都是通過下列方法進行設定,可以了解為ios中 NSAttribute 對富文本參數的設定,都是通過指定參數,并設定對應的值
//參數1:target,指定這些參數将要應⽤用在那個紋理理模式上,⽐比如GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D。
//參數2:pname,指定需要設定那個紋理理參數
//參數3:param,設定特定的紋理理參數的值
glTexParameterf(GLenum target,GLenum pname,GLFloat param);
glTexParameteri(GLenum target,GLenum pname,GLint param);
glTexParameterfv(GLenum target,GLenum pname,GLFloat *param);
glTexParameteriv(GLenum target,GLenum pname,GLint *param);
-
過濾方式
常用的過濾方式有兩種:;鄰近過濾、線性過濾
==> 鄰近過濾(GL_NEAREST):根據字面意思就是選擇離目前位置最近的顔色
==> 線性過濾(GL_LINEAR):所有顔色綜合後的顔色,類似于顔色混合
==> 建議:紋理縮小時,使用鄰近過濾,紋理放大時,使用線性過濾
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);
-
環繞方式
環繞方式是指當紋理坐标超出預設範圍時,邊緣的顯示形式
環繞方式的設定主要是針對x、y軸設定的,而在紋理的描述中使用并不是x,y,而是 s,t
注意:
紋理中的 s, t, r, q 對應坐标系中的 x, y, z, w
//參數1: 紋理應用的次元,一般設定的都是 GL_TEXTURE_2D
// GL_TEXTURE_1D:一維
// GL_TEXTURE_2D: 二維
// GL_TEXTURE_3D: 三維
//參數2: 紋理坐标,一般設定s,t即可
// GL_TEXTURE_WRAP_S: 對應坐标系中的x軸
// GL_TEXTURE_T: 對應坐标系中的y軸
// GL_TEXTURE_R: 對應坐标系中的z軸
//參數3:紋理環繞方式
// GL_REPEAT:OpenGL 在紋理坐标超過1.0的⽅方向上對紋理進行重複;
// GL_CLAMP:所需的紋理單元取⾃紋理邊界或TEXTURE_BORDER_COLOR.
// GL_CLAMP_TO_EDGE環繞模式強制對範圍之外的紋理坐标沿着合法的紋理單元的最後⼀行或者最後⼀列來進⾏采樣。
// GL_CLAMP_TO_BORDER:在紋理理坐标在0.0到1.0範圍之外的隻使⽤邊界紋理單元。邊界紋理單元是作為圍繞基本圖像的額外的行和列,并與基本紋理圖像⼀一起加載的。
glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_S,GL_CLAMP_TO_EDGE); glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_T,GL_CLAMP_TO_EDGE);
紋理相關參考表格
紋理過濾方式
紋理的過濾方式-常量 | 說明 |
---|---|
GL_NEAREST | 在Mip基層上執行最鄰近過濾 |
GL_LINEAR | 在Mip基層執行線性過濾 |
GL_NEAREST_MIPMAP_NEAREST | 在最鄰近Mip層,并執行最鄰近過濾 |
GL_NEAREST_MIPMAP_LINEAR | 在MIP層之間執行線性插補,并執行最鄰近過濾 |
GL_LINEAR_MIPMAP_NWAREST | 選擇最鄰近的Mip層,并執行線性過濾 |
GL_LINEAR_MIPMAP_LINEAR | 在Mip層之間執行線性插補,并執行線性過濾,又稱三線性Mip貼圖 |
紋理的環繞方式
環繞方式 | 說明 |
---|---|
GL_REPEAT | 對紋理的預設行為,重複紋理圖像 |
GL_MIRRORED_REPEAT | 和GL_REPEAT一樣,但每次重複圖檔是鏡像放置的 |
GL_CLAMP_TO_EDGE | 紋理坐标會被限制到0和1之間,超出的部分會重複紋理坐标的邊緣,産生一種邊緣被拉伸的效果 |
GL_CLAMP_TO_BORDER | 超出的坐标為使用者指定的邊緣顔色 |
4種環繞方式的效果如圖所示
OpenGL像素格式
常用的
GL_RGB、GL_RGBA
等
常量 | 說明 |
---|---|
GL_RGB | 描述紅、綠、藍順序排列的顔⾊ |
GL_RGBA | 按照紅、綠、藍、Alpha順序排列的顔⾊ |
GL_BGR | 按照藍、綠、紅順序排列顔⾊ |
GL_BGRA | 按照藍、綠、紅、Alpha順序排列顔⾊ |
GL_RED | 每個像素隻包含了⼀個紅⾊分量 |
GL_GREEN | 每個像素隻包含了⼀個綠⾊分量 |
GL_BLUE | 每個像素隻包含了⼀個藍⾊分量 |
GL_RG | 每個像素依次包含了一個紅色和綠色的分量 |
GL_RED_INTEGER | 每個像素包含了一個整數形式的紅⾊分量 |
GL_GREEN_INTEGER | 每個像素包含了一個整數形式的綠色分量 |
GL_BLUE_INTEGER | 每個像素包含了一個整數形式的藍色分量 |
GL_RG_INTEGER | 每個像素依次包含了一個整數形式的紅⾊、綠⾊分量 |
GL_RGB_INTEGER | 每個像素包含了一個整數形式的紅⾊、藍⾊、綠色分量 |
GL_RGBA_INTEGER | 每個像素包含了一個整數形式的紅⾊、藍⾊、綠⾊、Alpah分量 |
GL_BGR_INTEGER | 每個像素包含了一個整數形式的藍⾊、綠⾊、紅色分量 |
GL_BGRA_INTEGER | 每個像素包含了一個整數形式的藍⾊、綠⾊、紅色、Alpah分量 |
GL_STENCIL_INDEX | 每個像素隻包含了一個模闆值 |
GL_DEPTH_COMPONENT | 每個像素隻包含一個深度值 |
GL_DEPTH_STENCIL | 每個像素包含一個深度值和一個模闆值 |
OpenGL像素資料的書籍類型
常用的是
GL_UNSIGNED_BYTE
常量 | 說明 |
---|---|
GL_UNSIGNED_BYTE | 每種顔色分量都是一個8位無符号整數 |
GL_BYTE | 8位有符号整數 |
GL_UNSIGNED_SHORT | 16位無符号整數 |
GL_SHORT | 16位有符号整數 |
CL_UNSIGNED_INT | 32位無符号整數 |
GL_INT | 32位有符号整數 |
GL_FLOAT | 單精度浮點數 |
GL_HALF_FLOAT | 半精度浮點數 |
GL_UNSIGNED_BYTE_3_2_3 | 包裝的RGB值 |
GL_UNSIGNED_BYTE_2_3_3_REV | 包裝的RGB值 |
GL_UNSIGNED_SHORT_5_6_5 | 包裝的RGB值 |
GL_UNSIGNED_SHORT_5_6_5_REV | 包裝的RGB值 |
GL_UNSIGNED_SHORT_4_4_4_4 | 包裝的RGB值 |
GL_UNSIGNED_SHORT_4_4_4_4_REV | 包裝的RGB值 |
GL_UNSIGNED_SHORT_5_5_5_1 | 包裝的RGB值 |
GL_UNSIGNED_SHORT_1_5_5_5_REV | 包裝的RGB值 |
GL_UNSIGNED_INT_8_8_8_8 | 包裝的RGB值 |
GL_UNSIGNED_INT_8_8_8_8_REV | 包裝的RGB值 |
GL_UNSIGNED_INT_10_10_10_2 | 包裝的RGB值 |
GL_UNSIGNED_INT_2_10_10_10_REV | 包裝的RGB值 |
GL_UNSIGNED_INT_24_8 | 包裝的RGB值 |
GL_UNSIGNED_INT_10F_11F_REV | 包裝的RGB值 |
GL_FLOAT_24_UNSIGNED_INT_24_8_REV | 包裝的RGB值 |
與紋理相關的其他API
改變/恢複像素存儲方式
這個API用的很少,一般很少去改變OpenGL中像素的存儲方式,主要都是使用預設的方式
API | 說明 |
---|---|
void glPixelStorei(GLenum pname,GLint param); | 改變像素存儲方式 |
void glPixelStoref(GLenum pname,GLfloat param); | 恢複像素存儲方式 |
- 參數1:OpenGL如何從資料緩存區解包圖像資料,即 像素的存儲方式
- 參數2:設定參數1中存儲方式的具體排列方式 即 像素讀取後的排列方式
例如:
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
- 參數1:
表示記憶體中每個像素行起點的排列請求,允許設定為以下值GL_UNPACK_ALIGNMENT
- 1:byte排列
- 2:排列為偶數byte的行
- 4:字word排列
- 8:行從雙位元組邊界開始
- 參數2:指定
設定的值GL_UNPACK_ALIGNMENT
載入紋理其他API
更新紋理
參數的說明參考載入紋理API的參數說明
void glTexSubImage1D(GLenum target,GLint level,GLint xOffset,GLsizei width,GLenum format,GLenum type,const GLvoid *data);
void glTexSubImage2D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const GLvoid *data);
void glTexSubImage3D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLint zOffset,GLsizei width,GLsizei height,GLsizei depth,Glenum type,const GLvoid * data);
插入替換紋理
參數的說明參考載入紋理API的參數說明
void glCopyTexSubImage1D(GLenum target,GLint level,GLint xoffset,GLint x,GLint y,GLsize width);
void glCopyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint x,GLint y,GLsizei width,GLsizei height);
void glCopyTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint zOffset,GLint x,GLint y,GLsizei width,GLsizei height);
使用顔色緩沖區家在資料,形成新的紋理
- 函數中的x、y是在顔色緩存區中指定的開始讀取紋理資料的位置
- 緩沖區中的資料是通過源緩沖區
設定的glReadBuffer
void glCopyTexImage1D(GLenum target,GLint level,GLenum internalformt,GLint x,GLint y,GLsizei width,GLint border);
void glCopyTexImage2D(GLenum target,GLint level,GLenum internalformt,GLint x,GLint y,GLsizei width,GLsizei height,GLint border);
注: 不存在glCopyTexImage2D,主要是因為無法從3D顔色緩存區中擷取體積資料
紋理對象其他API
删除綁定紋理、測試綁定紋理是否有效
//删除綁定紋理對象
//紋理對象 及 紋理對象指針(指針指向⼀一個⽆無符号整形數組,由紋理理對象辨別符填充)。
void glDeleteTextures(GLsizei n,GLuint *textures);
//測試紋理理對象是否有效
//如果texture是⼀個已經配置設定空間的紋理對象,那麼這個函數會傳回GL_TRUE,否則會傳回GL_FALSE。
GLboolean glIsTexture(GLuint texture);