紋理的基礎知識

紋理是一種資料儲存形式,不僅可以方便地訪問特定的資料條目,還可以將多個條目混合(插入)在一起。

在 OpenGL 中,紋理可以用於很多事情,但最常見的是它將影象對映到多邊形(例如三角形)。為了將紋理對映到三角形(或另一個多邊形),我們必須告訴每個頂點它對應的紋理部分。我們將紋理座標分配給多邊形的每個頂點,然後在該多邊形中的所有片段之間進行插值。紋理座標在 x 和 y 軸上的範圍通常為 0 到 1,如下圖所示:

StackOverflow 文件

此三角形的紋理座標如下所示:

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_SGL_TEXTURE_WRAP_TGL_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_BORDERGL_CLAMP_TO_EDGE 相同,但在夾緊的情況下,取出的紋理元素資料被 GL_TEXTURE_BORDER_COLOR 指定的顏色替換。

  • GL_REPEAT 導致紋理座標的整數部分被忽略。紋理是平鋪的

StackOverflow 文件

  • GL_MIRRORED_REPEAT:如果紋理座標的整數部分是偶數,則忽略它。相反,如果紋理座標的整數部分是奇數,則紋理座標設定為 1 - frac(s)fract(s) 是紋理座標的小數部分。這會導致紋理每隔一次映象一次。

StackOverflow 文件

  • GL_MIRROR_CLAMP_TO_EDGE 使紋理座標重複為 GL_MIRRORED_REPEAT,對於紋理的一次重複,此時要被鉗位的座標如 GL_CLAMP_TO_EDGE

注意 GL_TEXTURE_WRAP_SGL_TEXTURE_WRAP_TGL_TEXTURE_WRAP_R 的預設值是 GL_REPEAT

應用紋理

最後要做的是在繪製呼叫之前繫結紋理:

glBindTexture(GL_TEXTURE_2D, texture);