1
votes

I am trying to do a scene in OpenGL to simulate earth from space. I have two spheres right now, one for earth, and another slightly big for clouds. The earth and the cloud sphere objects have their own shader programs to keep it simple. The earth shader program takes 4 textures (day, night, specmap and normalmap) and the cloud shader program takes 2 textures (cloudmap and normalmap). I have an object class which has a render function, and in that function I use this logic:

//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);
    }
}

It starts from the 0th texture unit, and binds N number of textures to N number of texture units starting from GL_TEXTURE0. Then it binds the the samplers starting from 0 to N in the shader program. The samplers are provided by me while loading the textures:

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);
}

When I do this, all the textures in the first sphere (earth) gets loaded successfully, but in the seconds sphere I get no textures and I just get a black sphere. My query is, how should I manage multiple textures and samplers if I'm using different shader programs for each object?

1

1 Answers

2
votes

From what I see You are binding all textures as separate texture unit

  • that is wrong
  • what if you have 100 objects and each has 4 textures ...
  • I strongly doubt that you have 400 texture units at your disposal
  • Texture ID (name) is not Texture unit ...

I render space bodies like this:

  1. First pass renders the astro body geometry

    • I have specific texture units for specific tasks

      // 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
      
    • see the shader in that link (it was written for the solar system visualization too)...

    • you bind only the textures for single body before each render of it
    • (after you bind the shader)
    • do not change the texture unit meanings (how shader will know which texture is what if you do?)
  2. Second render pass adds atmospheres

    • no textures used
    • it is just single transparent quad covering whole screen
  3. here some insights to your tasks

[edit1] example of multitexturing

// 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);