|
Tutorial 8 - Multitexturing
This tutorial shows how to use multitexturing in OGLSL programs. It is a very important topic, because a lot of shaders in future tutorials use multitexturing, for example image processing, texture functions and bump mapping.
A little introduction to OpenGL Multitexturing
This tutorial uses 2 RGB textures "texture1" and "texture2".

First we need to write a little C++ programm to load textures etc.
The draw loop for the two images above looks about like this:
void DrawFrame(void)
{
glTranslatef(-2.0,-1.0,0.0);
glBindTexture(GL_TEXTURE_2D, texture1);
drawBox(2.0);
glTranslatef(2.0,0.0,0.0);
glBindTexture(GL_TEXTURE_2D, texture2);
drawBox(2.0);
} |
Next step is using multitexturing:
setup for multitexturing.
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, texture1);
glEnable(GL_TEXTURE_2D);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);
glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D, texture2);
glEnable(GL_TEXTURE_2D);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INCR); |
'sending' both textures to drawBox:
(This example should result same if you disable shaders.)
void DrawFrame(void)
{
glTranslatef(-1.0,-1.0,0.0);
myShader->begin();
myShader->sendUniform1i("myTexture1", 0); // Texture Unit 0 myShader->sendUniform1i("myTexture2", 1); // Texture Unit 1
drawBox(2.0);
myShader->end();
} |
Inside DrawBox you have to define two sets of texture coordinates, one for each Texture unit. It looks like this:
void drawBox(float size)
{
// Texture Coordinate (0,0) is top left.
glBegin(GL_QUADS);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0, 1.0);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0, 0.0);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 0.0);
glVertex3f(0.0, size*1.0, 0.0);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0, 0.0);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0, 0.0);
glVertex3f(size*1.0, size*1.0, 0.0);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0, 1.0);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0, 1.0);
glVertex3f(size*1.0, 0.0, 0.0);
glEnd();
} |
To figure out how many texture units you can use, you can check GL_MAX_TEXTURE_UNITS_ARB with glGetIntegerv.
You probably noted, multitexturing functions end with ARB - multitexturing is an OpenGL extension and function pointers have to be allocated first.
OGLSL Example
In the following shader program I simply add the color values of the two textures and divide it by 2.
Vertex Program Source
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
} |
Fragment Program Source
uniform sampler2D myTexture1;
uniform sampler2D myTexture2;
void main (void)
{
vec4 texval1 = texture2D(myTexture, vec2(gl_TexCoord[0]));
vec4 texval2 = texture2D(myTexture2, vec2(gl_TexCoord[1]));
gl_FragColor = 0.5*(texval1 + texval2);
} |
Result: adding both Textures

Exercises:
1. Change fragment shader so it mirrors 2nd texture (doesn't matter which direction).
2. Add an uniform variable to move 2nd texture up and down.
A little (time based) animation would be nice.
3. How would you access neighbour texture coordinates in this example?
(hint: modify C++ code and fragment shaders for this.)
Author: Martin Christen, christen@clockworkcoders.com
(source code is included in Tutorial Version 0.2 and higher)
|