PDA

View Full Version : Fragment Shader and Textures



Hurgh
06-24-2009, 04:03 AM
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:
initializeShader(); initializeTextures(); drawPlane();



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_UNSIGNE D_BYTE,image.bits());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R, 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_UNSIG NED_BYTE,image2.bits());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R, 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 \n",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 \n");
}
//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 \n");
}
//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

scratt
06-24-2009, 04:18 AM
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.

dletozeun
06-24-2009, 04:28 AM
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 (http://www.opengl.org/wiki/GLSL_:_common_mistakes#Binding_A_Texture)

Hurgh
06-24-2009, 04:33 AM
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

Hurgh
06-24-2009, 04:36 AM
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 (http://www.opengl.org/wiki/GLSL_:_common_mistakes#Binding_A_Texture)

didnīt made a diffrence -.-

def
06-24-2009, 05:10 AM
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.

dletozeun
06-24-2009, 05:15 AM
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 (http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniform.xml).

Hurgh
06-24-2009, 05:22 AM
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


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.

def
06-24-2009, 07:02 AM
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)

Hurgh
06-24-2009, 09:05 AM
@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 (http://imagebin.org/53545) showing my results.
I used two diffrent textures, as you can see.

any ideas?

Thanks,
Hurgh

def
06-24-2009, 04:53 PM
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()...

Hurgh
06-25-2009, 02:21 AM
@def
I did as you said. Sadly nothing changed...I really have no idea what to try out next...:-(

I uploaded the hole program. You can download it here (http://www.2shared.com/file/6444292/95037797/shaderstar.html)
Anyone interesting in finding the error can try ;)
You need qt+glew to compile and run the program.

Thanks in advance!
Hurgh

def
06-25-2009, 04:03 AM
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)

Hurgh
06-25-2009, 04:19 AM
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.. :)

thanks for your help!

dletozeun
06-25-2009, 05:49 AM
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.

Hurgh
06-25-2009, 06:00 AM
Indeed a more funny color :). The result is correct... :p

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

awhig
06-25-2009, 02:06 PM
Try changing to GL_NEAREST instead of GL_LINEAR while assigning texture filter type in your texture allocation code.

Hurgh
06-26-2009, 04:22 AM
@awhig
that changed nothing :-/