glTexImage2D 介紹

? ? ?void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * data);

? ? ? 此函數(shù)式完成紋理ID申請(qǐng)后數(shù)據(jù)綁定功能。這個(gè)函數(shù)的第一個(gè)輸入?yún)?shù)的意思是指定texture object的類型,可以是GL_TEXTURE_2D,又或者是cubemap texture6面中的其中一面,通過(guò)GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z來(lái)指定,我們說(shuō)了cubemap的texture其實(shí)也就是由6個(gè)2D texture組成的,所以這個(gè)函數(shù)實(shí)際上是用于給一張2D texture賦值。剛才我們已經(jīng)說(shuō)過(guò)了,在bindTexture之后,對(duì)texture object的操作,需要先active對(duì)應(yīng)的紋理單元,然后再指定texture target來(lái)確定是哪個(gè)紋理,而不再通過(guò)buffer object name了(除非是對(duì)buffer object進(jìn)行刪除),由于GPU中同一時(shí)間一個(gè)thread的一個(gè)context中只能有一個(gè)紋理單元是處于被使用狀態(tài),而一個(gè)紋理單元最多只能有一個(gè)2D texture和一個(gè)cubemap的texture,所以在active了對(duì)應(yīng)的紋理單元之后,在這里通過(guò)target指定我們是操作2D texture還是cubemap texture的哪一面,就能精確的指定到我們實(shí)際操作的是哪個(gè)texture object。如果傳入其他的參數(shù),就會(huì)報(bào)INVALID_ENUM的錯(cuò)誤。第二個(gè)是指給該texture的第幾層賦值。上個(gè)課時(shí)我們也簡(jiǎn)單的介紹過(guò),沒(méi)有mipmap的texture,就相當(dāng)于只有一層mipmap,而有mipmap的texture就好比一層一層塔一樣,每一層都需要賦值。所以在這里需要確認(rèn)我們是給紋理的第幾層賦值,絕大多數(shù)情況是給第一層賦值,因?yàn)榧词辜y理需要mipmap,我們也經(jīng)常會(huì)使用glGenerateMipmap這個(gè)API去生成mipmap信息,而不直接賦值。glGenerateMipmap這個(gè)API一會(huì)我們?cè)僬f(shuō)。mipmap又稱LOD,level 0就是第一層mipmap,也就是圖像的基本層。如果level小于0,則會(huì)出現(xiàn)GL_INVALID_VALUE的錯(cuò)誤。而且level也不能太大,因?yàn)閠exture是由最大尺寸限制的,而第一層mipmap就是紋理的原始尺寸,而第二層mipmap的尺寸為原始寬高各除以2,依次類推,最后一層mipmap的尺寸為寬高均為1。所以如果level超過(guò)了log2(max),則會(huì)出現(xiàn)GL_INVALID_VALUE的錯(cuò)誤。這里的max,當(dāng)target為GL_TEXTURE_2D的時(shí)候,指的是GL_MAX_TEXTURE_SIZE,而當(dāng)target為其他情況的時(shí)候,指的是GL_MAX_CUBE_MAP_TEXTURE_SIZE。這里的GL_MAX_TEXTURE_SIZE和GL_MAX_CUBE_MAP_TEXTURE_SIZE,都可以通過(guò)glGet這個(gè)API獲取到。而且還有,假如圖像的寬或者高不是2的冪,那么有個(gè)專業(yè)術(shù)語(yǔ)叫做NPOT,non power of two。在OpenGL ES2.0中NPOT的texture是不支持mipmap的,所以針對(duì)NPOT的texture,如果level大于0,也就會(huì)出現(xiàn)GL_INVALID_VALUE的錯(cuò)誤。第三個(gè)參數(shù)internalformat,第七個(gè)參數(shù)format和第八個(gè)參數(shù)type我們放在一起來(lái)說(shuō),就是指定原始數(shù)據(jù)在從CPU傳入GPU之前,在CPU中的格式信息,以及傳入GPU之后,在GPU中的格式。internalformat,是用于指定紋理在GPU端的格式,只能是GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA。GL_ALPHA指的是每個(gè)像素點(diǎn)只有alpha通道,相當(dāng)于RGB通道全為0。GL_LUMINANCE指的是每個(gè)像素點(diǎn)只有一個(gè)luminance值,相當(dāng)于RGB的值全為luminance的值,alpha為1。GL_LUMINANCE_ALPHA指的是每個(gè)像素點(diǎn)有一個(gè)luminance值和一個(gè)alpha值,相當(dāng)于RGB的值全為luminance的值,alpha值保持不變。GL_RGB指的是每個(gè)像素點(diǎn)有一個(gè)red、一個(gè)green值和一個(gè)blue值,相當(dāng)于RGB的值保持不變,alpha為1。GL_RGBA指的是每個(gè)像素點(diǎn)有一個(gè)red、一個(gè)green值、一個(gè)blue值和一個(gè)alpha值,相當(dāng)于RGBA的值都保持不變。如果internalformat是其他值,則會(huì)出現(xiàn)GL_INVALID_VALUE的錯(cuò)誤。第七個(gè)參數(shù)format和第八個(gè)參數(shù)type,用于指定將會(huì)生成的紋理在所需要的信息在CPU中的存儲(chǔ)格式,其中format指定通道信息,只能是GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, and GL_LUMINANCE_ALPHA。type指的每個(gè)通道的位數(shù)以及按照什么方式保存,到時(shí)候讀取數(shù)據(jù)的時(shí)候是以byte還是以short來(lái)進(jìn)行讀取。只能是GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, and GL_UNSIGNED_SHORT_5_5_5_1。當(dāng)type為GL_UNSIGNED_BYTE的時(shí)候,每一個(gè)byte都保存的是一個(gè)顏色通道中的值,當(dāng)type為GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, and GL_UNSIGNED_SHORT_5_5_5_1的時(shí)候,每個(gè)short值中將包含了一個(gè)像素點(diǎn)的所有顏色信息,也就是包含了所有的顏色通道的值。從CPU往GPU傳輸數(shù)據(jù)生成紋理的時(shí)候,會(huì)將這些格式的信息轉(zhuǎn)成float值,方法是比如byte,那么就把值除以255,比如GL_UNSIGNED_SHORT_5_6_5,就把red和blue值除以31,green值除以63,然后再全部clamp到閉區(qū)間[0,1],設(shè)計(jì)這種type使得綠色更加精確,是因?yàn)槿祟惖囊曈X(jué)系統(tǒng)對(duì)綠色更敏感。而type為GL_UNSIGNED_SHORT_5_5_5_1使得只有1位存儲(chǔ)透明信息,使得每個(gè)像素要么透明要么不透明,這種格式比較適合字體,這樣可以使得顏色通道有更高的精度。如果format和type不是這些值,那么就會(huì)出現(xiàn)GL_INVALID_ENUM的錯(cuò)誤。

