Course list http://www.c-jump.com/bcc/
A vertex in OpenGL can have multiple components. That includes an (x, y, z) position in 3D space, a normal vector, and a color. In this lab, we add a new piece of vertex data -- a texture coordinate, also known as UV coordinate. Each UV coordinate specify where the vertex can find its color in a texture image. This process is called texture sampling, which yields texels -- the texture elements.
As we add all required code, we will see the practical application of textures, texture mapping, UV coordinates, pixels, texels, magnification, and minification.
We will be also experimenting with loading bitmap files and uploading them to OpenGL as textures.
Download c262_lab09.zip and unzip it under the labs subdirectory:
C:\bcc\GL262Labs\labs\c262_lab09
Open Visual Studio project
C:\bcc\GL262Labs\labs\c262_lab09\c262_lab09.sln
and compile the executable:
Build -> Build Solution
(or simply press F7.)
The starting point of this lab is the result of what we have already got working in the previous lab, GLUT keyboard and mouse events
Notice there are new keyboard key controls:
y.........altitude gain
SHIFT+y...altitude loss
z/x.......wing roll
Also, the mouse controls have changed as follows:
the mouse wheel controls variable levels of zoom
the left mouse button allows to look around
the right mouse button zooms in
Open Model.cpp and locate Model::upload_bitmap_texture() member function. It contains directions as follows:
// 1) Generate a texture ID
// 2) Bind that texture as the current ID
// 3) Load the bitmap onto the GPU using glTexImage2D()
// 4) Set the parameters for minification, magnificaiton and repeating UVs
// 5) Get the ID of the variable "texture" from the fragment shader...
To get this done, open Textures in OpenGL handout and jump to the topic Texture example (client side). A working sample project can also be found in our example folder:
C:\bcc\GL262Labs\example\Lecture17_Texture
Do it! If you are still unsure how all this code should look like, here a hint:
glGenTextures( 1, &tex_buffer_ID );
glBindTexture( GL_TEXTURE_2D, tex_buffer_ID );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, bitmap_data );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// Mipmap generation is quite easy:
glGenerateMipmap( tex_buffer_ID );
texture = glGetUniformLocation( shader->program_ID, "texture" );
Examine the code in Model::render(). Notice what this function does when UV coordinates are present in our model:
if (vTexCoord != -1) {
glEnableVertexAttribArray( vTexCoord );
// Turn on 2D texturing
glEnable( GL_TEXTURE_2D );
// Set it to be texture 0
glActiveTexture( GL_TEXTURE0 );
// Bind the texture we loaded as the current texture
glBindTexture( GL_TEXTURE_2D, tex_buffer_ID );
// and upload to the "texture" variable in the fragment shader
glUniform1i( texture, 0 );
}
You don't need to make any changes here, but understand that this is an important part of rendering the texture.
Next, open the vertex shader in Shaders\TextureShader_v.c file. Observe that there is the new in variable, vTexCoord, as well as new out variable, texCoord. This is data from our UV coordinates array, uploaded to OpenGL by Model::upload_2_server() member function. As you can see, the vertex shader doesn't do anything with UV coordinates, it simply passes the data through to the fragment shader. Nothing to change here.
Open the fragment shader in Shaders\TextureShader_f.c file. The fragment shader receives the interpolated texCoord from the vertex shader. Also notice that it has the texture variable, already bound to texture unit zero by glActiveTexture() and glUniform1i() calls (as shown above):
uniform sampler2D texture;
The texture variable provides access to the actual image in GPU memory. To use the colors from the texture, we need to modify the old formula
fColor = ambient + dif + spec;
to a new, adding texel colors into the mix:
fColor = ambient*0.5 + dif*0.5 + spec*0.5 + 0.5*texture2D(texture, newTexCoord);
I am using factors of 0.5 for each component of the final color. You may tweak it to any proportion you like -- you should start feeling how flexible OpenGL is in this regard.
A better way is to use texel color as a diffuse component:
// Calculate the diffuse part
float Kd = max (dot(N, L), 0.2); // Intensity
vec4 dif = Kd*texture2D(texture, texCoord*10);
// Calculate the specular part.
float Ks = pow (max(dot(N, H), 0.0), shininess); // Intensity
vec4 spec = Ks*specular; // ... and then color
if (dot(N, L) < 0.0) { // But only if the light is in front!
spec = vec4(0.2, 0.2, 0.2, 1.0);
}
// Compute final color:
fColor = ambient*0.5 + dif + spec*0.5;
Compile and run the program. Make sure everything works as expected. Try different models by uncommenting the corresponding MODEL_OBJ_FILENAME definitions. Remember to change the scale_amount variable if the object appears to be too small or too big on the screen.
Open Shaders\TextureShader_f.c fragment shader. Observe what happens if you change the line
newTexCoord = texCoord*10;
to
newTexCoord = texCoord;
Multiplication by 10 makes UV coordinates repeating the texture ten times more often than the original. This permits texture resizing after appropriate parameters for minification, magnificaiton and repeating UVs are specified. (In our lab those preferences are handled by Model::upload_bitmap_texture() function.)
There are no files to submit.
Demonstrate a working c262_lab09 program to your instructor.