多重纹理和纹理组合器
多重紋理和紋理組合器
本文主要介紹OpenGL中兩種技術的使用方法:多重紋理技術和紋理組合器技術,最終根據參考【2】中的代碼,實現了兩個簡單的演示DEMO,其中使用到了《八叉樹顏色量化、BMP、TGA文件解析》篇章中提供的圖像解析類。
下載地址:https://github.com/twinklingstar20/twinklingstar_cn_demo_multitexture_texture_combiner/
一.多重紋理技術(Multitexture)
1.1 多重紋理技術簡介
OpenGL在渲染多邊形時允許多張紋理同時被應用,這些紋理在操作管線上一個接一個的被處理。一個紋理單元(texture unit)表示單個紋理的操作,一個紋理單元處理完成后,將它的結果傳遞給下一個紋理單元,直至所有的紋理單元都被處理完。下圖顯示了片斷(fragment)經歷的四個紋理操作過程。
圖1.片斷經歷的四個紋理過程
注意:在反饋模式下,除了第一個紋理單元外多重紋理是處于未定義的狀態,即只有第一張紋理單元能用(In feedback mode, multitexturing is undefined beyond the first texture unit)。
1.2?使用多重紋理的幾個步驟
(1)?? 建立每個紋理單元的紋理狀態,包括紋理圖像數據,過濾器,環境,矩陣,紋理函數生成方式等。可用glActiveTexture()函數以改變當前的紋理狀態,然后調用glTexImage*(),glTexParameter*(),glTexEnv*(),glTexGen*(),glBindTexture()方法分配每個紋理單元的紋理信息,紋理狀態、紋理坐標和光柵化紋理坐標的查詢都應用在當前紋理單上,即glActiveTexture()指定的紋理單元。此外,可以使用glGetIntegerv(GL_MAX_TEXTURE_UNITS,…)顯示當前實現中允許的最大紋理單元數,得到的最大紋理單元數至少為2。
注意:glPushAttrib(),glPushClientAttrib(),glPopAttrib(),或者glPopClientAttrib()可以保存或者恢復所有紋理單元的紋理狀態,但是紋理矩陣堆棧除外。
(2)?? 可以用glMultiTexCoord*()函數規定每個頂點上不同紋理單元的紋理坐標。下面的代碼片段演示該函數的用法:
| 1 2 3 4 5 6 7 8 9 10 11 | glBegin(GL_TRIANGLES); glMultiTexCoord2f(GL_TEXTURE0,0.0f,0.0f); glMultiTexCoord2f(GL_TEXTURE1,1.0f,0.0f); glVertex2f(0.0f,0.0f); glMultiTexCoord2f(GL_TEXTURE0,0.5f,1.0f); glMultiTexCoord2f(GL_TEXTURE1,0.5f,0.0f); glVertex2f(50.0f,100.0f); glMultiTexCoord2f(GL_TEXTURE0,1.0f,0.0f); glMultiTexCoord2f(GL_TEXTURE1,1.0f,1.0f); glVertex2f(100.0f,0.0f); glEnd(); |
注意:如果使用glTexCoord*()相當于采用了第一個紋理單元的紋理坐標,即與glMultiTexCoord*(GL_TEXTURE0,…)等價。
(3)?? 恢復使用單個紋理。在使用多重紋理時,如果想要恢復使用單個紋理,需要禁用除紋理單位0之外的所有紋理單位。如下面的代碼片段所示:
| 1 2 3 4 5 | glActiveTexture(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE2); glDisable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); |
附加說明:
(1)由于微軟的VS平臺上,只支持OpenGL 1.1版本,所以無法使用glActiveTexture()等函數,所以需要安裝上glew庫,這個庫的安裝方法網上很容易搜索到;
(2)將多重紋理技術與組合器函數glTexEnv*()結合使用,可以產生很絢麗的效果,下面介紹紋理組器函數;
(3)multitexture-demo演示了一個多重紋理的簡單例子,使用到紋理組合器。
二.紋理組合器(Texture combiner)
2.1?紋理組合器函數簡介
OpenGL除了多重紋理外,還提供了一些靈活的紋理組合器函數,允許程序員對片斷與紋理值或者其它顏色的混合,對紋理提供了更加精細的控制。這就使得OpenGL的重心從原先的頂點處理(變換、裁剪)過渡到光柵化和片斷操作,片斷的處理能力越來越強。紋理組合器函數glTexEnv*()的參數比較多,下面會逐步進行介紹。
2.2 glTexEnv*()函數介紹
void glTexEnv{if}(GLenum target,GLenum pname,TYPE param);
void glTexEnv{if}v(GLenum target,GLenum pname,TYPE* param);
target規定紋理環境(texture environment),必需是GL_TEXTURE_ENV,GL_TEXTURE_FILTER_CONTROL,GL_POINT_SPRITE中的任意一個值。對target和pname對應參數進行總結,如表1所示;對pname和param對應參數進行總結,如表2所示。
表1. 參數target和參數pname的對應取值
表2. 參數pname和參數param的對應取值
2.2.1 target的值是GL_TEXTURE_FILTER_CONTROL
如果target是GL_TEXTURE_FILTER_CONTROL時,pname必須是GL_TEXTURE_LOD_BIAS,則param規定了紋理細節層的偏移量,它的用途可以參見文章《基本的二維紋理對象的使用方法介紹》中3.1小節的介紹。
2.2.2 target的值是GL_POINT_SPRITE
如果target是GL_POINT_SPRITE?時,pname必須是GL_COORD_REPLACE,boolean值用于規定是否開啟點精靈紋理坐標替換(point sprite texture coordinate replacement)。
2.2.3 target的值是GL_TEXTURE_ENV
如果target是GL_TEXTURE_ENV,pname必須是(1)GL_TEXTURE_ENV_MODE, ?GL_TEXTURE_ENV_COLOR,(3)GL_COMBINE_RGB,GL_COMBINE_ALPHA,(4)GL_RGB_SCALE,(5)GL_ALPHA_SCALE,(6)GL_SRC0_RGB, GL_SRC1_RGB,(7)GL_SRC2_RGB,(8)GL_SRC0_ALPHA,(9)GL_SRC1_ALPHA,(10)GL_SRC2_ALPHA。
在不同的紋理存儲格式下,用于紋理計算的R、G、B、A4個顏色分量的取值。
表3.進行組合操作的源紋理(不同的內部存儲格式下)的Cs、As值
C代表一個三元的顏色值(RGB),A是相關的alpha值,從紋理圖像中提取的RGBA的值都在范圍[0,1]內,下標是p的代表由上一個階段計算得到的紋理顏色(處理階段為0的紋理顏色就是起始的原片斷顏色),下標是s的代表原紋理顏色(Texture Source Color),下標是c的代表紋理環境的顏色(Texture Environment Color),下標是v的代表通過紋理函數計算后得到的紋理顏色。
表4. 當pname是GL_TEXTURE_ENV_MODE時,幾種紋理處理函數的計算公式
如果pname是GL_TEXTURE_ENV_MODE,params是GL_COMBINE,則紋理函數的計算依賴GL_COMBINE_RGB和GL_COMBINE_ALPHA。
接下來描述的是由GL_SRC0_RGB、GL_SRC1_RGB、GL_SRC2_RGB、GL_SRC0_ALPHA、GL_SRC1_ALPHA、GL_SRC2_ALPHA規定的源紋理,通過組合,生成最后的紋理顏色的方法,在下面的表中GL_SRC0_c表示Arg0,GL_SRC1_c表示Arg1,GL_SRC2_c表示Arg2。
當pname是GL_COMBINE_RGB時,param可以接受的幾個參數是GL_REPLACE、GL_MODULATE、GL_ADD、GL_ADD_SIGNED、GL_INTERPOLATE、GL_SUBTRACT、GL_DOT3_RGB、GL_DOT3_RGBA。
表5. 規定幾種源紋理,通過對這幾種紋理的RGB顏色計算,得到最終的紋理顏色
??? 類似的,當pname是GL_COMBINE_ALPHA時,param可以接受的幾個參數是GL_REPLACE、GL_MODULATE、GL_ADD、GL_ADD_SIGNED、GL_INTERPOLATE、GL_SUBTRACT。
表6.規定幾種源紋理,通過對這幾種紋理的alpha顏色計算,得到最終的紋理顏色
下面的表格中Cs表示當前綁定的紋理采樣的顏色,Cc表示環境紋理顏色常量(Constant Texture-Environment Color),Cf表示傳入片斷的主顏色,Cp表示以前的紋理階段計算出的顏色(如果當前正處理的紋理階段是0,則它的值為Cf),類似的,As,Ac,Af,Ap表示對應紋理的alpha值。下表是基于源紋理的RGB值和操作,計算得到的Arg0,Arg1,Arg2。
表7. 基于源紋理的RGB值和操作,計算得到的Arg0,Arg1,Arg2?
??? 類似的,下表是基于源紋理的Alpha值和操作,計算得到的Arg0,Arg1,Arg2。
表8. 基于源紋理的Alpha值和操作,計算得到的Arg0,Arg1,Arg2
2.3 glTexEnv*()函數使用例子
選擇激活紋理組合方法:
| 1 | glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE); |
選擇紋理組合的運算法則:
| 1 | glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_SUBTRACT); |
設置紋理組合函數中紋理的來源:
| 1 2 | glTexEnvf(GL_TEXTURE_ENV,GL_SRC0_RGB,GL_TEXTURE); glTexEnvf(GL_TEXTURE_ENV,GL_SRC1_RGB,GL_PREVIOUS); |
設置如何使用紋理組合函數中紋理的來源來計算Arg0和Arg1,如表7所示:
| 1 2 | glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR); glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR); |
實現了multitexture-combine-demo這個demo,用組合器生成多重紋理的代碼片段如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | void initTexture() { ????unsigned int textureId[2]; ????//創建2個紋理 ????//生成一個2*2,顏色為(0,0,255)的紋理圖片 ????textureId[0] = genTexture(0,0,255); ????//讀取一個BMP圖片,生成紋理 ????textureId[1] = genTextureFile("text.bmp"); ????//激活第1個紋理 ????glActiveTexture(GL_TEXTURE0); ????glEnable(GL_TEXTURE_2D); ????glBindTexture(GL_TEXTURE_2D,textureId[0]); ????//用紋理textureId[0]替換環境紋理 ????glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); ????glActiveTexture(GL_TEXTURE1); ????glEnable(GL_TEXTURE_2D); ????glBindTexture(GL_TEXTURE_2D,textureId[1]); ????//設置組合器,運算法則是“減法”, ????//textureId[1]是紋理GL_SRC0_RGB,前一個階段計算的紋理是GL_SRC1_RGB, ????//根據運算法則GL_SRC0_RGB-GL_SRC1_RGB,字體中間是白色的(255,255,255),減去(0,0,255),會顯示出黃色; ????//字體周圍是黑色的,減去(0,0,255)還是黑色的。 ????glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE); ????glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_SUBTRACT); ????glTexEnvf(GL_TEXTURE_ENV,GL_SRC0_RGB,GL_TEXTURE); ????glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR); ????glTexEnvf(GL_TEXTURE_ENV,GL_SRC1_RGB,GL_PREVIOUS); ????glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR); } void drawScene() { ????glBegin(GL_QUADS); ????????//分別指定三個紋理的紋理坐標 ????????glMultiTexCoord2f(GL_TEXTURE0,0.0f, 0.0f);glMultiTexCoord2f(GL_TEXTURE1,0.0f, 0.0f); ????????glVertex3f(-1.0f, -1.0f,? 1.0f); ????????glMultiTexCoord2f(GL_TEXTURE0,1.0f, 0.0f);glMultiTexCoord2f(GL_TEXTURE1,1.0f, 0.0f); ????????glVertex3f( 1.0f, -1.0f,? 1.0f); ????????glMultiTexCoord2f(GL_TEXTURE0,1.0f, 1.0f);glMultiTexCoord2f(GL_TEXTURE1,1.0f, 1.0f); ????????glVertex3f( 1.0f,? 1.0f,? 1.0f); ????????glMultiTexCoord2f(GL_TEXTURE0,0.0f, 1.0f);glMultiTexCoord2f(GL_TEXTURE1,0.0f, 1.0f); ????????glVertex3f(-1.0f,? 1.0f,? 1.0f); ????glEnd(); } |
該DEMO的組合效果如下圖所示:
圖2. 通過設置組合器,得到最終的結果
??? 至此,演示了組合器的基本用法,可以通過概念組合器不同的參數,得到不同的結果。
總結
以上是生活随笔為你收集整理的多重纹理和纹理组合器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 给IT新人的15个建议:程序员的辛酸反省
- 下一篇: LevelDB简述