1. 創建紋理圖像
OpenGL要求紋理的高度和寬度都必須是2的n次方大小,只有滿足這個條件,這個紋理圖片才是有效的。 一旦獲取了像素值,我們就可以將這些數據傳給OpenGL,讓OpenGL生成一個紋理貼圖:
glGenTextures(1,@Texture);
glBindTexture(GL_TEXTURE_2D,Texture);
glTexImage2D(GL_TEXTURE_2D,0,3,Bit.Width,Bit.Height,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
glGenTextures和glBindTexture函數用於創建和綁定紋理對象,glTexImage2D函數將Pixels數組中的像素值傳給當前綁定的紋理對象,於是便創建了紋理。glTexImage函數的參數分別是紋理的類型,紋理的等級,每個像素的字節數,紋理圖像的寬度和高度,邊框大小,像素數據的格式,像素值的數據類型,像素數據。
2. OpenGL中的貼圖方式
OpenGL為我們提供了三種紋理——GL_TEXTURE_1D、GL_TEXTURE_2D和GL_TEXTURE_3D。它們分別表示1維紋理、2維紋理和3維紋理。無論是哪一中紋理,使用方法都是相同的:即先創建一個紋理對象和一個存儲紋理數據的n維數組,在調用glTexImageN D函數來傳入相應的紋理數據。除此之外,我們可以一些函數來設置紋理的其他特性。
2.1 設置貼圖模式
OpenGL提供了3種不同的貼圖模式:GL_MODULATE,GL_DECAL和GL_BLEND。默認情況下,貼圖模式是GL_MODULATE,在這種模式下,OpenGL會根據當前的光照系統調整物體的色彩和明暗。第二種模式是GL_DECAL, 在這種模式下所有的光照效果都是無效的,OpenGL將僅依據紋理貼圖來繪制物體的表面。最后是GL_BLEND,這種模式允許我們使用混合紋理。在這種 模式下,我們可以把當前紋理同一個顏色混合而得到一個新的紋理。我們可以調用glTexEnvi函數來設置當前貼圖模式:
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,TextureMode);
其中TextureMode就是想要設置的紋理模式,可以為GL_MODULATE,GL_DECAL和GL_BLEND中的任何一種。
另外,對於GL_BLEND模式,我們可以調用
glTexEnvfv(GL_TEXUTRE_ENV,GL_TEXTURE_ENV_COLOR,@ColorRGBA);
其中,ColorRGBA為一個表示RGBA顏色的4維數組。
2.2 紋理濾鏡
在紋理映射的過程中,如果圖元的大小不等於紋理的大小,OpenGL便會對紋理進行縮放以適應圖元的尺寸。我們可以通過設置紋理濾鏡來決定OpenGL對某個紋理采用的放大、縮小的算法。
調用glTexParameter來設置紋理濾鏡。如:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILETER, MagFilter);//設置放大濾鏡
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, MinFilter); //設置縮小濾鏡
上述調用中,第一個參數表明是針對何種紋理進行設置,第二個參數表示要設置放大濾鏡還是縮小濾鏡。第三個參數表示使用的濾鏡。可以為下面的值之一:
表6.3-1 可使用的紋理濾鏡 | |
濾鏡 | 描述 |
GL_NEAREST | 取最鄰近像素 |
GL_LINEAR | 線性內部插值 |
GL_NEAREST_MIPMAP_NEAREST | 最近多貼圖等級的最鄰近像素 |
GL_NEAREST_MIPMAP_LINEAR | 在最近多貼圖等級的內部線性插值 |
GL_LINEAR_MIPMAP_NEAREST | 在最近多貼圖等級的外部線性插值 |
GL_LINEAR_MIPMAP_LINEAR | 在最近多貼圖等級的外部和內部線性插值 |
3 紋理映射
3.1 紋理坐標
要使用當前的紋理繪制圖元,我們必須在繪制每個頂點之前為該頂點指定紋理坐標。只需調用
glTexCoord2d(s:Double;t:Double);
函數即可。其中,s、t是對於2D紋理而言的s、t坐標。對於任何紋理,它的紋理坐標都如同圖6.4-1所示的那樣:
![[轉載]OpenGL基本概念入門鈥斺斘評硤 [轉載]OpenGL基本概念入門鈥斺斘評硤](/image/aHR0cDovL3M1LnNpbmFpbWcuY24vYm1pZGRsZS82MmRmYWY1NXg3ODJkYWNkYWNmMzQmNjkw.png)
對於任何紋理,無論紋理的真正大小如何,其頂端(左上角)的紋理坐標恆為(0,0),右下角的紋理坐標恆為(1,1)。也就是說,紋理坐標應是一個介於0到1之間的一個小數。
例如,下面的代碼將使用當前紋理繪制一個三角形:
glBindTexture(Tex);
glBegin(GL_TRIANGLES);
glTexCoord2d(0,0);
glVertex3f(-10,-10,0);
glTexCoord2d(0,1);
glVertex3f(-10,10,0);
glTexCoord2d(1,1);
glVertex3f(10,10,0);
glEnd();
3.2 紋理纏繞
前面提到,紋理坐標應位於0-1之間。那么當紋理坐標大於這個值會出現什么情況呢?
我們可以對OpenGL進行設置,以決定當紋理坐標不位於這一區間時應采取的操作。我們可以指定兩種操作:GL_CLAMP和GL_REPEAT。對於GL_CLAMP,超出紋理坐標的區域會使用紋理圖像的邊界顏色來代替,如圖6.4-2所示。
而GL_REPEAT方式則是對紋理坐標進行重置而得到重復的圖像。觀察圖6.4-3,你就能很容易地發現這一點。
可以調用glTexParameter設置纏繞方式:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,WrapMode);//在s方向上的纏繞方式
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,WrapMode);//在t方向上的纏繞方式
其中,WrapMode可取GL_CLAMP或者GL_REPEAT。
4.紋理對象
創建和使用文理對象
在OpenGL中,我們使用glGenTextures創建紋理對象:
glGenTextures(Count:Integer;TexObjs:Pointer);
其中,Count是我們要創建的紋理數目,當我們只想創建一個紋理時,只需調用
var Texture:GLUint;
...
glGenTextures(1,@Texture);
這樣,Texture變量中就存儲了我們創建的紋理的ID號。
創建之后,我們使用glBindTexture將創建的紋理綁定到當前紋理。這樣所有的紋理函數都將針對當前紋理。
glBindTexture(Texture:GLUint);
這樣,我們就可以調用glTexParameter、glTexImage2D等函數來設置這個紋理對象了。
刪除紋理對象
在紋理資源使用完畢后(一般是程序退出或場景轉換時),一定要刪除紋理對象,釋放資源。
調用
glDeleteTextures(Count:Integer;TexObj:Pointer);
來刪除紋理對象。例如
glDeleteTextures(1,@Texture);
5. 多貼圖紋理
多貼圖紋理(Mip Mapping)為一個紋理對象生成不同尺寸的圖像。在需要時,根據繪制圖形的大小來決定采用的紋理等級或者在不同的紋理等級之間進行線性內插。使用多貼 圖紋理的好處在於消除紋理躁動。這種情況在所繪制的景物離觀察者較遠時常常發生(如圖6.6-1和6.6-2)。由於多貼圖紋理現在的渲染速度已經很快, 以至於和普通紋理沒有什么區別,我們現在一般都使用多貼圖紋理。
使用多貼圖紋理並不麻煩。首先,我們需要創建不同等級(尺寸)的紋理圖片。我們需要調用n次glTexImage2D函數,生成不同等級的紋理貼圖。例如:
glTexImage2D(GL_TEXTURE_2D,0,3,8,8,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
glTexImage2D(GL_TEXTURE_2D,1,3,4,4,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
glTexImage2D(GL_TEXTURE_2D,2,3,2,2,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
glTexImage2D(GL_TEXTURE_2D,3,3,1,1,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
這些函數調用的第二個參數表示當前紋理的等級。0級的分辨率最大。之后,每一級的分辨率是上一級分辨率的一半。這樣的函數調用應一直進行下去,直至圖像的高度和寬度都為1。
但有時候,這樣做總並不是很方便。我們可以借助一個glu函數幫我們自動生成這些多貼圖紋理。只需要把生成紋理圖像的函數調用由glTexImage2D改為gluBuild2DMipMaps即可:
gluBuild2DMipMaps(GL_TEXTURE_2D,3,Bit.Width,Bit.Height,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
此外,還必須把紋理的濾鏡改為MIP_MAP濾鏡。例如:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);