Search code examples
openglglslmultitexturing

GLSL Multitexturing Only Shows Texture 0


Before you ask, yes I have read numerous tutorials, similar questions posted on this and other forums, etc... I have tried every suggestion I can find, but I cannot get GLSL 3.3 multitexturing to work for the life of me.

I posted the full VS2013 project on Google Docs at https://drive.google.com/file/d/0B05Cvmc8jIzjMW1wS09BSWp3MzA/view?usp=sharing

Here is my texture-binding code:

static GLuint gTextures[2];

/* Create textures */
glGenTextures( 2, gTextures );

glBindTexture( GL_TEXTURE_2D, gTextures[ 0 ] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, gTestTexture0 );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glBindTexture( GL_TEXTURE_2D, gTextures[ 1 ] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, gTestTexture1 );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

/* For the next lines, "shader_id" is the value returned from glCreateProgram when I create
   the shader. */

glActiveTexture(GL_TEXTURE0);
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, gTextures[0]);
glBindSampler(0, glGetUniformLocation(shader_id, "mytex[0]"));

glActiveTexture(GL_TEXTURE1);
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, gTextures[1]);
glBindSampler(1, glGetUniformLocation(shader_id, "mytex[1]"));

My fragment shader code:

#version 330 core
precision mediump float;

in vec3 pass_Color;
in vec2 pass_texcrd0;
in vec2 pass_texcrd1;

uniform sampler2D mytex[ 2 ];

out vec4 outputF;

void main()
{
    outputF = vec4( 
                texture( mytex[ 0 ], pass_texcrd0 ).r * texture( mytex[ 1 ], pass_texcrd1 ).r, 
                texture( mytex[ 0 ], pass_texcrd0 ).g * texture( mytex[ 1 ], pass_texcrd1 ).g, 
                texture( mytex[ 0 ], pass_texcrd0 ).b * texture( mytex[ 1 ], pass_texcrd1 ).b, 
                1.0 );
}

Texture 1 is a white square with a gray square in the middle, so I would expect the output to be my Texture 0 with some dark shading in the middle. However, texture 0 appears unmodified. To isolate the problem, I changed the main() of the fragment shader to just:

outputF = vec4( texture( mytex[ 0 ], pass_texcrd0 ).rgb, 1.0 );

As expected, this displays texture 0. However, the real kicker is that when I change the fragment shader instruction to reference only mytex[ 1 ], the output still displays texture 0.

I have tried this on two computers, one with an ATI and one Nvidia. I thought the problem might be that the ATI computer only supports OpenGL 3.2, and therefore my shader had to use the #version 150 instead. However, the NVidia supports OpenGL 4.1, so there is no problem there. Both machines support multitexturing with legacy client calls, so lack of general multitexturing support is not the issue.

I also tried using glUniform1iv instead of glBindSampler() to set the texture units like this:

GLint samplerArrayLoc = glGetUniformLocation(shader_id, "mytex");
const GLint samplers[2] = {0,1}; // we've bound our textures in textures 0 and 1.
glUniform1iv( samplerArrayLoc, 2, samplers );

This also had no effect.

I've been programming in the old client calls (glVertex3d, glTexCoord2d, etc...) for a long time. I'm just getting spun up on GLSL. So I'm staring simply. All I'm trying to do is render a simple square in a triangle strip pattern. My vertex and texture coordinate arrays are as follows:

float vertices[] =
    {
    -0.5, -0.5, 0.0,
     0.5, -0.5, 0.0,
    -0.5,  0.5, 0.0,
     0.5,  0.5, 0.0
    };

float tex0[] =
    {
    0.0, 0.0,
    1.0, 0.0,
    0.0, 1.0,
    1.0, 1.0
    };

float tex1[] =
    {
    0.0, 0.0,
    1.0, 0.0,
    0.0, 1.0,
    1.0, 1.0
    };

Solution

  • The glBindSampler() calls in the original code are not correct:

    glBindSampler(0, glGetUniformLocation(shader_id, "mytex[0]"));
    

    The second argument for this call must be the name of a sampler object, not a uniform location. Sampler objects are a feature introduced in OpenGL 3.3, and provide a mechanism to sample the same texture with multiple sets of sampling attributes. To use glBindSampler(), the value passed as second argument would be a name obtained with glGenSamplers().

    Unless you really have a good use for them (and I don't see one based on what you posted), there is no need to get sampler objects involved here.

    I'm not sure why your other attempt did not work:

    GLint samplerArrayLoc = glGetUniformLocation(shader_id, "mytex");
    const GLint samplers[2] = {0,1}; // we've bound our textures in textures 0 and 1.
    glUniform1iv( samplerArrayLoc, 2, samplers );
    

    With shader_id being the program name (using shader in the name for a variable that is actually a program is somewhat misleading), that looks fine to me. Make sure that samplerArrayLoc came back as a valid uniform location, i.e. not -1, and call glGetError() to verify that none of the calls triggered error conditions.