OpenGL ES手冊翻譯---3.柵格化(三)

3.7 紋理

紋理查找表把一個或者多個指定圖像的部分映射到碎片或者頂點上。通過指定(s,t,r)紋理坐標(biāo),采樣圖像在該坐標(biāo)位置上的顏色,在著色器中完成映射。紋理查詢表通常是用在更改碎片的RGBA顏色,有時候也在著色器中因為一些其他的目的使用。

著色器支持紋理使用,至少是在頂點著色器上(見2.10.5)有MAX_VERTEX_TEXTURE_IMAGE_UNITS圖像,在碎片著色器上有MAX_TEXTURE_IMAGE_UNITS圖像(見3.8.2)。多組紋理坐標(biāo)由普通的頂點屬性指定,或者通過著色器計算;這些坐標(biāo)用來采樣單獨的圖像。

下面的小節(jié)(這里到3.7.7節(jié))描述對單一紋理的操作,包括圖像到紋理映射的介紹和退昂在采集時使用過濾的方法。這里介紹的操作都是通過著色器分別采樣每個紋理的應(yīng)用。

在著色器中采樣紋理的細(xì)節(jié)在OpenGL ES Shading Language Specification中介紹。

函數(shù)

void ActiveTexture(enum texture);

是一個激活紋理圖像單元的選擇器,ACTIVE_TEXTURE。每個紋理圖像單元有在3.7節(jié)中定義的所有紋理狀態(tài)組成。

活躍紋理單元選擇器選擇被函數(shù)訪問的紋理圖像單元,這些函數(shù)是關(guān)于紋理圖像處理的,在3.7節(jié)中有定義。這些函數(shù),包括所有TexImage函數(shù)的變體函數(shù),BindTexture,和所有這種類型的查詢函數(shù)。如果ACTIVE_TEXTURE的當(dāng)前值對應(yīng)的紋理圖像單元的數(shù)量大于等于依賴實現(xiàn)的常量MAX_COMBINED_TEXTURE_IMAGE_UNITS,這樣的函數(shù)將會產(chǎn)生INVELID_OPERATION錯誤。

如果指定了無效的紋理,ActiveTexture會產(chǎn)生INVALID_ENUM錯誤。texutureTEXTUREi的符號化常量,表示紋理圖像單元i正在被修改。常量遵守等式:TEXTUREi = TEXTURE0 + i,i的范圍是0到MAX_COMBINED_TEXTURE_IMAGE_UNITS-1。

查詢活躍紋理圖像單元選擇器的狀態(tài)是一個單一的整數(shù)。初始值是TEXTURE0。

3.7.1 紋理圖像的指定

函數(shù)

void TexImage2D(enum target,int level, int internalformat, sizei width, sizei height, int border, enum format, enum type, void *data);

用來指定一個紋理圖像。target對二維的紋理,一定是TEXTURE_2D,對于立方體的紋理映射,一定是TEXTURE_CUBE_MAP_POSITIVE_X,TEXTURE_CUBE_MAP_NEGATIVE_X,TEXTURE_CUBE_MAP_POSITIVE_Y,TEXTURE_CUBE_MAP_NEGATIVE_Y,TEXTURE_CUBE_MAP_POSITIVE_Z,TEXTURE_CUBE_MAP_NEGATIVE_Z中的一個。format,type,data表示圖像數(shù)據(jù)格式,類型,和圖像數(shù)據(jù)在內(nèi)存中的指針,在3.6.2中有描述。

一個二維的紋理由單一的二維紋理圖像組成。一個立方體紋理貼圖,是一組六個二維的紋理圖像。六個立方體紋理目標(biāo)形成一個單一的立方體貼圖紋理,每個目標(biāo)命名立方體貼圖的不同面。上面列出的TEXTURE_CUBE_MAP_的目標(biāo)靶,會更新合適的立體貼圖面的2D紋理圖像。要注意,六個立體貼圖的二維圖像命令,比如TEXTURE_CUBE_MAP_POSITIVE_X會在指定,更新或者查詢立方體貼圖六個二維圖像時被使用,但當(dāng)開啟立方體貼圖紋理或者綁定到一個立方體貼圖紋理對象時(立方體貼圖被當(dāng)做是整體訪問而不是一個特殊的二維圖像),TEXTURE_CUBE_MAP是被指定的。

當(dāng)TexImage2Dtarget參數(shù)是六個立方體貼圖的二維圖像目標(biāo)靶中的一個時,如果widthheight的參數(shù)不相等,將會產(chǎn)生INVALID_VALUE錯誤。

內(nèi)存中的分組被認(rèn)為按照像矩形排列的。這個矩形就是一副圖像,圖像的尺寸和組織由TexImage2D通過widthheight來指定。

被選擇的組被按照3.6.2節(jié)中描述的那樣處理,在最終被擴展到RGBA。這樣產(chǎn)生的每個R,G,B,A的的值被鉗制到[0,1]內(nèi)。

通道選擇自R,G,B,A的值,來獲取由internalformat指定的基本內(nèi)部格式的紋理,紋理的基本內(nèi)部格式必須匹配format;在紋理圖像處理期間,在格式之間是不支持轉(zhuǎn)換的。表3.8總結(jié)了作為紋理圖像的一個基本內(nèi)部格式的函數(shù)時,R,G,B,A的值在紋理通道上的映射。internalformat可能是在表3.8中列出的五種內(nèi)部格式的符號化常量的其中一個。給internalformat指定的值如果不是表中列出的,就會產(chǎn)生INVALID_VALUE錯誤。如果internalformatformat不匹配,會產(chǎn)生INVALID_OPERATION錯誤。

image

