紋理單元的理解c++
Shader中要用到紋理:數組
uniform sampler2D texture1;spa
Main讀取圖片數據,建立了紋理:code
unsigned int texture1;orm
怎麼把c++里加載的紋理傳給shader程序裏呢?對象
這就要用到紋理單元。blog
glBindTexture(GL_TEXTURE_2D, texture1);
這條代碼將紋理texture1傳遞給了正在使用的着色器程序裏的uniform sampler2D texture1圖片
中間隱含過程是,opengl有許多默認的紋理單元(GL_TEXTURE0,GL_TEXTURE1,GL_TEXTURE2~GL_TEXTUREn),ip
其中,默認激活的是紋理單元0——GL_TEXTURE0,上面的代碼就把紋理傳遞給了這個默認激活的紋理單元0;it
另外一方面,在shader裏聲明的採樣器——unigorm sampler,他會從一個特定的紋理單元裏取得紋理數據,而這個特定的紋理單元是GL_TEXTURE0~n中的哪個呢?
答案是,在shader裏聲明的每個採樣器,其默認對應的紋理單元是GL_TEXTURE0;
因此,使用上面的一行代碼,其中的過程是這樣的:
一、沒有選擇激活紋理單元,因此使用默認的紋理單元0
二、把紋理texture1傳遞給了紋理單元0
三、沒有設置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); }
回頭看以前的步驟,只要完成原先省略作的事就行了
一、綁定紋理時,先選擇激活相應的紋理單元
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
二、設置shader裏聲明的採樣器所對應的紋理單元
glUniform1i(glGetUniformLocation(myShader.ID, "texture1"), 0); myShader.setInt("texture2", 1); // 或者使用着色器類設置
兩中方法,都是先找到shader中的採樣器」texture1」/」texture2」的地址,而後設置其對應的紋理單元,0是指GL_TEXTURE0,1對應GL_TEXTURE1,二、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 = 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);