具有多个着色器程序的OpenGL多重纹理

时间:2015-08-09 04:00:39

标签: c++ opengl opengl-es glsl shader

我正在尝试在OpenGL中创建一个场景来模拟太空中的地球。我现在有两个球体,一个用于地球,另一个用于云层。地球和云球体对象有自己的着色器程序,以保持简单。地球着色器程序采用4种纹理(白天,夜晚,specmap和法线贴图),云着色器程序采用2种纹理(cloudmap和normalmap)。我有一个具有渲染功能的对象类,在该函数中我使用这个逻辑:

//bind the current object's texture
for (GLuint i = 0; i < texIDs.size(); i++){
    glActiveTexture(GL_TEXTURE0 + i);
    if (cubemap)
        glBindTexture(GL_TEXTURE_CUBE_MAP, texIDs[i]);
    else
        glBindTexture(GL_TEXTURE_2D, texIDs[i]);
}
    if (samplers.size()){
    for (GLuint i = 0; i < samplers.size(); i++){
        glUniform1i(glGetUniformLocation(program, samplers[i]), i);
    }
}

它从第0个纹理单元开始,并将N个纹理绑定到从GL_TEXTURE0开始的N个纹理单元。然后它在着色器程序中将采样器从0开始绑定到N.加载纹理时,我提供了采样器:

void Object::loadTexture(const char* filename, const GLchar* sampler){
    int texID;
    texID = SOIL_load_OGL_texture(filename, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS);
    if(texID == 0){
        cerr << "SOIL error: " << SOIL_last_result();
    }
    cout << filename << " Tex ID: " << texID << endl;
    texIDs.push_back(texID);
    samplers.push_back(sampler);
    //glBindTexture(GL_TEXTURE_2D, texID);
}

当我这样做时,第一个球体(地球)中的所有纹理都成功加载,但是在秒球体中我没有纹理,我得到一个黑色球体。我的问题是,如果我为每个对象使用不同的着色器程序,我该如何管理多个纹理和采样器呢?

1 个答案:

答案 0 :(得分:2)

从我看到你将所有纹理绑定为单独的纹理单元

  • 这是错误的
  • 如果你有100个物体,每个物体有4个纹理......
  • 我强烈怀疑你有400个纹理单位
  • 纹理ID(名称)不是纹理单元...

我像这样渲染太空物体:

  1. First pass renders the astro body geometry

    • 我有特定任务的特定纹理单元

      // texture units:            
      // 0 - texture0 map 2D rgba (surface)
      // 1 - texture1 map 2D rgba (clouds blend)
      // 2 - normal map 2D xyz (normal/bump mapping)
      // 3 - specular map 2D i (reflection shininess)
      // 4 - light map 2D rgb rgb (night lights)
      // 5 - enviroment/skybox cube map 3D rgb
      
    • 查看该链接中的着色器(它也是为太阳系可视化而编写的)...

    • 在每次渲染之前,只绑定单个纹理的纹理
    • (绑定着色器后)
    • 不要改变纹理单位的含义(如果你这样做,着色器将如何知道哪种纹理?)
  2. Second render pass adds atmospheres

    • 没有使用纹理
    • 它只是单个透明四边形覆盖整个屏幕
  3. here some insights to your tasks

  4. [edit1]多纹理的例子

    // init shader once per render all geometries
    GLint prog_id;      // shader program ID;
    GLint txrskybox;    // global skybox environment cube map
    GLint id;
    glUseProgram(prog_id);
    id=glGetUniformLocation(prog_id,"txr_texture0"); glUniform1i(id,0); //uniform sampler2D   txr_texture0;
    id=glGetUniformLocation(prog_id,"txr_texture1"); glUniform1i(id,1); //uniform sampler2D   txr_texture1;
    id=glGetUniformLocation(prog_id,"txr_normal");   glUniform1i(id,2); //uniform sampler2D   txr_normal;
    id=glGetUniformLocation(prog_id,"txr_specular"); glUniform1i(id,3); //uniform sampler2D   txr_specular;
    id=glGetUniformLocation(prog_id,"txr_light");    glUniform1i(id,4); //uniform sampler2D   txr_light;
    id=glGetUniformLocation(prog_id,"txr_skybox");   glUniform1i(id,5); //uniform samplerCube txr_skybox;
    
    // add here all uniforms you need ...
    glActiveTexture(GL_TEXTURE0+5); glEnable(GL_TEXTURE_CUBE_MAP); glBindTexture(GL_TEXTURE_CUBE_MAP,txrskybox);
    
    for (i=0;i<all_objects;i++)
        {
        // add here all uniforms you need ...
    
        // pass textures once per any object render
        // obj::(GLint) txr0,txr1,txrnor,txrspec,txrlight; // object local textures
        glActiveTexture(GL_TEXTURE0+0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txr0);
        glActiveTexture(GL_TEXTURE0+1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txr1);
        glActiveTexture(GL_TEXTURE0+2); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txrnor);
        glActiveTexture(GL_TEXTURE0+3); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txrspec);
        glActiveTexture(GL_TEXTURE0+4); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txrlight);
        // here render the geometry of obj[i]
        }
    
    // unbind textures and shaders
    glActiveTexture(GL_TEXTURE0+5); glBindTexture(GL_TEXTURE_CUBE_MAP,0); glDisable(GL_TEXTURE_CUBE_MAP);
    glActiveTexture(GL_TEXTURE0+4); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0+3); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0+2); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0+1); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0+0); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D); // unit0 at last so it stays active ...
    glUseProgram(0);