GL按照紋理選擇的內(nèi)部通道組成存儲最終的紋理。內(nèi)部通道結(jié)構(gòu)的分配會根據(jù)TexImage2D的參數(shù)(除了target)發(fā)生變化,但一定不會是其他狀態(tài)的函數(shù),建立之后就不能被改變了。分配的空間一定是不變性的;當(dāng)紋理圖像被相同的參數(shù)值指定時,一定要選擇同一塊分配的空間。

圖像自身(data指針指向)是一些成組的數(shù)據(jù)的序列。第一組數(shù)據(jù)是紋理圖像的左下角。接下來的分組將寬為width的行從左到右填滿。height行從底到高堆積形成圖像。當(dāng)最終的R,G,B,A通道計算出了一個分組,他們就會被分配到如表3.8中描述的texel中去。從0開始,每個得出的第N個紋素被分配一個內(nèi)部的整數(shù)坐標(biāo):
i = (N \; mod \; width) \\ j = (\lfloor \frac{N}{width} \rfloor \; mod \;height)
因此,圖像的最后一行就是索引j就是圖像的高。

每個顏色通道被近似轉(zhuǎn)換成一個有n比特的修正點值,n是在圖像排列中的通道分配的存儲空間的比特數(shù)。我們假設(shè),使用不動點表示法表示把每個值k/(2^n-1)表示為k(比如1.0在二進(jìn)制中表示所有值的字符串),其中k\in\{0,1,...,2^n-1\}。

level參數(shù)在TexImage2D中是一個level-of-detail的整數(shù)數(shù)字。下面在Mipmapping上討論細(xì)節(jié)的等級。主要的紋理圖像有一個數(shù)字為0的細(xì)節(jié)等級,被稱為level zero array(或者0等級圖像數(shù)組)。如果level參數(shù)比0小,產(chǎn)生INVALID_VALUE參數(shù)。如果level比0打,而widthheight不是二的冪,也會產(chǎn)生INVALID_VALUE錯誤。

如果TexImage2Dborder參數(shù)不是0,會產(chǎn)生INVALID_VALUE錯誤。

如果w_t,h_t是圖像的寬和高,w_t,h_t比0小,會產(chǎn)生INVALID_VALUE錯誤。

對于參數(shù)為k的0級別的圖像陣列,二維紋理圖像的最大允許的寬高至少是2^{k-lod},k是MAX_TEXUTRE_SIZE的以2為底的對數(shù),lod是圖像陣列的詳細(xì)等級。比k大的任何詳細(xì)等級的圖像陣列都有可能是0。如果指定圖像在存儲的時候過大,將會產(chǎn)生INVALID_VALUE錯誤。

立方體貼圖紋理的允許的最大寬高一定是相同的,對于參數(shù)為k的0級別的圖像陣列至少是2^{k-lod},k是MAX_CUBE_MAP_TEXTURE_SIZE的以2為底的對數(shù)。

只有如果單一的圖像陣列可以被支持時,0等級的圖像陣列才是可以被允許實現(xiàn)的。另外的關(guān)于等級1或者更大等級的圖像陣列的創(chuàng)建的約束條件在3.7.10節(jié)中會詳細(xì)講解。

圖像指針指向給GL的圖像,這些圖像被解碼然后被拷貝到GL內(nèi)部的內(nèi)存中。

我們把解碼后的圖像稱作texture array。一個紋理數(shù)組有如上定義的寬和高w_t,h_t。

紋理數(shù)組的元素(i,j)被稱為texel(紋素)。在紋理化碎片時的紋理值由碎片相關(guān)聯(lián)的坐標(biāo)(s,t)所決定,但并不是一定要相應(yīng)一些實際的紋素。見圖3.6。

image

如果TexImage2Ddata參數(shù)是一個空指針(在C實現(xiàn)中是一個0值的指針),將會使用指定的target,level,internalformat,width,height生成紋理數(shù)組,但是沒有圖像內(nèi)容。這種情況下,在客戶端內(nèi)存中沒有像素值,也沒有像素處理操作被執(zhí)行。會產(chǎn)生錯誤,但是,卻感覺數(shù)據(jù)指針是有效的。

3.7.2 選擇紋理圖像規(guī)定函數(shù)

紋理圖像也可以用從幀緩沖中獲取圖像數(shù)據(jù)來指定,已經(jīng)存在的紋理圖像的矩形子區(qū)域也可以被重新指定。

函數(shù)

void CopyTexImage2D(enum target, int level, enum internalformat, int x, int y, sizei width, sizei height, int border);

正好就是定義了TexImage2D操作下的紋理數(shù)組,只是圖像數(shù)據(jù)是從幀緩沖中獲取的而不是客戶端中,target一定是TEXTURE_2D,TEXTURE_CUBE_MAP_POSITIVE_X,TEXTURE_CUBE_MAP_NEGATIVE_X,TEXTURE_CUBE_MAP_POSITIVE_Y,TEXTURE_CUBE_MAP_NEGATIVE_Y,TEXTURE_CUBE_MAP_POSITIVE_Z,TEXTURE_CUBE_MAP_NEGATIVE_Z中的一個。x,y,width,heightReadPixel的相關(guān)參數(shù)相同(參考4.3.1節(jié)),指定了幀緩沖區(qū)域中要拷貝的圖像的寬高和左下角坐標(biāo)(x,y)。確切來講,圖像是從幀緩沖的顏色緩沖中獲取的,就好像把這些參數(shù)設(shè)置給ReadPixel并把fromat參數(shù)設(shè)置為RGBA一樣,在轉(zhuǎn)換為RGBA值后圖像獲取就會停止。接下來的處理過程和TexImage2D中描述的一樣,從結(jié)果像素分組中的R,G,B,A值嵌拉開始。參數(shù)level,internalformat,border用一樣的值指定,和在TexImage2D中的參數(shù)是一樣的意思。interformat受到更多的限制,這樣顏色緩沖區(qū)通道在轉(zhuǎn)換為internalformat時可以丟掉,但是新的顏色通道不能被添加。比如,RGB顏色緩沖區(qū)可以被用來創(chuàng)造LUMINANCE或者RGB的紋理,但是不能用來創(chuàng)造ALPHA,LUMINANCE_ALPHA,RGBA的紋理。表3.9總結(jié)了允許的幀緩沖和基本內(nèi)部格式的結(jié)合方式。如果幀緩沖格式和基本紋理格式不匹配,會產(chǎn)生INVALID_OPERATION錯誤。width,height,border這些參數(shù)的限制和TexImage2D的參數(shù)是相同的。

