? ? ?void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * data);
? ? ? 此函數(shù)式完成紋理ID申請后數(shù)據(jù)綁定功能虹茶。這個函數(shù)的第一個輸入?yún)?shù)的意思是指定texture object的類型,可以是GL_TEXTURE_2D拾徙,又或者是cubemap texture6面中的其中一面尼啡,通過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來指定崖瞭,我們說了cubemap的texture其實也就是由6個2D texture組成的书聚,所以這個函數(shù)實際上是用于給一張2D texture賦值。剛才我們已經(jīng)說過了斩个,在bindTexture之后做个,對texture object的操作居暖,需要先active對應(yīng)的紋理單元,然后再指定texture target來確定是哪個紋理太闺,而不再通過buffer object name了(除非是對buffer object進行刪除),由于GPU中同一時間一個thread的一個context中只能有一個紋理單元是處于被使用狀態(tài),而一個紋理單元最多只能有一個2D texture和一個cubemap的texture灭贷,所以在active了對應(yīng)的紋理單元之后甚疟,在這里通過target指定我們是操作2D texture還是cubemap texture的哪一面览妖,就能精確的指定到我們實際操作的是哪個texture object檩电。如果傳入其他的參數(shù),就會報INVALID_ENUM的錯誤府树。第二個是指給該texture的第幾層賦值俐末。上個課時我們也簡單的介紹過,沒有mipmap的texture奄侠,就相當(dāng)于只有一層mipmap卓箫,而有mipmap的texture就好比一層一層塔一樣,每一層都需要賦值垄潮。所以在這里需要確認我們是給紋理的第幾層賦值烹卒,絕大多數(shù)情況是給第一層賦值闷盔,因為即使紋理需要mipmap,我們也經(jīng)常會使用glGenerateMipmap這個API去生成mipmap信息旅急,而不直接賦值逢勾。glGenerateMipmap這個API一會我們再說。mipmap又稱LOD坠非,level 0就是第一層mipmap盟迟,也就是圖像的基本層歉闰。如果level小于0凹炸,則會出現(xiàn)GL_INVALID_VALUE的錯誤变骡。而且level也不能太大,因為texture是由最大尺寸限制的,而第一層mipmap就是紋理的原始尺寸,而第二層mipmap的尺寸為原始寬高各除以2,依次類推而克,最后一層mipmap的尺寸為寬高均為1。所以如果level超過了log2(max),則會出現(xiàn)GL_INVALID_VALUE的錯誤。這里的max,當(dāng)target為GL_TEXTURE_2D的時候,指的是GL_MAX_TEXTURE_SIZE嗡综,而當(dāng)target為其他情況的時候碑幅,指的是GL_MAX_CUBE_MAP_TEXTURE_SIZE异吻。這里的GL_MAX_TEXTURE_SIZE和GL_MAX_CUBE_MAP_TEXTURE_SIZE,都可以通過glGet這個API獲取到。而且還有殊者,假如圖像的寬或者高不是2的冪海蔽,那么有個專業(yè)術(shù)語叫做NPOT域仇,non power of two。在OpenGL ES2.0中NPOT的texture是不支持mipmap的括改,所以針對NPOT的texture,如果level大于0,也就會出現(xiàn)GL_INVALID_VALUE的錯誤。第三個參數(shù)internalformat儡遮,第七個參數(shù)format和第八個參數(shù)type我們放在一起來說,就是指定原始數(shù)據(jù)在從CPU傳入GPU之前筛欢,在CPU中的格式信息剥险,以及傳入GPU之后么介,在GPU中的格式。internalformat跑慕,是用于指定紋理在GPU端的格式唤衫,只能是GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA悴侵。GL_ALPHA指的是每個像素點只有alpha通道怕品,相當(dāng)于RGB通道全為0。GL_LUMINANCE指的是每個像素點只有一個luminance值迎罗,相當(dāng)于RGB的值全為luminance的值尤辱,alpha為1。GL_LUMINANCE_ALPHA指的是每個像素點有一個luminance值和一個alpha值卒茬,相當(dāng)于RGB的值全為luminance的值郭赐,alpha值保持不變拉盾。GL_RGB指的是每個像素點有一個red、一個green值和一個blue值挤巡,相當(dāng)于RGB的值保持不變,alpha為1酷麦。GL_RGBA指的是每個像素點有一個red矿卑、一個green值、一個blue值和一個alpha值沃饶,相當(dāng)于RGBA的值都保持不變母廷。如果internalformat是其他值,則會出現(xiàn)GL_INVALID_VALUE的錯誤糊肤。第七個參數(shù)format和第八個參數(shù)type琴昆,用于指定將會生成的紋理在所需要的信息在CPU中的存儲格式,其中format指定通道信息馆揉,只能是GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, and GL_LUMINANCE_ALPHA业舍。type指的每個通道的位數(shù)以及按照什么方式保存,到時候讀取數(shù)據(jù)的時候是以byte還是以short來進行讀取升酣。只能是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的時候,每一個byte都保存的是一個顏色通道中的值噩茄,當(dāng)type為GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, and GL_UNSIGNED_SHORT_5_5_5_1的時候下面,每個short值中將包含了一個像素點的所有顏色信息,也就是包含了所有的顏色通道的值巢墅。從CPU往GPU傳輸數(shù)據(jù)生成紋理的時候诸狭,會將這些格式的信息轉(zhuǎn)成float值,方法是比如byte君纫,那么就把值除以255驯遇,比如GL_UNSIGNED_SHORT_5_6_5,就把red和blue值除以31蓄髓,green值除以63叉庐,然后再全部clamp到閉區(qū)間[0,1],設(shè)計這種type使得綠色更加精確会喝,是因為人類的視覺系統(tǒng)對綠色更敏感陡叠。而type為GL_UNSIGNED_SHORT_5_5_5_1使得只有1位存儲透明信息,使得每個像素要么透明要么不透明肢执,這種格式比較適合字體枉阵,這樣可以使得顏色通道有更高的精度。如果format和type不是這些值预茄,那么就會出現(xiàn)GL_INVALID_ENUM的錯誤兴溜。
同樣的format在OpenGL ES2.0中,將對應(yīng)相同的internalformat耻陕,比如format GL_RGBA就對應(yīng)著internalformat GL_RGBA拙徽,format GL_ALPHA就對應(yīng)著internalformat GL_ALPHA,這里一共有5種format诗宣,也對應(yīng)著5種internalformat膘怕,分別是GL_RGBA,GL_RGB召庞,GL_ALPHA岛心,GL_LUMINANCE,GL_LUMINANCE_ALPHA篮灼。internalformat和format需要一一對應(yīng)鹉梨,而且確定了internalformat和format之后,type的選擇也受到了限制穿稳,比如針對internalformat和format為GL_RGB的時候存皂,type只能是GL_UNSIGNED_SHORT_5_6_5或者GL_UNSIGNED_BYTE。而internalformat和format為GL_ALPHA的時候逢艘,type只能是GL_UNSIGNED_BYTE旦袋。internal format、format和type必須要對應(yīng)著使用它改。
第四個參數(shù)width和第五個參數(shù)height就是原始圖片的寬和高疤孕,也是新生成紋理的寬和高。因為兩者是一樣的央拖,圖片信息以數(shù)據(jù)的形式從CPU傳到GPU祭阀,可能每個像素點格式和包含的信息會發(fā)生變化鹉戚,但是圖片的大小,也就是像素點的數(shù)量专控,每行多少個像素點抹凳,一共多少行,這個信息是不會發(fā)生變化的伦腐,這里我們說的像素點其實在紋理的相關(guān)知識中還有一個專業(yè)術(shù)語叫做紋理像素texels赢底,簡稱紋素。width和height不能小于0柏蘑,也不能當(dāng)target為GL_TEXTURE_2D的時候幸冻,超過GL_MAX_TEXTURE_SIZE,或者當(dāng)target為其他情況的時候咳焚,超過GL_MAX_CUBE_MAP_TEXTURE_SIZE洽损,否則,就會出現(xiàn)GL_INVALID_VALUE的錯誤革半。第6個參數(shù)border趁啸,代表著紋理是否有邊線,在這里必須寫成0督惰,也就是沒有邊線不傅,如果寫成其他值,則會出現(xiàn)GL_INVALID_VALUE的錯誤赏胚。最后一個輸入?yún)?shù)也是上面準(zhǔn)備好的信息访娶,意思是:data是CPU中一塊指向保存實際數(shù)據(jù)的內(nèi)存。如果data不為null觉阅,那么將會有width*height個像素的data從CPU端的data location開始讀取崖疤,然后會被從CPU端傳輸并且更新格式保存到GPU端的texture object中。當(dāng)然典勇,從CPU讀取數(shù)據(jù)的時候要遵守剛才glPixelStorei設(shè)置的對齊規(guī)則劫哼。其中第一個數(shù)據(jù)對應(yīng)的是紋理中左下角那個頂點。然后第二個數(shù)據(jù)對應(yīng)的是紋理最下面一行左邊第二個點割笙,依次類推权烧,按照從左到右的順序,然后一行完畢伤溉,從下往上再賦值下一行的順序般码,一直到最后一個數(shù)據(jù)對應(yīng)紋理中右上角那個頂點。如果data為null乱顾,那么執(zhí)行完這個API之后板祝,依然會給texture object分配可以保存width*height那么多像素信息的內(nèi)存,但是沒有對這塊內(nèi)存進行初始化走净,如果使用這個texture去繪制到圖片上券时,那么繪制出來的顏色值為undefine孤里。可以通過glTexSubImage2D給這塊沒有初始化的內(nèi)存賦值橘洞。
這個函數(shù)沒有輸出參數(shù)捌袜,但是有以下幾種情況會出錯,除了剛才說的那些參數(shù)輸入錯誤之外震檩,還有如果target是CubeMap texture的一個面,但是width和height不相同蜓堕,則會出現(xiàn)GL_INVALID_VALUE的錯誤抛虏。如果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)迂猴,則會出現(xiàn)GL_INVALID_OPERATION的錯誤。
總結(jié)一下背伴,這個命令的輸入為CPU內(nèi)存中以某種方式保存的像素數(shù)據(jù)沸毁,轉(zhuǎn)變成閉區(qū)間[0,1]的浮點型RGBA像素值,保存在GPU中的texture object內(nèi)傻寂。
一旦該命令被執(zhí)行息尺,會立即將圖像像素數(shù)據(jù)從CPU傳輸?shù)紾PU的內(nèi)存中,后續(xù)對客戶端數(shù)據(jù)的修改不會影響服務(wù)器中的texture object相關(guān)信息疾掰。所以在這個API執(zhí)行之后搂誉,客戶端中的圖像數(shù)據(jù)就可以被刪掉了。
如果一個texture object中已經(jīng)包含有內(nèi)容了静檬,那么依然可以使用glTexImage2D對這個texture object中的內(nèi)容進行替換炭懊。