Fragment Shader and Textures

What i´m trying to do:
I have 2 textures, which i want to blend together on a plane (GL_Quad) using my own fragment shader. Later on i want to implement bump mapping.
At the moment i´m using the same image for BOTH textures to test my code.

The Problem:
Both Versions of my fragment-shader should have the same result, since the textures are equal (same image). But only Version2 seems correct…
It seems that the secound texture is missing!


//VERSION1
uniform sampler2D texture;
uniform sampler2D bumpmap;

void main() {
        vec4 colTexture = texture2D(texture,gl_TexCoord[0].st);
        vec4 colBumpmap = texture2D(bumpmap,gl_TexCoord[1].st);
        gl_FragColor =    0.1* colBumpmap + colTexture;
	
}
-------------------------------------------------------------------
//VERSION2
uniform sampler2D texture;
uniform sampler2D bumpmap;

void main() {
        vec4 colTexture = texture2D(texture,gl_TexCoord[0].st);
        vec4 colBumpmap = texture2D(bumpmap,gl_TexCoord[1].st);
        gl_FragColor =    colBumpmap + 0.1 * colTexture;
	
}

I think that the error lies in the c++ code. Here are the 3 methods that are relevant:
[ul][li]initializeShader(); []initializeTextures();[]drawPlane();[/ul][/li]


void OpenglWindow::initializeTextures(){
       //1 texture
       glActiveTexture(GL_TEXTURE0);
       glEnable(GL_TEXTURE_2D);
       glGenTextures(1,&textureNr1);
       glBindTexture(GL_TEXTURE_2D,textureNr1);

       QImage image = QGLWidget::convertToGLFormat(QImage("droplets.jpg"));
       glTexImage2D(GL_TEXTURE_2D,0, GL_RGB ,image.width(),image.height(),0,GL_RGBA,GL_UNSIGNED_BYTE,image.bits());
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);

       //2 texture (same code, same image, only for GL_TEXTURE1)
       glActiveTexture(GL_TEXTURE1);
       glEnable(GL_TEXTURE_2D);
       glGenTextures(1,&textureNr2);
       glBindTexture(GL_TEXTURE_2D,textureNr2);

       QImage image2 = QGLWidget::convertToGLFormat(QImage("droplets.jpg"));       
       glTexImage2D(GL_TEXTURE_2D,0, GL_RGB ,image2.width(),image2.height(),0,GL_RGBA,GL_UNSIGNED_BYTE,image2.bits());
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}