image

當(dāng)CopyTexImage2Dtarget參數(shù)是六個立方體貼圖的二維圖像目標(biāo)靶,在width,height不相等時,會產(chǎn)生INVALID_VALUDE的錯誤。

另外兩個函數(shù):

void TexSubImage2D(enum target,int level, int xoffset, int yoffset, sizei width, sizei height, enum format, enum type, void *data);

void CopyTexSubImage2D(enum target, int level, int xoffset, int yoffset, int x, int y sizei width, sizei height);

僅僅是重新指定了存在的紋理矩陣的矩形子區(qū)域。在internalformat,width, height這些指定的紋理矩陣的參數(shù)上都沒有發(fā)生變化,在超出子區(qū)域的范圍的紋素值也不會發(fā)生變化。 TexSubImage2D,CopyTexSubImage2Dtarget參數(shù)一定是TEXTURE_2D,TEXTURE_CUBE_MAP_POSITIVE_X,TEXTURE_CUBE_MAP_NEGATIVE_X,TEXTURE_CUBE_MAP_POSITIVE_Y,TEXTURE_CUBE_MAP_NEGATIVE_Y,TEXTURE_CUBE_MAP_POSITIVE_Z,TEXTURE_CUBE_MAP_NEGATIVE_Z中的一個。每個函數(shù)的level參數(shù)指定要修改的紋理矩陣的詳細(xì)等級。如果level比0小或者比最大紋理寬度或者高度的以2為底的對數(shù)大,會產(chǎn)生INVALID_VALUE錯誤。

函數(shù)TexSubImage2D的參數(shù)width,height,format, type, data都和TexImage2D對應(yīng)的參數(shù)是匹配的,意味著他們可以有相同的值,并產(chǎn)生相同的作用。

函數(shù)CopyTexSubImage2D的參數(shù)x,y,width, heightCopyTexImage2D對應(yīng)的參數(shù)是相同的。每個TexSubImage函數(shù)用和對應(yīng)的TexImage完全相同的方式解釋和處理像素組,除非給為例通道分配的R,G,B,A像素組的值被紋理矩陣的internalformat參數(shù)控制了,而不是該函數(shù)的參數(shù)控制。紋理矩陣使用TexSubImage函數(shù)參數(shù)fromatinternalformat時應(yīng)用的約束和錯誤,被重新指定用在TexImage對應(yīng)的函數(shù)的參數(shù)formatinternalformat上。

函數(shù)TexSubImage2D,CopyTexSubImage2D的參數(shù)xoffsetyoffset指定了紋理矩陣的widthheight高的矩形子區(qū)域中左下角的紋素坐標(biāo),如圖3.6。w_t,h_t代指紋理矩陣的寬高,x,y,w,h指xoffset, yosset, width, height參數(shù)的值,滿足下面的關(guān)系將會產(chǎn)生INVALID_VALUE錯誤。
x<0 \\ x+w>w_t \\ y<0 \\ y+h>h_t

從0計數(shù),給第n個像素組分配內(nèi)部整數(shù)坐標(biāo)為[i,j]的紋素:
i = x + (n \,mod\,w) \\ j = y + (\lfloor \frac{n}{w} \rfloor \, mod \, h)

如果綁定到FRAMEBUFFER_BINDING的對象不是完整的幀緩沖(見4.4.5節(jié)),調(diào)用CopyTexImage2D或者CopyTexSubImage2D會產(chǎn)生INVALID_FRAMEBUFFER_OPERATION錯誤。

  • 紋理拷貝的反饋回路

如果目標(biāo)紋理圖像等級也綁定到了要讀的幀緩沖的選定的緩沖區(qū)上,調(diào)用CopyTexImage2D或者CopyTexSubImage2D會導(dǎo)致未定義的行為。這種情況在4.4.4節(jié)中的反饋回路的詳細(xì)描述中會有更多的討論。

3.7.3 壓縮紋理圖像

紋理圖像也可以使用按照已知壓縮圖像格式存儲的圖像數(shù)據(jù)來指定或者修改。GL沒有定義指定的壓縮格式,但是壓縮格式可以由GL擴展來定義。有一種可以獲取壓縮格式token值的機制;通過查詢NUM_COMPRESSED_TEXTURE_FORMATS的值可以獲取到指定的壓縮內(nèi)部格式支持的數(shù)目。渲染器支持的特定的壓縮內(nèi)部格式可以通過查詢COMPRESSED_TEXTURE_FORMATS獲取。查詢返回的結(jié)果值就是internalformat參數(shù)相關(guān)且能被CompressedTexImage2D函數(shù)接受的,而且適合通用目的的用處。渲染器不會枚舉那些有在使用之前需要特殊理解的限制的格式。

函數(shù)

void CompressedTexImage2D(enum target, int level, enum internalformat, sizei width, sizei height, int border, sizei imageSize, void *data);

定義了一張紋理圖像,這張圖像的輸入的數(shù)據(jù)按照指定的壓縮圖像格式被存儲的。target,level,internalformat,width,height,border參數(shù)和TexImage2D是一樣的。data指向被壓縮的圖像數(shù)據(jù)中,這些圖像數(shù)據(jù)是按照internalformat相關(guān)的壓縮圖像格式存儲起來的。

