1

I am using OpenGL version string: 4.6 (Compatibility Profile) Mesa 21.3.5. I load objects from an .obj file with matching textures, 51 textures to be exact. To be able to match various textures to various triangles and surfaces, I am adding texture coordinates along with an texture identifier in my vertex array buffer.

So now I use a stride looking like this: x y z u v r g b id which clarifies with: pos tex col id.

The problem now is that I can generate textures and bind them to corresponding texture units, but I cannot select each texture in my shader in regards to the texture unit id I get from my texture array buffer. To clarify: I generate and bind textures like so:

void loadTextures(void) {
    std::cout << "Size: " << this->materialLib.materials.size() << std::endl;
    std::cout << "Loading textures" << std::endl;
    for (long unsigned int i = 0; i < this->materialLib.materials.size(); i++) {
        Material m = this->materialLib.materials[i];
        // init
        struct TEXTURE *t = (struct TEXTURE*)malloc(sizeof(struct TEXTURE));
        t->data = NULL;
        t->path = (char*)malloc(sizeof(char) * (m.ambient_map.length() + 1)); // add one to include \0 character
        t->texture_int = 0;
        strcpy(t->path, m.ambient_map.c_str());
        
        t->data = stbi_load( t->path, &t->width, &t->height, &t->nrChannels, 0);
        textures.push_back(t);

        std::cout << '\r';
        std::cout << i << "/" << this->materialLib.materials.size();
        std::cout.flush(); // see wintermute's comment
    }
}
void applyTextures(Shader ourShader) {
    for (long unsigned int i = 0; i < textures.size(); i++) {
        struct TEXTURE *t = textures[i];
        glGenTextures( 1, &t->texture_int );
        glBindTexture( GL_TEXTURE_2D, t->texture_int );
        // set the texture wrapping parameters
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
        // set texture filtering parameters
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
        // load image, create texture and generate mipmap
        //stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.

        if (t->data) {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, t->width, t->height, 0, GL_RGB, GL_UNSIGNED_BYTE, t->data);
            glGenerateMipmap(GL_TEXTURE_2D);
        } else
            std::cout << "ERROR::LOAD::TEXTURE " << t->path << " " << i << std::endl;
    }
    return;
    /* This could be optimized by moving this to the above loop but we'll separate for simplicity for now */
    GLint gl_textures[MAX_TEXTURES];
    ourShader.use();
    for (long unsigned int i = 0; i < textures.size() && i < MAX_TEXTURES; i++) {
        gl_textures[i] = i;

        // set texture unit as a uniform for the fragment shader, could be set by ourShader.setInt()
        glUniform1i(glGetUniformLocation(ourShader.ID, "texture" + (1 + i)), i); // 'i' is our texture id, for another texture, use another id
    }
    // set texture units as a uniform for the fragment shader
    glUniform1iv(glGetUniformLocation(ourShader.ID, "textures"), MAX_TEXTURES, gl_textures);
}
void bindTextures(void) {
    for (long unsigned int i = 0; i < textures.size(); i++) {
        glActiveTexture(GL_TEXTURE0 + i);
        glBindTexture(GL_TEXTURE_2D, textures[i]->texture_int);
    }
}

This gives me varius uniforms in my fragment shader that I can select like so:

uniform sampler2D texture1;
uniform sampler2D texture2;
...
FragColor = texture(texture2, TexCoord);

I want to be able to select a texture like this:

uniform sampler2D texures;
...
FragColor = texture(textures[id], TexCoord);

What I have tried is to pass the id as the first argument to "texture()" but that gave me an error, I also tried to cast my id as a sampler2D type but that didn't work either.

How can I fix this?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Snakehater
  • 145
  • 1
  • 9
  • 5
    What texture size? If it's low, could you consider using a texture atlas? – Alexey S. Larionov Mar 28 '22 at 08:08
  • 7
    If not, use [texture arrays](https://www.khronos.org/opengl/wiki/Array_Texture) at least. They do exactly what you want – Alexey S. Larionov Mar 28 '22 at 08:12
  • @AlexeyLarionov I have thought about the texture atlas but since I want this to be dynamic, I cannot create an atlas, also, the textures are of different sizes. I will try with the texture arrays, thank you! – Snakehater Mar 28 '22 at 08:30
  • 2
    there is also bindless texturing in OpenGL/GLSL which does exactly that however never used it ... – Spektre Mar 28 '22 at 11:16

0 Answers0