void OpenglWindow::initializeShader(){
    //1. create new fragmentshader
    GLuint fragmentHandle = glCreateShader(GL_FRAGMENT_SHADER);
    //2. read shader program from file
    QFile fragmentFile("shader.frag");
    if (!fragmentFile.open(QIODevice::ReadOnly | QIODevice::Text))
      exit(1);
    QTextStream in(&fragmentFile);
    QString fragSourceCode = in.readAll();
    fragmentFile.close();    
    QByteArray ba = fragSourceCode.toLocal8Bit();
    printf("size %d 
",ba.size());
    const char* src = ba.data();
    glShaderSource(fragmentHandle, 1,&src ,NULL);
    //3. compile fragmentshader
    glCompileShader(fragmentHandle);
    int compiled;
    glGetShaderiv(fragmentHandle, GL_COMPILE_STATUS, &compiled);
    if (!compiled){
        printf("compile error 
");
    }    
    //4. create program and attach the fragmentshader to it
    GLuint prog = glCreateProgram();
    glAttachShader(prog,fragmentHandle);
    //5. link programm
    glLinkProgram(prog);
    int linked;
    glGetProgramiv(prog, GL_LINK_STATUS, &linked);
    if (!linked){
        printf("linker error 
");
    }        
    //6. init shader uniforms
    int textureLoc = glGetUniformLocation(prog, "texture");
    glUniform1i(textureLoc, GL_TEXTURE0);
    int bumpmapLoc = glGetUniformLocation(prog, "bumpmap");
    glUniform1i(bumpmapLoc, GL_TEXTURE1);
    //use the prog
    glUseProgram(prog);
}


void OpenglWindow::drawPlane(){    
    glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
        glBegin(GL_QUADS);
            glMultiTexCoord2f(GL_TEXTURE0,0,1); glMultiTexCoord2f(GL_TEXTURE1,0,1); glVertex3f(-1,1,0);
            glMultiTexCoord2f(GL_TEXTURE0,0,0); glMultiTexCoord2f(GL_TEXTURE1,0,0); glVertex3f(-1,-1,0);
            glMultiTexCoord2f(GL_TEXTURE0,1,0); glMultiTexCoord2f(GL_TEXTURE1,1,0); glVertex3f(1,-1,0);
            glMultiTexCoord2f(GL_TEXTURE0,1,1); glMultiTexCoord2f(GL_TEXTURE1,1,1); glVertex3f(1,1,0);
        glEnd();    
}


Thx for your help!
Hurgh

I don’t really understand your explanation… and how / what are you testing when you use two identical textures? A bit confusing…

But at a quick glance… the maths after glFragColor in the two shaders (Version 1 and Version 2) are very different from each other…

The order of multiplication and addition will be different, hence a different result.

It should be:


 //6. init shader uniforms
    int textureLoc = glGetUniformLocation(prog, "texture");
    glUniform1i(textureLoc, 0);
    int bumpmapLoc = glGetUniformLocation(prog, "bumpmap");
    glUniform1i(bumpmapLoc, 1);

See the wiki

Sorry for my bad englisch i will try to clear things up.

Both Shader-Versions should give the same result since the textures are the same. But the results are diffrent.

if colTexture == colBumpmap => same result:


 gl_FragColor =    0.1* colTexture + colBumpmap;
 gl_FragColor =    0.1* colBumpmap + colTexture;

But -as i said- the results are diffrent.

Thanks for your time,
Hurgh

didn´t made a diffrence -.-

You need to use a vertex shader to fill the gl_TexCoord[] varyings correctly ( with gl_MultiTexCoord0 etc.). Otherwise their content is undefined in the fragment shader.

Try to use a simpler shader with just one sampler and see at first if you can render both textures, first binding textureNr1 to TEXTURE0 then binding textureNr2 to TEXTURE0;
This way, you will be sure that both textures are correctly loaded in memory.

You can then debug your shader getting the number of active uniforms with glGetProgramiv( program, GL_ACTIVE_UNIFORMS, &activeUniformNb ) and get more information about these uniforms with glGetActiveUniform.

Is this also the explenation if i use this code instead?


//Version1 (seems right, i see a bright image(texture))
gl_FragColor = 0.1*texture2D(bumpmap,gl_TexCoord[0].st) + texture2D(texture,gl_TexCoord[0].st);

//Version2 (seems wrong, i see a very dark image(texture))
gl_FragColor = texture2D(bumpmap,gl_TexCoord[0].st) + 0.1*texture2D(texture,gl_TexCoord[0].st);

Because in this way both textures are accessed using the same texture coordinates (gl_TexCoord[0]).

…and it is not working…

Hurgh

From the GLSL Specs (1.2):

The following built-in varying variables are available to write to in a vertex shader. A particular one
should be written to if any functionality in a corresponding fragment shader or fixed pipeline uses it or
state derived from it. Otherwise, behavior is undefined.
varying vec4 gl_FrontColor;
varying vec4 gl_BackColor;
varying vec4 gl_FrontSecondaryColor;
varying vec4 gl_BackSecondaryColor;
varying vec4 gl_TexCoord;

“undefined” means exactly that, you don’t know what you are getting.

You could use for testing:

vec2( gl_FragCoord.x/WIDTH, gl_FragCoord.y/HEIGHT )

as texture coordinates (exchange WIDTH and HEIGHT with your viewport dimensions)

@dletozeun
I did as you said. Both textures are loaded in memory.
I also used glGetProgramiv => the number of uniforms is 2 (if i use my shader with two samples). Seems ok though. I did´nt used glGetActiveUniform because i do not know which of the accessible information could be useful to debug.

@def
I attached a vertex shader to the program and changed the fragment shader a little.



//VERTEX shader
void main(){
        gl_TexCoord[0]  = gl_MultiTexCoord0;
        gl_TexCoord[1]  = gl_MultiTexCoord1;
        gl_Position     = ftransform();
}

//FRAGMENT shader
uniform sampler2D texture;
uniform sampler2D bumpmap;

void main() {
        gl_FragColor = 0.5 * texture2D(texture,gl_TexCoord[0].st) + 0.5 * texture2D(bumpmap,gl_TexCoord[1].st);
}


My (fragment) shader is still not working as i expect.
Here is an image showing my results.
I used two diffrent textures, as you can see.

any ideas?

Thanks,
Hurgh

Try activating and binding your textures units again just before your draw commands:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,textureNr1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,textureNr2);

I always do this after glUseProgram()…

@def
I did as you said. Sadly nothing changed…I really have no idea what to try out next…:frowning:

I uploaded the hole program. You can download it here
Anyone interesting in finding the error can try :wink:
You need qt+glew to compile and run the program.

Thanks in advance!
Hurgh

Hmmm. can’t find anything wrong in the code…
I don’t use linux, qt or glew, so no debugging here…

Please make sure the shader is actually being used:


gl_FragColor = vec4( 0.0, colBumpmap.g, colTexture.g, 1.0);

Do more GL error checking…
When using a GLSL Shader glEnable(GL_TEXTURE_2D) is not needed (ignored by the shader)

If i use following code for the fragment shader, the plane get´s black…as it should… => the shader is being used.



gl_FragColor = 0.0 * texture2D(texture,gl_TexCoord[0].st) + 0.0 * texture2D(bumpmap,gl_TexCoord[1].st);


I will do more GL error checking -.- … that will take some time… :slight_smile:

thanks for your help!

Hmmm, black is not necessarily a comforting color. Try using a more funny one like:

gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );

Sorry I am not able right now to compile and run your program.

Indeed a more funny color :). The result is correct… :stuck_out_tongue:

I also can use the code line from def´s last post. Also working as expected.

Thank you for at least thinking about compiling and running my code =)

Hurgh

Try changing to GL_NEAREST instead of GL_LINEAR while assigning texture filter type in your texture allocation code.

@awhig
that changed nothing :-/