對于所有的壓縮內(nèi)部格式,壓縮圖像將會根據(jù)internalformat的定義解碼。壓縮紋理圖像被看做是一個imageSize大小的ubyte的數(shù)組,這個數(shù)組的起始地址為data。當(dāng)解碼壓縮紋理圖像時,所有的像素存儲和像素轉(zhuǎn)移都會被忽略。如果imageSize參數(shù)和格式,維度以及壓縮圖像的內(nèi)容不一致,會產(chǎn)生INVALID_VALUE的錯誤結(jié)果。如果壓縮圖像沒有根據(jù)定義的圖像格式編碼,調(diào)用函數(shù)的結(jié)果是未定義的。

在使用壓縮圖像規(guī)范調(diào)用參數(shù)時,指定的壓縮內(nèi)部格式會強制實行一些格式相關(guān)的限制。比如,壓縮圖像格式可能不會允許寬和高的值不是4的倍數(shù)。這些限制將會在定義壓縮內(nèi)部格式的擴展規(guī)范書中記錄。違背這些限制將會導(dǎo)致INVALID_OPERATION錯誤。

任何由特定壓縮內(nèi)部格式強制實行的限制認(rèn)真對待圖像內(nèi)容是不變的,意味著如果GL接受并存儲一張壓縮格式的紋理圖像,CompressedTexImage2D將會接受任何合適的編碼壓縮紋理圖像,這些圖像的寬,高,壓縮圖像大小都是相同的,存儲時的壓縮內(nèi)部格式也在同一個紋理詳細(xì)等級上。

  • 重新指定壓縮紋理的子圖像

函數(shù)

void CompressedTexSubImage2D(enum target, int level, int xoffset, int yoffset, sizei width, sizei height, enum format, sizei imageSize, void *data);

用已知的壓縮圖格式存儲的數(shù)據(jù),重新指定了已經(jīng)存在的紋理矩陣的一個矩形區(qū)域。target,level,xoffset,yoffest,width,height,format參數(shù)的意義和TexSubImage2D是相同。data指針指向和format相關(guān)的壓縮圖像格式的壓縮圖像數(shù)據(jù)。

dataimageSize參數(shù)指向的圖像數(shù)據(jù)被認(rèn)為是由CompresseTexImage2D提供的。這個函數(shù)不提供圖像格式轉(zhuǎn)換,所以如果format不匹配要被修改的紋理圖像的內(nèi)部格式,將會產(chǎn)生* INVALID_OPERATION錯誤。如果imageSize參數(shù)和格式,維度,壓縮圖像的內(nèi)容(太少或者太多的數(shù)據(jù))不一致,將會產(chǎn)生INVALID_VALUE*。

至于CompressedTexImage的調(diào)用,壓縮內(nèi)部格式在使用壓縮圖像規(guī)范調(diào)用和參數(shù)是,有額外附加的限制。任何這樣的限制在定義壓縮內(nèi)部格式的規(guī)格書中都會有記錄;違反這些限制將會導(dǎo)致INVALID_OPERATION錯誤。

指定壓縮內(nèi)部格式強制的要求的限制對于處理圖像內(nèi)容是不變的,意味著如果GL存儲或者接受了一個壓縮格式下的紋理圖像,CompressedTexSubImage2D將會接受任何合適的編碼壓縮的紋理圖像,這些紋理圖像有相同的寬,高,壓縮圖像大小,存儲的壓縮內(nèi)部格式在同一紋理級別。

調(diào)用CompressedTexSubImage2D圖像時,如果xoffset或者yoffset不等于0,或者widthheight和紋理的寬高各自不匹配,將會導(dǎo)致INVALID_OPERATION錯誤。通過調(diào)用修改的區(qū)域以為的任何紋素的內(nèi)容都是未定義的。這些限制,可能在特定的壓縮內(nèi)部格式且這些格式的圖像很容易修改時,比較寬松。

3.7.4 紋理參數(shù)

當(dāng)紋理在被指定或者改變,當(dāng)紋理被應(yīng)用到著色器上是,變化的參數(shù)控制著紋理矩陣是如何被處理的。參數(shù)通過下面函數(shù)設(shè)置

void TexParameter{if}(enum target, enum pname, T param);
void texParameter{if}v(enum target, enum pname, T params);

target是目標(biāo)靶,一定是TEXTURE_2D或者TEXTURE_CUBE_MAP中的一個。pname是指定參數(shù)設(shè)置的符號化常量;可能的常量和相應(yīng)的參數(shù)總結(jié)在表3.10中。在函數(shù)的第一種形式中,param是一個設(shè)置單值參數(shù)的值;函數(shù)的第二種形式中,param是一個類型依靠設(shè)置的參數(shù)的參數(shù)數(shù)組。

image

立方體貼圖紋理的紋理參數(shù)全部應(yīng)用在立方體貼圖上;六個不同的二維紋理圖像使用立方體貼圖自己的紋理參數(shù)。

3.7.5 立方體貼圖紋理選擇

當(dāng)在著色器中使用立方體紋理貼圖,(s,t,r)紋理坐標(biāo)被當(dāng)做是從立方體的中心發(fā)出的方向向量(r_x,r_y,r_z)(q坐標(biāo)是可以忽略的,因為它值放縮向量但不影響方向)。在紋理應(yīng)用期間,插入的每個碎片的方向向量根據(jù)最大量值坐標(biāo)方向(主軸方向)會選擇立方體貼圖的面的二維的圖像中的一個。如果兩個或者多個坐標(biāo)有相同的量值,實現(xiàn)時可以定義規(guī)則來消除這種情形的歧義。規(guī)則必須決定性的且只依賴于(r_x,r_y,r_z)。在3.11表中的目標(biāo)靶一列解釋了主軸方向如何映射到一個特定的立方體貼圖目標(biāo)靶的二維圖像上。