同樣的format在OpenGL ES2.0中,將對(duì)應(yīng)相同的internalformat,比如format GL_RGBA就對(duì)應(yīng)著internalformat GL_RGBA,format GL_ALPHA就對(duì)應(yīng)著internalformat GL_ALPHA,這里一共有5種format,也對(duì)應(yīng)著5種internalformat,分別是GL_RGBA,GL_RGB,GL_ALPHA,GL_LUMINANCE,GL_LUMINANCE_ALPHA。internalformat和format需要一一對(duì)應(yīng),而且確定了internalformat和format之后,type的選擇也受到了限制,比如針對(duì)internalformat和format為GL_RGB的時(shí)候,type只能是GL_UNSIGNED_SHORT_5_6_5或者GL_UNSIGNED_BYTE。而internalformat和format為GL_ALPHA的時(shí)候,type只能是GL_UNSIGNED_BYTE。internal format、format和type必須要對(duì)應(yīng)著使用。

第四個(gè)參數(shù)width和第五個(gè)參數(shù)height就是原始圖片的寬和高,也是新生成紋理的寬和高。因?yàn)閮烧呤且粯拥?,圖片信息以數(shù)據(jù)的形式從CPU傳到GPU,可能每個(gè)像素點(diǎn)格式和包含的信息會(huì)發(fā)生變化,但是圖片的大小,也就是像素點(diǎn)的數(shù)量,每行多少個(gè)像素點(diǎn),一共多少行,這個(gè)信息是不會(huì)發(fā)生變化的,這里我們說(shuō)的像素點(diǎn)其實(shí)在紋理的相關(guān)知識(shí)中還有一個(gè)專業(yè)術(shù)語(yǔ)叫做紋理像素texels,簡(jiǎn)稱紋素。width和height不能小于0,也不能當(dāng)target為GL_TEXTURE_2D的時(shí)候,超過(guò)GL_MAX_TEXTURE_SIZE,或者當(dāng)target為其他情況的時(shí)候,超過(guò)GL_MAX_CUBE_MAP_TEXTURE_SIZE,否則,就會(huì)出現(xiàn)GL_INVALID_VALUE的錯(cuò)誤。第6個(gè)參數(shù)border,代表著紋理是否有邊線,在這里必須寫成0,也就是沒(méi)有邊線,如果寫成其他值,則會(huì)出現(xiàn)GL_INVALID_VALUE的錯(cuò)誤。最后一個(gè)輸入?yún)?shù)也是上面準(zhǔn)備好的信息,意思是:data是CPU中一塊指向保存實(shí)際數(shù)據(jù)的內(nèi)存。如果data不為null,那么將會(huì)有width*height個(gè)像素的data從CPU端的data location開始讀取,然后會(huì)被從CPU端傳輸并且更新格式保存到GPU端的texture object中。當(dāng)然,從CPU讀取數(shù)據(jù)的時(shí)候要遵守剛才glPixelStorei設(shè)置的對(duì)齊規(guī)則。其中第一個(gè)數(shù)據(jù)對(duì)應(yīng)的是紋理中左下角那個(gè)頂點(diǎn)。然后第二個(gè)數(shù)據(jù)對(duì)應(yīng)的是紋理最下面一行左邊第二個(gè)點(diǎn),依次類推,按照從左到右的順序,然后一行完畢,從下往上再賦值下一行的順序,一直到最后一個(gè)數(shù)據(jù)對(duì)應(yīng)紋理中右上角那個(gè)頂點(diǎn)。如果data為null,那么執(zhí)行完這個(gè)API之后,依然會(huì)給texture object分配可以保存width*height那么多像素信息的內(nèi)存,但是沒(méi)有對(duì)這塊內(nèi)存進(jìn)行初始化,如果使用這個(gè)texture去繪制到圖片上,那么繪制出來(lái)的顏色值為undefine??梢酝ㄟ^(guò)glTexSubImage2D給這塊沒(méi)有初始化的內(nèi)存賦值。

