Texture Units are not bound to texture object

I have been trying to bind multiple textures each to their own texture units. However, my code won’t work, it only shows one texture or the other. I have even tried copying code from the internet that is known to work (w/ multiple texture units and samplers) yet when I compile it and run it, it only shows one of the two textures. I have tried running my code on different graphics cards (AMD integrated to NVidia dedicated) and it still only shows one texture unit. I have tried debugging with RenderDoc and it doesn’t seem to detect any of my textures. I have read other posts on the Khronos forums and none have solved my issue. In particular, my issue seems to be from the following lines of code:

> unsigned char * data_ptr = stbi_load("res/textures/cat.png", &width, &height, &num_of_components, STBI_rgb_alpha);
> 
>     if (data_ptr == nullptr)
>     {
>         LogMSG(stbi_failure_reason());
>         LogERR(std::string("Could not load image file, \"") + "res/textures/cat.png" + "\", for texture!");
>     }
> 
>     int width2, height2, num_of_components2;
> 
>     unsigned char* data_ptr2 = stbi_load("res/textures/ironman.png", &width2, &height2, &num_of_components2, STBI_rgb_alpha);
> 
>     if (data_ptr2 == nullptr)
>     {
>         LogMSG(stbi_failure_reason());
>         LogERR(std::string("Could not load image file, \"") + "res/textures/ironman.png" + "\", for texture!");
>     }
> 
> 
>     glBindTexture(GL_TEXTURE_2D_ARRAY, texture1.get_id());
> 
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
> 
>     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_MAG_FILTER, GL_LINEAR);
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); // minamp is default so w/o genminmap the texture would be disabled
> 
>     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_ptr);
>     glGenerateMipmap(GL_TEXTURE_2D);
>     //glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
> 
> 
>     glBindTexture(GL_TEXTURE_2D_ARRAY, texture2.get_id());
> 
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
> 
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
>     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); // minamp is default so w/o genminmap the texture would be disabled
> 
>     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_ptr2);
>     glGenerateMipmap(GL_TEXTURE_2D);

The only thing that determines which texture is drawn is the order in which I load the textures with glTexImage2D. The first texture is then ignored as if it weren’t there at all. I have omitted other lines of code (to be concise) but I may post them if needed. Any help would be appreciated.

So, is the texture a 2D array texture or a regular 2D texture? Your code is very inconsistent on this. You bind it as GL_TEXTURE_2D_ARRAY array, but then you call a bunch of functions on GL_TEXTURE_2D, which will in no way affect the texture you bound.

1 Like

It is meant to be a regular 2D texture. That is a silly mistake I must have looked over. I have changed the code appropriately (to GL_TEXTURE_2D) and now I don’t get any textures on my screen at all. I will continue debugging tomorrow, any further feedback would be appreciated. It isn’t clear yet whether that was the cause of the issue as described in my original post. I appreciate your quick response.

I don’t see any calls to glActiveTexture in your code. In light of:

I’d assume that you’re only using texture unit zero.

I do have that. I should have added it. Here is my render loop:

while (!glfwWindowShouldClose(glfw_window))
{
/* Render here */
renderer1.clear();

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture1.get_id());

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, texture2.get_id());
    

    {
        
        //glm::mat4 glm_model = glm::identity<glm::mat4>();
        renderer1.draw(vertex_array, index_buffer1, shader);
    }

    /* Swap front and back buffers */
    glfwSwapBuffers(glfw_window);

    /* Poll for and process events */
    glfwPollEvents();
}

Shader files:

#shader vertex
#version 330 core

layout(location = 0) in vec4 in_position; // attrib index = 0, in = comes from bound vertex buffer, vec4 = length of 4
layout(location = 1) in vec2 in_texcoord;
layout(location = 2) in float in_texid;

out vec2 v_texcoord;
out float v_texid;

uniform mat4 u_ModelViewProjectionMat;

void main()
{
gl_Position = u_ModelViewProjectionMat * in_position;
v_texcoord = in_texcoord;
v_texid = in_texid;
}

#shader fragment
#version 330 core

in vec2 v_texcoord; // attrib index = 1, in = comes from bound vertex buffer, vec2 = length of 2
in float v_texid; // attrib index = 1, in = comes from bound vertex buffer, vec2 = length of 2

layout(location = 0) out vec4 outColor;
uniform vec4 u_Color; // define a uniform of type vec4

//out vec2 Texcoord;
uniform sampler2D u_textures[2];
uniform int u_textures_t[2];
uniform float u_val;

void main()
{
// color = vec4(1.0, 0.0, 0.0, 1.0);
// outColor = v_Color;
vec4 texColor = texture(u_textures[int(v_texid)], v_texcoord);
outColor = texColor;
// outColor = vec4(u_textures_t[0], u_textures_t[1], 0.0f, 1.0f);
}

And renderer:

void Renderer::draw(VertexArray& vertex_array, IndexBuffer& index_buffer, ProgramShader& shader, const glm::mat4& model_mat)
{
shader.bind();

shader.set_uniform_matfv(“u_ModelViewProjectionMat”, m_camera->get_view_projection_mat() * model_mat);

// bind buffers
vertex_array.bind();
index_buffer.bind();

glDrawElements(GL_TRIANGLES, index_buffer.get_count(), GL_UNSIGNED_INT, nullptr); // null for 0 offset
}

This isn’t valid. From the GLSL 3.3 specification:

GLSL 4.x relaxes the constraint to require that the index be a dynamically-uniform expression, but it’s not clear that would apply in this case.

This should work (unless there are other issues with the code):

vec4 texColor0 = texture(u_textures[0], v_texcoord);
vec4 texColor1 = texture(u_textures[1], v_texcoord);
vec4 texColor = v_texid > 0 ? texColor1 : texColor0;

Alternatively, use a 2D array texture. These allow the texture layer to be selected dynamically, but are more restrictive: layers must all have the same dimensions and format, and sampling parameters (wrap and filter modes) are set for the texture as a whole.

1 Like

I’ve found the issue:

The following was set to 2,6 instead of 0,1 while I was debugging previously.

std::array<int, 2> arr = { 0, 1 };

shader.bind();
shader.set_uniformiv("u_textures", arr.data(), 1, 2);

What you mentioned is also true and I had gone from 4.5 to 3.3 as I was debugging but the issue persisted. The main cause seems to have been the GL_TEXTURE_2D_ARRAY that Alfonse pointed out. When I fixed that the texture samplers were now pointing to invalid texture units so nothing was displayed. Although, it is odd that when I used the texture array the sampler mapping didn’t seem to have an effect on rendering. I will revert my shaders back to 4.5 and apply your code. I appreciate all the help, thank you.