image

使用在表3.11中指定的由主軸方向決定的s_c,t_c,m_a,更新的(s,t)通過下面算是計算:
s = \frac{1}{2}(\frac{s_c}{|m_a|}+1) \\ t = \frac{1}{2}(\frac{t_c}{|m_a|}+1)
新的值(s t)通過使用3.7.6到3.7.8節(jié)中給出的規(guī)則,來發(fā)現(xiàn)在已經(jīng)確定的朝向面的二維紋理圖像的紋理值。

3.7.6 紋理的包裹模式

包裹模式分別由TEXTURE_WRAP_STEXTURE_WRAP_T的值定義,包裹模式會影響紋理坐標(biāo)s和t的解釋。下面描述每種模式的效果。

  • 包裹模式 REPEAT

包裹模式REPEAT會忽略紋理坐標(biāo)系的整數(shù)部分,僅僅使用小數(shù)部分。(對于數(shù)字f,f的小數(shù)部分是f-|f|,不考慮f的符號;記得\lfloor\rfloor函數(shù)是往-\infty朝向截斷的)。
REPEAT是所有紋理坐標(biāo)的默認(rèn)行為。

  • 包裹模式 CLAMP_TO_EDGE

包裹模式ClAMP_TO_EDGE把紋理坐標(biāo)鉗制在所有的mip圖級別中,這樣,紋理過濾器就不會采集紋理圖像以外的值。返回的顏色在鉗制時僅僅來自于紋理圖像邊緣的紋素。

紋理坐標(biāo)被鉗制在[min, max]的范圍中,最小值被定義為
min = \frac {1}{2N}
N是在鉗制方向的紋理圖像的大小。最大值被定義為
max = 1-min
所以鉗制總是關(guān)于紋理坐標(biāo)的[0,1]映射區(qū)間對稱。

  • 包裹模式 MIRRORED_REPEAT

包裹模式MIRRORED_REPEAT先會對紋理坐標(biāo)做鏡像,值f的鏡像計算如下:
mirror(f) = \begin{cases} f-|f|, & \lfloor f \rfloor \text {是偶數(shù)} \\ 1-(f-|f|), & \lfloor f \rfloor \text {是奇數(shù)} \end{cases}

然后如同上述描述的包裹模式CLAMP_TO_EDGE那樣,被鏡像的坐標(biāo)被固定起來。

3.7.7 紋理縮小化

在圖元上使用紋理意味著要把紋理圖像空間映射到幀緩沖圖像空間??傮w上來說,這個映射過程涉及到采樣紋理圖像的重建,然后在幀緩沖空間映射過程的相同的包裹模式,然后是一個濾波器,最后一步,在應(yīng)用到碎片之前,是一副被濾波的,被包裹的,被重建的圖像的重采樣。在GL中,這個映射由兩個簡單的過濾方案來近似。一種方案的選擇是基于從紋理空間到幀緩沖空間的映射是否被認(rèn)為是放大或者縮小了紋理圖像。

  • 放縮因子和細(xì)節(jié)等級

這種行為被一個放縮因\rho(x,y)和細(xì)節(jié)等級參數(shù)\lambda(x,y)管理,公式是:
\lambda(x,y) = \log_2[\rho(x,y)] \qquad (3.11)
如果\lambda(x,y)小于或者等于常數(shù)c(在3.7.8節(jié)中描述),紋理圖像就被認(rèn)為是放大了;如果大于c,紋理圖像就是被縮小了。

讓函數(shù)s(x,y)把在圖元內(nèi)的每組窗口坐標(biāo)(x,y)和紋理坐標(biāo)s關(guān)聯(lián)起來;t(x,y)類似。讓u(x,y) = w_t \times s(x,y), v(x,y) = h_t \times t(x,y),w_t,h_t是0級別圖像矩陣的寬高。對于一個多邊形,窗口坐標(biāo)(x,y)在碎片上的\rho計算:

\rho = \max \{ \sqrt{ (\frac{\partial u}{\partial x})^2+ (\frac{\partial v}{\partial x})^2},\sqrt{(\frac{\partial u}{\partial y})^2 + (\frac {\partial v}{\partial y})^2} \} \qquad (3.12)
\partial u / \partial x是u關(guān)于窗口x的導(dǎo)數(shù),其他的導(dǎo)數(shù)也相同。

對于直線,公式是:
\rho = \sqrt{(\frac{\partial u}{\partial x}\Delta x +\frac{\partial u}{\partial y}\Delta y)^2,(\frac{\partial v}{\partial x}\Delta x +\frac{\partial v}{\partial y}\Delta y)^2} / l, \qquad (3.13)
其中\Delta x = x_2-x_1, \Delta y = y_2-y_1(x_1,y_1),(x_2,y_2)是部分的窗口坐標(biāo),l = \sqrt{\Delta x^2+\Delta y^2}。對于一個點來說,\rho \equiv 1。

盡管通常認(rèn)為3.12和3.13會給出紋理過程中最好的值,但是他們的實現(xiàn)是不能被實踐的。因此,在服從下面這些條件是,實現(xiàn)時可以用函數(shù)f(x,y)近似為理想的\rho

  1. f(x,y)在每個|\partial u / \partial x|,|\partial u / \partial y|,|\partial v / \partial x|,|\partial v / \partial y|都是連續(xù)單調(diào)的。
  2. m_u = \max \{ |\frac{\partial u}{\partial x}|,|\frac{\partial u}{\partial y}|\},m_v = \max \{ |\frac{\partial v}{\partial x}|,|\frac{\partial v}{\partial y}|\},其中,\max{\{m_u,m_v\}} \le f(x,y) \le m_u+m_v.