這個(gè)函數(shù)沒(méi)有輸出參數(shù),但是有以下幾種情況會(huì)出錯(cuò),除了剛才說(shuō)的那些參數(shù)輸入錯(cuò)誤之外,還有如果target是CubeMap texture的一個(gè)面,但是width和height不相同,則會(huì)出現(xiàn)GL_INVALID_VALUE的錯(cuò)誤。如果format與internalformat不匹配,或者type與format不匹配(比如type為GL_UNSIGNED_SHORT_5_6_5 但是format 不是GL_RGB,或者type 是 GL_UNSIGNED_SHORT_4_4_4_4 或者 GL_UNSIGNED_SHORT_5_5_5_1 而 format 不是 GL_RGBA),則會(huì)出現(xiàn)GL_INVALID_OPERATION的錯(cuò)誤。

總結(jié)一下,這個(gè)命令的輸入為CPU內(nèi)存中以某種方式保存的像素?cái)?shù)據(jù),轉(zhuǎn)變成閉區(qū)間[0,1]的浮點(diǎn)型RGBA像素值,保存在GPU中的texture object內(nèi)。

一旦該命令被執(zhí)行,會(huì)立即將圖像像素?cái)?shù)據(jù)從CPU傳輸?shù)紾PU的內(nèi)存中,后續(xù)對(duì)客戶端數(shù)據(jù)的修改不會(huì)影響服務(wù)器中的texture object相關(guān)信息。所以在這個(gè)API執(zhí)行之后,客戶端中的圖像數(shù)據(jù)就可以被刪掉了。

如果一個(gè)texture object中已經(jīng)包含有內(nèi)容了,那么依然可以使用glTexImage2D對(duì)這個(gè)texture object中的內(nèi)容進(jìn)行替換。

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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