C++ 如何向openGL程序添加多个纹理?

C++ 如何向openGL程序添加多个纹理?,c++,opengl,glsl,shader,C++,Opengl,Glsl,Shader,我正在编写一个openGL程序,在环境中绘制了多个模型,但我不知道如何对每个模型应用不同的纹理,所以现在它们都具有相同的纹理。我读到我需要在程序中添加多个纹理单元或使用纹理图集。纹理图集似乎更复杂,所以我尝试添加纹理单元 我认为这个过程的工作方式是: 使用glGenTextures生成两个纹理单元 使用glBindTexture和glTexImage2D将第一个图像的数据绑定到第一个纹理单元 对第二个图像执行相同的操作 从这里,我想我可以告诉openGL我想使用glActiveTexture使用

我正在编写一个openGL程序,在环境中绘制了多个模型,但我不知道如何对每个模型应用不同的纹理,所以现在它们都具有相同的纹理。我读到我需要在程序中添加多个纹理单元或使用纹理图集。纹理图集似乎更复杂,所以我尝试添加纹理单元

我认为这个过程的工作方式是:

  • 使用glGenTextures生成两个纹理单元
  • 使用glBindTexture和glTexImage2D将第一个图像的数据绑定到第一个纹理单元
  • 对第二个图像执行相同的操作
  • 从这里,我想我可以告诉openGL我想使用glActiveTexture使用哪个纹理单元。这似乎只适用于一种纹理(即跳过步骤3),但在使用两种或更多纹理时失败

    我肯定我遗漏了什么,有人能给我指出正确的方向吗

    //Generate textures
    int texturec=2;
    int w[texturec],h[texturec];
    unsigned char *data[texturec];
    data[0]=getImage(&w[0],&h[0],"resources/a.png");
    data[1]=getImage(&w[1],&h[1],"resources/b.png");
    
    //Apply textures
    GLuint textures[texturec];
    glGenTextures(texturec, textures);
    
    //Bind a.png to the first texture unit
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[0], h[0], 0, GL_RGB, GL_UNSIGNED_BYTE, data[0]);
    
    //Bind b.png to the second texture unit
    glBindTexture(GL_TEXTURE_2D, textures[1]);
    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[1], h[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data[1]);
    
    glActiveTexture(GL_TEXTURE0);
    
    //Not super clear on what this does, but it needs to be here.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
    以下是我的着色器:

    片段:

    #version 330 core
    
    in vec2 UV;
    out vec3 color;
    
    uniform sampler2D textureSampler;
    
    void main(){
        color=texture(textureSampler,UV).rgb;
    }
    
    顶点:

    #version 330 core
    
    layout(location=0) in vec3 vertexPos;
    layout(location=1) in vec2 vertexUV;
    
    out vec2 UV;
    
    uniform mat4 MVP;
    
    void main(){
        gl_Position=MVP*vec4(vertexPos,1);
        UV=vertexUV;
    }
    
    编辑:

    以下是我应用Rabid76建议后的新代码:

    //Generate textures
    int texturec=2;
    int w[texturec],h[texturec];
    unsigned char *data[texturec];
    data[0]=getImage(&w[0],&h[0],"resources/a.png");
    data[1]=getImage(&w[1],&h[1],"resources/b.png");
    
    //Apply textures
    GLuint textures[texturec];
    glGenTextures(texturec, textures);
    
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[0], h[0], 0, GL_RGB, GL_UNSIGNED_BYTE, data[0]);
    
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textures[1]);
    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[1], h[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data[1]);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
    //Shaders
    programID=loadShaders("shaders/vertex.shader","shaders/fragment.shader");
    glUseProgram(programID);
    
    //Use texture unit 1
    glActiveTexture(GL_TEXTURE1);
    GLint texLoc=glGetUniformLocation(programID, "textureSampler");
    glUniform1i(texLoc, 1);
    
  • 使用
    glGenTextures
    生成两个纹理单元
  • 否。
    glGenTextures
    不生成纹理单元

    保留可用于纹理对象的名称值

    将命名纹理绑定到纹理目标。调用此函数时,纹理对象将绑定到当前纹理单元。
    当前纹理单位可以通过以下方式设置:

    e、 g

    GLuint纹理[texturec];
    glGenTextures(texturec,textures);
    玻璃纹理(GL_纹理0);
    glBindTexture(GL_TEXTURE_2D,纹理[0]);
    // [...]
    玻璃结构(GL_纹理1);
    glBindTexture(GL_纹理_2D,纹理[1]);
    // [...]
    
    纹理对象名称值和纹理单位完全不同。
    纹理单元是纹理对象和着色器程序之间的绑定点。
    一方面,纹理对象必须绑定到纹理单元,另一方面,纹理单元必须设置为纹理采样器。因此,纹理单元是两者之间的“链接”

    自GLSL版本4.2以来,可以通过着色器中的。对应于纹理单元。e、 g.
    binding=1
    表示纹理单元1:

    layout(binding=1)统一采样器2D纹理采样器;
    
    或者,纹理单位索引可以通过
    glUniform1i
    分配给纹理采样器:

    GLint texLoc=glGetUniformLocation(programID,“textureSampler”); glUniform1i(texLoc,1);
    如果着色器程序使用1个纹理采样器,则

    统一采样器2D纹理采样器;
    
    然后,在绘制调用之前绑定适当的纹理对象就足够了:

    glActiveTexture(GL_TEXTURE0);//这是默认值
    glBindTexture(GL_TEXTURE_2D,纹理[0]);
    
    但是,如果着色器程序使用(同一目标的)多个纹理采样器,则不同的纹理对象必须绑定到不同的纹理单元:

    e、 g

    布局(绑定=3)均匀采样2D纹理采样1;
    布局(绑定=4)均匀取样器2D纹理取样器2;
    
    glActiveTexture(GL_TEXTURE3);
    glBindTexture(GL_TEXTURE_2D,纹理[0]);
    玻璃纹理(GL_纹理4);
    glBindTexture(GL_纹理_2D,纹理[1]);
    
    分别

    布局(位置=7)均匀取样器2D纹理取样器1;
    布局(位置=8)均匀取样器2D纹理取样器2;
    
    glActiveTexture(GL_TEXTURE3);
    glBindTexture(GL_TEXTURE_2D,纹理[0]);
    玻璃纹理(GL_纹理4);
    glBindTexture(GL_纹理_2D,纹理[1]);
    glUseProgram(programmaid);
    
    glUniform1i(7,3);//location=7因为OP没有在他们提供的代码中显示它,所以可能值得扩展最后一句来显示调用
    glUniform()
    来设置碎片着色器使用的纹理单位。我已经尽了最大努力根据您的答案更改代码。我已将更改后的代码粘贴到原始问题的末尾。这些更改允许我使用纹理单元1,但我无法切换回纹理单元0。如果我将第二个参数改为GLIMULL 1i到0,所有的纹理都默认为Black。@山姆,如问题的中间部分所提到的,在绘制调用之前绑定适当的纹理就足够了。由于着色器程序中一次只使用一个纹理,因此使用纹理单元0就足够了。这意味着您不需要任何
    glActiveTexture
    ,而是在
    glDraw…
    @sam之前使用
    glBindTexture
    ,在任何情况下
    glActiveTexture
    仅在
    glBindTexture
    之前有用。活动纹理单元的任何其他更改都不会达到您期望的效果-不管是什么。@sam在您的程序中是否还有其他调用
    glBindTexture
    ?必须先安装程序(
    glUseProgram(programID)
    ),然后才能设置制服(
    glUniform1i(texLoc,1)
    glTexParameteri
    不会更改某些神奇的全局参数。它设置当前绑定纹理对象的参数。必须为每个对象调用它。