當(dāng)\lambda指代縮小時,分配給TEXTURE_MIN_FILTER的值被用來決定碎片的紋理是怎樣選擇的。當(dāng)TEXTURE_MIN_FILTERNEAREST時,坐標(biāo)(s,t)指定的在0等級陣列中距離最近的(曼哈頓距離)紋素就會被獲取到。這意味著在(i,j)位置的紋素會變成紋理值,i的公式:
i = \begin{cases} \lfloor u \rfloor, & s<1 \\ w_t-1, & s=1 \end{cases} \qquad (3.14)
(注意TEXTURE_WRAP_SREPEAT,0 \le s <1)同樣的,j的公式為:
i = \begin{cases} \lfloor v \rfloor, & t<1 \\ h_t-1, & t=1 \end{cases} \qquad (3.15)

當(dāng)TEXTURE_MIN_FILTERLINEAR,在0等級圖像陣列中2X2的方形紋素就會被選擇。這個方塊如同3.7.6中那樣首先獲取第一次包裹的紋理坐標(biāo),然后計算:
i_0 = \begin{cases} \lfloor u-1/2 \rfloor \,mod \, w_t,& \text {TEXTURE_WRAP_S is REPEAT} \\ \lfloor u-1/2 \rfloor, &\text{otherwise} \end{cases}
j_0 = \begin{cases} \lfloor v-1/2 \rfloor \,mod \, h_t,&\text{TEXTURE_WRAP_T is REPEAT} \\ \lfloor v-1/2 \rfloor, &\text{otherwise} \end{cases}
i_1 = \begin{cases} (i_0+1)\,mod \, w_t,&\text{TEXTURE_WRAP_S is REPEAT} \\ i_0+1 , &\text{otherwise} \end{cases}
j_1 = \begin{cases} (j_0+1) \,mod \, h_t,&\text{TEXTURE_WRAP_T is REPEAT} \\ j_0+1 , &\text{otherwise} \end{cases}
\alpha = frac(u-1/2) \\ \beta = frac(v-1/2)
其中frac(x)表示x的小數(shù)部分。
紋理值\tau的公式如下:
\tau = (1-\alpha)(1-\beta)\tau_{i0j0}+\alpha(1-\beta)\tau_{i1j0}+(1-\alpha)\beta\tau_{i0j1}+\alpha\beta\tau_{i1j1} \quad(3.16)
其中\tau_{ij}是在紋理圖像的(i,j)位置的紋素。

  • 反饋回路渲染過程

一個渲染反饋回路發(fā)生在當(dāng)一個紋理附著在當(dāng)前邊界幀緩沖對象的附著點上。這種情況下渲染結(jié)果是未定義的。準(zhǔn)確的條件在4.4.4節(jié)中有詳細(xì)描述。

  • Mip映射

TEXTURE_MIN_FILTER的值NEAREST_MIPMAP_NEAREST,NEAREST_MIPMAP_LINEAR,LINEAR_MIPMAP_NEAREST,LINEAR_MIPMAP_LINEAR,每一個都需要用到mipmap。mipmap是一組表現(xiàn)相同圖像的順序圖像陣列;每個圖像陣列的分辨率都比前一個低一點。如果0級別的圖像陣列有分辨率為w_b \times h_b,那么在mipmap中會有\lfloor log_2(\max(w_b,h_b)) \rfloor + 1個圖像陣列。每個隨后的圖像陣列的的分辨率為:
\max(1, \lfloor \frac{w_b}{2^i} \rfloor) \times \max(1,\lfloor \frac{h_b}{2^i} \rfloor)
知道最后一個圖像陣列的維度為1 \times 1。

在使用TexImage2D或者CopyTexImage2D時可以定義在mip圖中的每個圖像陣列;被設(shè)置的圖像陣列使用參數(shù)level來指定細(xì)節(jié)的等級。從原始紋理數(shù)組的等級0,到通過公式q = \lfloor log_2(\max(w_b,h_b)) \rfloor來計算每個單元增量,這些細(xì)節(jié)等級的數(shù)字表示一組圖像陣列,正如描述過的那樣,每個圖像陣列都是前一個一半的分辨率(如果有小數(shù)部分,就去下一個整數(shù))。所有從0到q的圖像陣列都是被定義的,在3.7.10中會討論。

如果在mip圖中的任一圖像陣列的維度不是2的平方(例如,像上面描述的那樣向下取整),這個mip圖就會被當(dāng)做不是二的指數(shù)型的紋理。這種紋理在紋理包裹模式和濾波時會有一些限制,在3.8.2節(jié)中介紹。

mip圖和細(xì)節(jié)等級結(jié)合使用,來近似的將比較合適的過濾過的紋理應(yīng)用到碎片上。從最小到最大的變化發(fā)生時,讓\lambda的值為c。(因為這個討論和最小化有關(guān),我們只關(guān)心當(dāng)\lambda >c\lambda的值)。

對于mip圖的濾波器NEAREST_MIPMAP_NEARESTLINEAR_MIPMAP_NEAREST,在mip圖中的第d個圖像被選擇時,有
d = \begin{cases} 0, & \lambda \le \frac{1}{2} \\ \lceil \lambda + \frac{1}{2}\rceil - 1, & \lambda > \frac{1}{2}, \lambda \le q + \frac{1}{2} \\ q, & \lambda > q + \frac{1}{2} \end{cases} \qquad (3.17)
NEARESTLINEAR的過濾規(guī)則然后被用在數(shù)組陣列的選擇中。

對于mip圖的濾波器NEAREST_MIPMAP_LINEARLINEAR_MIPMAP_LINEAR,d_1,d_2等級的mip圖總是被選擇的,有

