opengltexturessoil

Texture Sampler IDs not mapping to Texture Units


I'm attempting to use 3 textures on a model. I'm loading the images using SOIL and binding them to texture units 1, 2, and 3. But for some reason when I bind samplers 1, 2, and 3 to my shader, 1 produces the image bound to GL_TEXTURE2 while 2 and 3 produce the image bound to GL_TEXTURE3. Am I missing something simple here?

Definitions:

GLenum baseTextureUnitID = GL_TEXTURE1;
GLenum filterTextureUnitID = GL_TEXTURE2;
GLenum accentTextureUnitID = GL_TEXTURE3;
GLuint baseTextureSamplerValue = 1;
GLuint filterTextureSamplerValue = 2;
GLuint accentTextureSamplerValue = 3;

Loading Images:

baseTextureID = SOIL_load_OGL_texture(baseImageFile,
    SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
glActiveTexture(baseTextureUnitID);
glBindTexture(GL_TEXTURE_2D, baseTextureID);

filterTextureID = SOIL_load_OGL_texture(filterImageFile,
    SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
glActiveTexture(filterTextureUnitID);
glBindTexture(GL_TEXTURE_2D, filterTextureID);

accentTextureID = SOIL_load_OGL_texture(accentImageFile,
    SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
glActiveTexture(accentTextureUnitID);
glBindTexture(GL_TEXTURE_2D, accentTextureID);

Getting uniform locations:

baseTextureSamplerID = glGetUniformLocation(shaderProgram, "baseTex");
filterTextureSamplerID = glGetUniformLocation(shaderProgram, "filterTex");
accentTextureSamplerID = glGetUniformLocation(shaderProgram, "accentTex");

Setting Uniforms:

glUniform1i(baseTextureSamplerID, baseTextureSamplerValue);
glUniform1i(filterTextureSamplerID, filterTextureSamplerValue);
glUniform1i(accentTextureSamplerID, accentTextureSamplerValue);

Now if I sample from baseTex I get the filter Image, while the filterTex and accentTex samplers result in the accent image


Solution

  • Your problem is with the order of calls when you load the textures. SOIL_load_OGL_texture() will change your current texture bindings. It has to, since it needs to bind the newly created texture so that it can load data into it.

    Just picture what happens in this sequence of your code:

    glActiveTexture(baseTextureUnitID);
    glBindTexture(GL_TEXTURE_2D, baseTextureID);
    

    At this point, baseTextureID is bound to the intended texture unit. But the next line is:

    filterTextureID = SOIL_load_OGL_texture(filterImageFile, ...);
    

    Inside this call, the newly created texture will be bound to the current texture unit, which is the one you were planning to use for the base texture. This is the reason you have the wrong textures bound at the end of loading all the textures.

    Fixing this is easy. Simply change the order of the calls in your image loading code to first load all the textures, and then establish all the bindings:

    baseTextureID = SOIL_load_OGL_texture(baseImageFile,
        SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
    filterTextureID = SOIL_load_OGL_texture(filterImageFile,
        SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
    accentTextureID = SOIL_load_OGL_texture(accentImageFile,
        SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
    
    glActiveTexture(baseTextureUnitID);
    glBindTexture(GL_TEXTURE_2D, baseTextureID);
    
    glActiveTexture(filterTextureUnitID);
    glBindTexture(GL_TEXTURE_2D, filterTextureID);
    
    glActiveTexture(accentTextureUnitID);
    glBindTexture(GL_TEXTURE_2D, accentTextureID);