紋理單元的理解
Shader中要用到紋理:
uniform sampler2D texture1;
Main讀取圖片資料,創建了紋理:
unsigned int texture1;
怎么把c++里加載的紋理傳給shader程式里呢?
這就要用到紋理單元,
glBindTexture(GL_TEXTURE_2D, texture1);
這條代碼將紋理texture1傳遞給了正在使用的著色器程式里的uniform sampler2D texture1
中間隱含程序是,opengl有許多默認的紋理單元(GL_TEXTURE0,GL_TEXTURE1,GL_TEXTURE2~GL_TEXTUREn),
其中,默認激活的是紋理單元0——GL_TEXTURE0,上面的代碼就把紋理傳遞給了這個默認激活的紋理單元0;
另一方面,在shader里宣告的采樣器——unigorm sampler,他會從一個特定的紋理單元里取得紋理資料,而這個特定的紋理單元是GL_TEXTURE0~n中的哪一個呢?
答案是,在shader里宣告的每一個采樣器,其默認對應的紋理單元是GL_TEXTURE0;
所以,使用上面的一行代碼,其中的程序是這樣的:
1、沒有選擇激活紋理單元,所以使用默認的紋理單元0
2、把紋理texture1傳遞給了紋理單元0
3、沒有設定shader里的采樣器對應的紋理單元,所以采樣器從默認的紋理單元0讀取資料
這樣會使shader里所有的采樣器(如果宣告多個的話)都從紋理單元0中獲取紋理資料,很明顯這樣就會使宣告的采樣器都一樣了,
但是我們宣告多個采樣器明顯是想在一個著色器里使用多個不同的紋理,那么該怎么做?
著色器里有多個采樣器,像是這樣:
#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.5); //FragColor=texture(texture1,TexCoord); }
回頭看之前的步驟,只要完成原先省略做的事就好了

1、系結紋理時,先選擇激活相應的紋理單元
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
2、設定shader里宣告的采樣器所對應的紋理單元
glUniform1i(glGetUniformLocation(myShader.ID, "texture1"), 0); myShader.setInt("texture2", 1); // 或者使用著色器類設定
兩中方法,都是先找到shader中的采樣器”texture1”/”texture2”的地址,然后設定其對應的紋理單元,0是指GL_TEXTURE0,1對應GL_TEXTURE1,2、3以此類推,
Texture類
模仿Shader類寫了自己的Texture類(重復操作實在太多了
class lxlTexture { public: unsigned int Id; lxlTexture(){} lxlTexture(const GLchar* texPath,GLint format) { glGenTextures(1, &Id); glBindTexture(GL_TEXTURE_2D, Id); // 為當前系結的紋理物件設定環繞、過濾方式 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); //讀取圖片檔案 int width, height, nrChannels;//顏色通道個數 stbi_set_flip_vertically_on_load(false); unsigned char* data = https://www.cnblogs.com/lxliiin/p/stbi_load(texPath, &width, &height, &nrChannels, 0); //匯入讀取的圖片檔案資料,處理生成紋理 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); ////-解釋- //上面把紋理系結到了GL_TEXTURE_2D,現在這個引數選擇了GL_TEXTURE_2D為目標,處理系結在上面的紋理 //引數為紋理指定多級漸遠紋理的級別,如果你希望單獨手動設定每個多級漸遠紋理的級別的話,這里我們填0,也就是基本級別, //第三個引數告訴OpenGL我們希望把紋理儲存為何種格式,我們的影像只有RGB值,因此我們也把紋理儲存為RGB值, //第四個和第五個引數設定最終的紋理的寬度和高度,我們之前加載影像的時候儲存了它們,所以我們使用對應的變數, //下個引數應該總是被設為0(歷史遺留的問題), //第七第八個引數定義了源圖的格式和資料型別,我們使用RGB值加載這個影像,并把它們儲存為char(byte)陣列 //最后一個引數是真正的影像資料, //自動生成多級紋理 glGenerateMipmap(GL_TEXTURE_2D); //釋放 stbi_image_free(data); std::cout << Id << std::endl; } void bindTexture(int num) { switch (num) { case 0: glActiveTexture(GL_TEXTURE0); break; case 1: glActiveTexture(GL_TEXTURE1); break; case 2: glActiveTexture(GL_TEXTURE2); break; case 3: glActiveTexture(GL_TEXTURE3); break; case 4: glActiveTexture(GL_TEXTURE4); break; case 5: glActiveTexture(GL_TEXTURE5); break; case 6: glActiveTexture(GL_TEXTURE6); break; case 7: glActiveTexture(GL_TEXTURE7); break; default: std::cout << "紋理系結支持0~7"<<std::endl; } glBindTexture(GL_TEXTURE_2D, Id); } void SetWrap(GLint pname) { if (pname == GL_REPEAT || pname == GL_MIRRORED_REPEAT || pname == GL_CLAMP_TO_EDGE || pname==GL_CLAMP_TO_BORDER) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, pname); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, pname); } else { std::cout << "輸入不是設定環繞方式" << std::endl; } } void SetWrapS(GLint pname) { if (pname == GL_REPEAT || pname == GL_MIRRORED_REPEAT || pname == GL_CLAMP_TO_EDGE || pname == GL_CLAMP_TO_BORDER) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, pname); } else { std::cout << "輸入不是設定環繞方式" << std::endl; } } void SetWrapT(GLint pname) { if (pname == GL_REPEAT || pname == GL_MIRRORED_REPEAT || pname == GL_CLAMP_TO_EDGE || pname == GL_CLAMP_TO_BORDER) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, pname); } else { std::cout << "輸入不是設定環繞方式" << std::endl; } } void SetFilterMag(GLint pname) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, pname); } void SetFilterMin(GLint pname) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } };
使用
//初始化 mytexture1 = Texture("Resource/Texture/container.jpg",GL_RGB); mytexture2 = Texture("Resource/Texture/awesomeface.png",GL_RGBA); //傳遞 mytexture1.bindTexture(0); mytexture2.bindTexture(1);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/17709.html
標籤:其他
上一篇:我就那樣站著入睡