d_1 = \begin{cases} q, & \lambda \ge q \\ \lfloor \lambda \rfloor, & otherwise \end{cases} \qquad (3.18) \\ d_2 = \begin{cases} q, & \lambda \ge q \\ d_1+1, & otherwise \end{cases} \qquad (3.19)

NEAREST或者LINEAR濾波器的規(guī)則被應(yīng)用到每個被選擇的圖像陣列上,產(chǎn)生兩個相對應(yīng)紋理值\tau_1,\tau_2。最終的紋理值計算公式為:
\tau = [1-frac(\lambda)]\tau_1 + frac(\lambda)\tau_2.

3.7.8 紋理最大化

當(dāng)\lambda指放大系數(shù),TEXTURE_MAG_FILTER的值會決定紋理值的獲取方式。TEXTURE_MAG_FILTER有兩種可能的值:NEARESTLINEAR。NEAREST的表現(xiàn)和TEXTURE_MIN_FILTERNEAREST(公式3.14和3.15中使用的)完全一樣;LINEAR的表現(xiàn)和TEXTURE_MIN_FILTERLINEAR(公式3.16中使用的)完全一樣。0等級的圖像陣列總是用在最大化中。

最后有一個c值的選擇問題,是點的放大還是縮小的轉(zhuǎn)換點。如果放大濾波器是由LINEAR給出的,縮小濾波器是由NEAREST_MIPMAP_NEAREST或者NEAREST_MIPMAP_LINEAR給出的,那么c=0.5。這樣做是為了保證一個縮小的紋理不會比放大的紋理更“尖銳”。否則c=0。

3.7.9 紋理幀緩沖附著

如果下面的條件都成立,紋理值會被認(rèn)為是無定義的:

  • 當(dāng)前的FRAMEBUFFER_BINDING命名了一個應(yīng)用程序創(chuàng)建的幀緩沖對象F。
  • 紋理附著在幀緩沖對象F的附著點A上
  • TEXTURE_MIN_FILTERNEAREST或者LINEAR,附著點A的FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL的值是0;或者TEXTURE_MIN_FILTERNEAREST_MIPMAP_NEAREST,NEAREST_MIPMAP_LINEAR,LINEAR_MIPMAP_NEAREST,LINEAR_MIPMAP_LINEAR,而且A的FREAMBUFFER_ATTACHMENT_TEXTURE_LEVEL值是在0到最后的mip等級的閉區(qū)間中。

3.7.10 紋理的完整性和不是2的指數(shù)型紋理

紋理的完整性是指,如果所有的圖像陣列和紋理應(yīng)用所使用的紋理所必要的紋理參數(shù)都被一致定義過。

二維的紋理的完整性需要下面的條件為真:

  • 從0到q的mip圖像陣列數(shù)組(q的定義在3.7.7節(jié)中的Mipmapping的定義中討論過)中的每個陣列都被指定了相同的格式,內(nèi)部格式和類型。
  • 圖像陣列的維數(shù)和3.7.7節(jié)中Mipmapping中描述的一樣按照序列排列。
  • 每個0等級的圖像整理的維數(shù)是正的。

對于立方體貼圖紋理,一個紋理的“立方體完整性”需要滿足一下條件:

  • 六個紋理圖像的每一個的0級別陣列使得立方體貼圖有相等的,正數(shù)的方形維度。
  • 每個0級別陣列都被指定了相同的格式,內(nèi)部格式和類型。

最后,一個立方體貼圖紋理如果需要mip圖立方體完整性,就是在立方體完整性基礎(chǔ)上,增加一條,就是六個紋理圖像中的每一個都被認(rèn)為是擁有獨立的完整性的。

  • 完整性對紋理應(yīng)用的影響

在頂點和碎片著色器中執(zhí)行的紋理查詢表受到被采樣的紋理的完整性的影響,在2.10.5和3.8.2中有描述。

  • 完整性對紋理圖像規(guī)范的影響

如果完整的圖像序列和要求的可被支持的圖像陣列是一致的,實現(xiàn)可以允許創(chuàng)建詳細(xì)等級為1或者比1大的紋理圖像陣列。

Mip圖的產(chǎn)生

Mip圖可以通過函數(shù)產(chǎn)生:

void GenerateMipmap(enum target);

target是目標(biāo)靶,必須是TEXTURE_2D或者TEXTURE_CUBE_MAP。

GenerateMipmap從等級為0的圖像陣列中導(dǎo)出了mip圖陣列的完整集合(定義在3.7.10節(jié))。1到q的陣列等級被導(dǎo)出的圖像陣列代替,不用考慮他們的之前的內(nèi)容。通過這種計算,0級數(shù)組陣列保持不變。

導(dǎo)出的mip圖數(shù)組陣列的內(nèi)部格式都和他們的0級數(shù)組陣列相同,導(dǎo)出的數(shù)組的維數(shù)遵循3.7.10節(jié)中描述的要求。

導(dǎo)出的mip圖數(shù)組的內(nèi)容是通過對0級陣列的重復(fù)的過濾的簡化計算出來的。不需要特殊的過濾算法,一個空的濾波算法被推薦為默認(rèn)濾波。

對于立方體貼圖,如果target的紋理不是完整的立方體,會產(chǎn)生INVALID_OPERATION錯誤。

如果0等級陣列的寬或者高不是2或者2的冪,會產(chǎn)生INVALID_OPERATION的錯誤。

如果0級陣列按照壓縮的內(nèi)部格式存儲,會產(chǎn)生INVALID_OPERATION錯誤。

3.7.12 紋理狀態(tài)

