概述
??? OpenGL紋理是一種在三維圖形中應用紋理映射的技術。紋理是一張圖像,可以應用到三維模型的表面上,從而使得模型看起來更加真實和具有細節。通過紋理映射,可以將圖像的像素值與三維模型的頂點進行匹配,從而為模型的表面增加細節和圖案。
??? OpenGL提供了一套用于加載、創建和使用紋理的API,使得紋理映射變得簡單和高效。在OpenGL中,紋理被存儲在紋理緩沖區中,并通過紋理坐標來進行訪問。紋理坐標是一個二維向量,范圍在[0,1]之間,用于映射紋理的像素值。
??? 為了應用紋理映射,需要先加載紋理圖像并將其傳輸到OpenGL的紋理緩沖區中。然后,可以在繪制三維模型之前,將紋理坐標與模型的頂點進行匹配,并通過紋理坐標在紋理緩沖區中獲取相應的像素值。最后,將像素值應用到模型的表面上,從而實現紋理映射。
OpenGL還提供了一些紋理過濾和紋理環繞的選項,用于控制紋理在放大和縮小時的插值和邊界處理。這些選項可以改善紋理映射的質量和效果,使得紋理在不同大小和角度下都能正確顯示。
總的來說,OpenGL紋理是一種強大的技術,可以為三維模型增加細節和圖案,并提升圖形渲染的質量和真實感。通過合理的紋理映射和紋理處理,可以使得模型在視覺上更加吸引人和逼真。
示例
? ? 接下來通過一個簡單的示例來介紹如何使用紋理貼圖將一張圖片映射到一個矩形中,效果如下圖所示。
? ? 在上圖中,中間是一個矩形,在該矩形中顯示的圖片,下面分步介紹如何實現上面的效果。
1、創建紋理對象?
? ? 要使用紋理,首先要創建紋理對象,代碼如下。
mTexture = 0;glGenTextures(1, &mTexture);glBindTexture(GL_TEXTURE_2D, mTexture);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
?創建紋理過程解析如下。
1)創建紋理對象:glGenTextures用于創建紋理對象,1表示創建一個紋理對象,成功后紋理對象的句柄保存到tex中。
2)綁定紋理對象:glBindTexture用于綁定紋理對象到紋理目標GL_TEXTURE_2D,綁定后對目標的操作會影響到被綁定的紋理對象。
3)設置參數:glTexParameterf用于設置紋理參數。參數GL_TEXTURE_WRAP_S設置為GL_CLAMP_TO_EDGE表示S方向超出范圍[0.0,1.0]時使用邊界的顏色,同樣參數GL_TEXTURE_WRAP_T也設置為GL_CLAMP_TO_EDGE表示T方向超出范圍[0.0,1.0]時使用邊界的顏色。參數GL_TEXTURE_MIN_FILTER和GL_TEXTURE_MAG_FILTER都設置為GL_LINEAR表示紋理縮小和放大的過濾方式都是線性插值。
2、載入圖片數據
? ? 創建紋理對象后,接下來向該對象載入圖片數據,流程如下。
AAsset *pathAsset = AAssetManager_open(assetManager,path.c_str(), AASSET_MODE_BUFFER);unsigned char *filedata = (unsigned char *) AAsset_getBuffer(pathAsset);off_t assetLength = AAsset_getLength(pathAsset);stbi_set_flip_vertically_on_load(true);unsigned char *data = stbi_load_from_memory(filedata, assetLength,&w,&h,&n,0);if(data != nullptr){GLint format = GL_RGB;if(n == 4) format = GL_RGBA;glTexImage2D(GL_TEXTURE_2D,0, format, w,h,0,format,GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}
載入圖片數據流程解析如下
1)AAssetManager_open打開assets目錄的圖片文件
2)AAsset_getBuffer獲取圖片文件的緩沖
3)stbi_load_from_memory將圖片緩沖解嗎得到圖片數據
4)glTexImage2D向紋理對象載入圖片數據
5)glGenerateMipmap生成多級漸遠紋理
3、綁定紋理單元
? ? 紋理對象要綁定到特定的紋理單元,采樣器才能采樣,綁定方法如下
glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, mTexture);
? ? 這里把紋理對象綁定到0號紋理單元。
4、編寫著色器
? ? 紋理貼圖的著色器如下。
std::string strVs = R"(
#version 300 es
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;out vec2 vTexCoord;void main()
{gl_Position = vec4(aPos, 1.0);vTexCoord = aTexCoord;
}
)";std::string strFs = R"(
#version 300 es
precision mediump float;
out vec4 FragColor;
in vec2 vTexCoord;
uniform sampler2D sampler;
void main()
{FragColor = texture(sampler, vTexCoord);
}
)";
? ? 在頂點著色器中,有兩個頂點屬性,0號屬性aPos表示頂點位置,1號屬性aTexCoord表示紋理坐標。
? ? 在片元著色器中,vTexCoord是紋理坐標,sampler是紋理采樣器,在main方法中調用采樣函數texture對紋理進行采樣,采樣結果輸出到FragColor。
5、開始繪制
? ? 繪制紋理的流程如下所示。
mShader->setInt("sampler",0);glClear(GL_COLOR_BUFFER_BIT);glClearColor(0.5f,0.6f,0.7f,1.0f);glBindVertexArray(VAO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
繪制流程解析如下:
mShader->setInt("sampler",0); 知會著色器的采樣器到幾號紋理單元采樣,0表示0號紋理單元。
glBindVertexArray(VAO);綁定VAO,有了VAO才知道如何取得頂點數據。
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); 綁定索引數據
glDrawElements開始繪制,由于已經綁定了索引數據,所以最后的參數無須傳索引數據的首地址。
6、工程地址
? ? 本示例已經上傳到github,地址如下。
示例工程地址