紋理的基礎知識
紋理是一種資料儲存形式,不僅可以方便地訪問特定的資料條目,還可以將多個條目混合(插入)在一起。
在 OpenGL 中,紋理可以用於很多事情,但最常見的是它將影象對映到多邊形(例如三角形)。為了將紋理對映到三角形(或另一個多邊形),我們必須告訴每個頂點它對應的紋理部分。我們將紋理座標分配給多邊形的每個頂點,然後在該多邊形中的所有片段之間進行插值。紋理座標在 x 和 y 軸上的範圍通常為 0 到 1,如下圖所示:
此三角形的紋理座標如下所示:
GLfloat texCoords[] = {
0.0f, 0.0f, // Lower-left corner
1.0f, 0.0f, // Lower-right corner
0.5f, 1.0f // Top-center corner
};
將這些座標放入 VBO(頂點緩衝區物件)併為著色器建立新屬性。你應該已經具有頂點位置的至少一個屬性,因此為紋理座標建立另一個屬性。
生成紋理
首先要做的是生成一個紋理物件,該物件將由一個 ID 引用,該 ID 將儲存在 unsigned int 紋理中 :
GLuint texture;
glGenTextures(1, &texture);
之後必須繫結所有後續紋理命令將配置此紋理:
glBindTexture(GL_TEXTURE_2D, texture);
載入圖片
要載入影象,你可以建立自己的影象載入器,也可以使用影象載入庫,例如 c ++中的 SOIL (簡單 OpenGL 影象庫)或 java 中的 TWL PNGDecoder 。
使用 SOIL 載入影象的示例如下:
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
現在你可以將此影象指定給紋理物件:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
之後你應該取消繫結紋理物件:
glBindTexture(GL_TEXTURE_2D, 0);
包裹紋理座標的引數
如上所示,紋理的左下角有 UV(st)
座標(0,0),紋理的右上角有座標(1,1),但網格的紋理座標可以在任何範圍。要處理這個問題,必須定義紋理座標如何包裹到紋理。
對紋理卷繞引數座標可以與設定 glTextureParameter 使用 GL_TEXTURE_WRAP_S
,GL_TEXTURE_WRAP_T
和 GL_TEXTURE_WRAP_R
。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
可能的引數是:
-
GL_CLAMP_TO_EDGE
使紋理座標被限制在 [1 / 2N,1 - 1 / 2N]範圍內,其中 N 是方向上紋理的大小。 -
GL_CLAMP_TO_BORDER
與GL_CLAMP_TO_EDGE
相同,但在夾緊的情況下,取出的紋理元素資料被GL_TEXTURE_BORDER_COLOR
指定的顏色替換。 -
GL_REPEAT
導致紋理座標的整數部分被忽略。紋理是平鋪的。
GL_MIRRORED_REPEAT
:如果紋理座標的整數部分是偶數,則忽略它。相反,如果紋理座標的整數部分是奇數,則紋理座標設定為 1 -frac(s)
。fract(s)
是紋理座標的小數部分。這會導致紋理每隔一次映象一次。
GL_MIRROR_CLAMP_TO_EDGE
使紋理座標重複為GL_MIRRORED_REPEAT
,對於紋理的一次重複,此時要被鉗位的座標如GL_CLAMP_TO_EDGE
。
注意 GL_TEXTURE_WRAP_S
,GL_TEXTURE_WRAP_T
和 GL_TEXTURE_WRAP_R
的預設值是 GL_REPEAT
。
應用紋理
最後要做的是在繪製呼叫之前繫結紋理:
glBindTexture(GL_TEXTURE_2D, texture);