紋理必須的狀態(tài)分為兩種策略。首先,有mipmap數(shù)組的七個集合(一個是二維的目標(biāo)靶,六個是立方體貼圖的紋理目標(biāo)靶)以及他們的數(shù)目。每個圖像都和他們相關(guān)聯(lián),一個寬,一個高,一個描述圖像內(nèi)部格式的整數(shù),六個整數(shù)值描述圖像的紅,綠,藍(lán),透明度,亮度,強度通道的分辨率,每個通道的類型用一個整數(shù)描述,圖像是否被壓縮用一個布爾值描述,壓縮圖形的大小用一個整數(shù)描述。每個處室的紋理數(shù)組是空的(寬高為0)。然后,有兩組紋理屬性;每組屬性由被選擇的最小化和最大化濾鏡,以及對s和t的包裹模式組成。在初始狀態(tài)中,TEXTURE_MIN_FILTER的值是NEAREST_MIPMAP_LINEAR,TEXTURE_MAG_FILTER的值是LINEAR。s和t的包裹模式都被設(shè)置為REPEAT。

3.7.13 紋理對象

除了默認(rèn)的TEXTURE_2DTEXTURE_CUBE_MAP,命名為二維或者立體貼圖的紋理對象都可以被創(chuàng)建和操作。紋理對象的命名空間是無符號整數(shù),GL保留了0。

一個紋理對象通過給TEXTURE_2D或者TEXTURE_CUBE_MAP綁定一個沒有使用過的名字就可以創(chuàng)建了。綁定是通過下面函數(shù)起作用的:

void BindTexture(enum target, uint texture);

target要設(shè)置想要的紋理目標(biāo)靶,texutre要設(shè)置沒有使用過的名字。得到的紋理對象是一個新的狀態(tài)向量,在3.7.12節(jié)中列出來所有構(gòu)成的狀態(tài)的值,并設(shè)置了同樣的初始值。如果新的紋理對象綁定了TEXTURE_2D,TEXTURE_CUBEMAP*,新的紋理對象就會保留一個二維的或者立方體的紋理,直到被刪為止。

BindTexture也可以來綁定一個已經(jīng)存在的紋理對象,無論是TEXTURE_2D還是TEXTURE_CUBE_MAP都可以。如果試圖綁定一個和指定的target維度不同的紋理對象,將會產(chǎn)生INVALID_OPERATION錯誤。如果綁定是成功的,那么綁定的紋理對象的狀態(tài)沒有發(fā)生變化,而且之前綁定在target的紋理對象也會破裂。

當(dāng)紋理對象被綁定,對目標(biāo)靶的GL操作會對綁定的對象產(chǎn)生作用,對目標(biāo)靶查詢會使得目標(biāo)靶的綁定對象返回狀態(tài)。

在初始狀態(tài)下,TEXTURE_2D或者TEXTURE_CUBE_MAP各自有兩個二維的或者立方體貼圖紋理的狀態(tài)向量和他們相聯(lián)系。為了訪問這些初始的紋理不被丟失,他們都會被當(dāng)做是紋理對象,他們的名字都是0。初始化的二維的或者立方體貼圖紋理就這樣分別在TEXTURE_2D或者TEXTURE_CUBE_MAP上,在0綁定到相應(yīng)的目標(biāo)靶上時,操作,查詢和應(yīng)用。

紋理對象通過調(diào)用下面函數(shù)刪除:

void DeleteTexture(sizei n, uint *textures);

textures包含了n個要被刪除紋理對象的名字。在紋理對象被刪除后,是沒有內(nèi)容或者維數(shù)的,它的名字也再次變成了未被使用過的。如果一個紋理正綁定在TEXTURE_2D或者TEXTURE_CUBE_MAP被刪除,就像使用BindTexture使用相同的targettexture設(shè)置為0是一樣的。在textures中沒有使用的名稱被靜默忽略,值為0也是一樣的。

函數(shù)

void GenTextures(sizei n, uint *textures);

textures中返回了之前沒有被使用的n個紋理對象名字。這些名字會被標(biāo)記為已經(jīng)使用過的,這樣僅僅是為了函數(shù)GenTextures,但他們要求紋理狀態(tài)指示在第一次被綁定時使用,就像他們沒有用過一樣。

紋理對象的命名空間,包括初始化的紋理對象,在所有的紋理單元中共享。一個紋理對象可能同時綁定到超過一個紋理單元上。在紋理對象綁定后,在目標(biāo)靶上的對象的GL操作會影響其他的綁定著相同的紋理對象的單元。

紋理綁定受到狀態(tài)的設(shè)置ACTIVE_TEXTURE的影響。

如果紋理對象被刪除了,就好像是綁定在這個紋理對象的所有紋理單元都重新被綁定到了紋理對象0上。

最后編輯于
?著作權(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ù)。

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

  • 前言 本文主要是對OpegGL ES的api做一些資料上的搜集,給大家推薦一個中文詳解網(wǎng)站:鏈接,雖然作者還沒有寫...
    Link913閱讀 2,601評論 1 6
  • 一、紋理基礎(chǔ) 3D圖形渲染中最基本的操作就是對一個表面應(yīng)用紋理。紋理可以表現(xiàn)只從網(wǎng)格的幾何形狀無法得到的附加細(xì)節(jié)。...
    cain_huang閱讀 9,172評論 0 7
  • 本文首發(fā)于個人博客:Lam's Blog - 【OpenGL-ES】二維紋理,文章由MarkDown語法編寫,可能...
    格子林ll閱讀 3,963評論 0 9
  • 1、概述 前面幾篇文章OpenGL ES 3.0(一)綜述 、OpenGL ES 3.0(二)GLSL與著色器 討...
    高丕基閱讀 3,349評論 0 7
  • 有人問,人能不能沒有愛情? 如果魚兒可以離開水, 那我可以沒有愛情, 那一刻我已窒息。 如果飛機降落在懸崖, 那我...
    酩酊世月閱讀 424評論 6 11

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