Monday, August 30, 2010

OpenGL: Multitexturing with GLSL

I've had my trouble trying to figure how to do this. There are dozens of sample on the internet, but (surprisingly) its really hard to find a complete working one. Even if there is, it usually just the GLSL part. Now this article will describe how to do the OpenGL/C++ part.


Assume that you have two texture already transfered to GPU memory with ID texname1 and texname2 (I wont describe how to do this part). Now this two texture are compliment to each other, let say you want to add this two texture and put it in your object. Now before we go to the binding part, let see how the shaders code looks like. This is the vertex shader:

void main(void) {

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

and this is the fragment shader:

uniform sampler2D idtex1, idtex2;
void main (void) {
vec4 texval1 = texture2D(idtex1 vec2(gl_TexCoord[0].st));
vec4 texval2 = texture2D(idtex2, vec2(gl_TexCoord[0].st));
gl_FragColor = 0.5*(texval1 + texval2);
}

The vertex shader is quite self explanatory. The fragment shader is easy to understand. Uniform variable tex1 and tex2 is our key to decide which texture to use. The command texture2D() requires two parameters: the ID of the texture, and the coordinate(notice that texture coordinate is s, t instead of x, y). Now of course we have to define what is idtex1 and idtex2 from our OpenGL/C++ code.

Let say we want to bind idtex1 to texname1, and idtex2 to texname2. First we tell OpenGL that the active texture is texture0 by using the command:

glActiveTexture(GL_TEXTURE0);

then we bind the texture that we want to put as the first texture:

glBindTexture(GL_TEXTURE_2D, texname1);

After that, we tell GLSL that tex1 is filled with ID texname1

tex1 = glGetUniformLocation(programObj, "idtex1");
glUniform1i(tex1, 0);

Now do the exact same thing to the second texture (ID texname2) but with glActiveTexture (GL_TEXTURE1).

After the binding process is done, you may start drawing your object that is binded by those textures. For example this is my code for the drawing process:

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programObj);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texname1);
tex1 = glGetUniformLocation(programObj, "idtex1");
glUniform1i(tex1, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texname2);
tex2 = glGetUniformLocation(programObj, "idtex2");
glUniform1i(tex2, 1);
glBegin(GL_QUADS);
{
glTexCoord2d(0.0, 0.0);
glVertex2f(-0.75, -0.75);
glTexCoord2d(0.0, 1.0);
glVertex2f(-0.75, 0.75);
glTexCoord2d(1.0, 1.0);
glVertex2f(0.75, 0.75);
glTexCoord2d(1.0, 0.0);
glVertex2f(0.75, -0.75);
}
glEnd();
glUseProgram(0);
glutSwapBuffers();
}

Pretty easy huh? If you need the whole project, feel free to contact me.


No comments: