While texture mapping is a nice way of simulating surface textures without additional geometry, we can further embellish the appearance by blending multiple textures together on the same surface using multi-texturing. In this lab we will see how to apply multi-texturing through programmable shaders.

0. Getting Started

Download CS370_Lab21.zip, saving it into the labs directory.

Double-click on CS370_Lab21.zip and extract the contents of the archive into a subdirectory called CS370_Lab21

Navigate into the CS370_Lab21 directory and double-click on CS370_Lab21.sln (the file with the little Visual Studio icon with the 12 on it).

If the source file is not already open in the main window, open the source files by expanding the Source Files item in the Solution Explorer window and double-clicking dirtBall.cpp, dirtvert.vs, and dirtfrag.fs.

1. Associating Texture Maps in Shaders

Since we are using several textures, we will need to have several sampler shader variables. We do this similar to other global variables by declaring a uniform sampler2D variable in the fragment shader. As before, we then associate the sampler with an application identifier using

param = glGetUniformLocation(progObj,"var");

where param is an application GLuint identifier, progObj is the shader program object and var is the name of the shader global variable (again enclosed in double quotes).

Tasks

2. Multi-Texturing

First we will need to set the corresponding texture unit number (0 for a single texture) in the application for the textures units we are using via

glUniform1i(param, num);

where param is the associated texSampler[] identifier from above and num is the number of the texture unit to attach, e.g. 0, 1, etc (often stored in a symbolic constant for easier readability).

Applying several textures to a polygon is then accomplished through a process known as multi-texturing. The first texture will be applied in the standard fashion as we have done so far. The additional textures, however, will then be blended with the first to produce an enhanced effect, e.g. battle damage. After the textures are loaded (identically as before using SOIL), the mult-texturing process is accomplished by first activating several texture units (one per texture) via the command:

glActiveTexture(texture_unit);

where texture_unit is the texture unit identifier, e.g. GL_TEXTURE0, GL_TEXTURE1, etc. Once a texture unit is activated, we can then bind the desired texture to the texture unit using glBindTexture( ).

Then we assign texture coordinates for each texture unit (per vertex), i.e. multi-texture coordinates, using the command:

glMultiTexCoord2f(texture, s, t);

where texture is the texture unit identifier (described above) and s, t are the desired texture coordinates to be assigned to the vertex.

Tasks

3. Using Texture Maps in Shaders

Like other built-in shader variables, GLSL provides a (varying vec4) array for texture coordinates assigned to vertices in the application called gl_TexCoord[ ] (where the index represents a corresponding texture unit) which is then (modified and/or) passed from the vertex shader to the fragment shader. It also has built in variables for multi-texture coordinates in the variables gl_MultiTexCoord{0,1,…} for each texture unit number.

Finally in the fragment shader, we obtain the color from the sampler using the command

texColor = texture2D(sampler, gl_TexCoord[i].st);

where texColor is a local vec4 shader variable, sampler is the global sampler variable (associated with the desired texture map in section 2 above), i is the desired texture coordinate passed from the vertex shader (note we only use the .st components since we are only using 2D textures). At this point we are free to manipulate the color as desired and finally assign the result to gl_FragColor.

Tasks

Compiling and running the program

Once you have completed typing in the code, you can build and run the program in one of two ways:

(On Linux/OSX: In a terminal window, navigate to the directory containing the source file and simply type make. To run the program type ./dirtBall.exe)

The output should look similar to below

image

To quit the program simply close the window.

The multi-texturing process when used with shaders can use the textures to represent surface geometry variations that interact with lighting to produce one final effect we will investigate next known as bump mapping. In this effect we apply per pixel lighting rather than per vertex lighting to give a much more convincing surface appearance.