開始學習OpenGL,參考的是著名的LearnOpenGL這個網站,在這裏作一些總結性的記錄,只是方便本身往後查找或者記錄本身的一些拓展思考,關於OpenGL的具體內容請移步:
https://learnopengl-cn.github.io/
或英文原版:https://learnopengl.com/c++
爲了可以把紋理映射(Map)到三角形上,咱們須要指定三角形的每一個頂點各自對應紋理的哪一個部分。這樣每一個頂點就會關聯着一個紋理座標(Texture Coordinate),用來標明該從紋理圖像的哪一個部分採樣(譯註:採集片斷顏色)。以後在圖形的其它片斷上進行片斷插值(Fragment Interpolation)。git
因此先在頂點數據中加入紋理座標並記得將其傳入頂點着色器:github
float vertices[] = { // ---- 位置 ---- ---- 顏色 ---- - 紋理座標 - 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下 -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下 -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上 };
用的stb_image.h這個頭文件:函數
//讀取圖片 int width, height, nrChannels;//圖片寬度,高度,顏色通道數量 stbi_set_flip_vertically_on_load(true);//翻轉y軸 unsigned char* data = stbi_load("wall.jpg", &width, &height, &nrChannels, 0);
相似於以前生成VAO、VBO的流程:學習
//生成紋理 unsigned int texture1; glGenTextures(1, &texture1);//第一個參數爲生成紋理的數量 glBindTexture(GL_TEXTURE_2D, texture1);//綁定紋理對象
設置紋理環繞方式和紋理過濾選項,決定了紋理座標超過1時如何採樣以及多級漸遠紋理級別之間的過濾方式,具體含義和效果見LearnOpenGL。網站
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
這裏要注意glTexImage2D的第3個和第7個參數,決定了紋理的源格式和咱們但願的處理格式,若是原圖帶有Alpha通道,這裏要改爲GL_RGBA,原文中沒有說明致使我一直加載不出帶透明通道的圖,後來看源碼才發現。code
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);//生成紋理 glGenerateMipmap(GL_TEXTURE_2D);//生成多級漸遠紋理
結束以後記得釋放圖像的內存:orm
stbi_image_free(data);//釋放圖像內存
紋理座標傳入頂點着色器後直接傳到片元着色器便可,至於紋理對象自己定義爲sampler2D類型的uniform變量,經過GLSL的texture
函數便可進行採樣。對象
#version 330 core out vec4 FragColor; in vec3 ourColor; in vec2 TexCoord; uniform sampler2D ourTexture; void main() { FragColor = texture(ourTexture, TexCoord); }
結果:blog
能夠看到上面片元着色器中定義了uniform的紋理變量,但咱們並無在程序中給這個uniform變量傳值,這是由於OpenGL中有不少紋理單元,若是隻有一個紋理對象,會默認分配至GL_TEXTURE0,sampler變量也會默認從0號單元中採樣,因此若是須要渲染更多的紋理,須要分配不一樣的紋理單元。
更改一下片元着色器,用mix
函數讓兩張圖片進行混合:
#version 330 core out vec4 FragColor; in vec3 ourColor; in vec2 TexCoord; uniform sampler2D texture1; uniform sampler2D texture2; void main() { FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.3); }
先按以前的方式讀入第二張圖(這裏讀了一張帶透明通道的圖因此記得glTexImage2D的參數改成GL_RGBA):
unsigned int texture2; glGenTextures(1, &texture2); glBindTexture(GL_TEXTURE_2D, texture2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); data = stbi_load("face.png", &width, &height, &nrChannels, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); stbi_image_free(data);
而後再渲染循環以前
給sampler指定對應的紋理單元(注意必定要先激活shader程序):
shader.use(); glUniform1i(glGetUniformLocation(shader.ID, "texture1"), 0); glUniform1i(glGetUniformLocation(shader.ID, "texture2"), 1);
而後激活對應的紋理單元並將紋理對象綁定上去:
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2);
結果:
在LearnOpenGL這一章的評論區發現有人說,當讀取的圖片寬度爲奇數時顯示不正常,而我試了一下寬度爲奇數的圖片程序直接就崩潰了,評論區也給出瞭解決方法,加入一行代碼以後就正常了:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
這行代碼的做用是設置OpenGL讀取數據的對齊方式,OpenGL默認爲4字節對齊,也就是說一行圖像數據的長度必須是4的倍數,我又嘗試了一下寬度爲偶數但不是4的倍數的圖片,果真顯示不正確:
因此上面的代碼就是設置讀取數據的方式爲1個字節對齊,這樣OpenGL會一個一個字節讀取,不會致使越界,但這樣讀取效率確定也會下降,因此最好的方法仍是提供寬度爲4的倍數的圖片。