Friday, June 21, 2013

Modern OpenGL tutorial Texture Mapping Example source code

Texture mapping technique haven't change in Modern OpenGL. If you are experience in ancient version of OpenGL you might have done Texture mapping which is similar to here.Only difference is adding the extra variable to the vertex shader and fragment shader. Texture memory lie in video memory similar to VBO which is uploaded to OpenGL. Two things we have to pass in vertex shader and fragment shader. One is texture co-ordinate to define how to map on vertex and another texture color data to define the color of every pixel.Many article are there in internet about texture.Some of the great article are below.

  1. Texture Maping and Bitmap  This example use the OpenGL version 1.5 where VBO and VAO are absent.
  2. Texture is not Picture Article presents whats the texture is about.
  3. Texure This is the blog form where I learn about Modern OpenGL. 
Download
All the code in this series of articles is available from github: https://github.com/smokindinesh/Modern-OpenGL-Series  You can download a zip of all the files from that page, or you can clone the repository if you are familiar with git.

In this program I am going to map a texture on a square. My aim is to provide the simplest source code so that beginner can understand quickly and write there own. Code of this project is similar to my previous articles I only specify the added function. In this project I have added one library loadBMP.cpp and loadBMP.h which load the Bitmap image for texture. Function to load the texture is given below.

//Makes the image into a texture, and returns the id of the texture
GLuint loadTexture(Image* image) {
 GLuint textureId;
 glGenTextures(1, &textureId); //Make room for our texture
 glBindTexture(GL_TEXTURE_2D, textureId); //Tell OpenGL which texture to edit
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 //Map the image to the texture
 glTexImage2D(GL_TEXTURE_2D,                //Always GL_TEXTURE_2D
     0,                            //0 for now
     GL_RGB,                       //Format OpenGL uses for image
     image->width, image->height,  //Width and height
     0,                            //The border of the image
     GL_RGB, //GL_RGB, because pixels are stored in RGB format
     GL_UNSIGNED_BYTE, //GL_UNSIGNED_BYTE, because pixels are stored
                       //as unsigned numbers
     image->pixels);               //The actual pixel data
 return textureId; //Returns the id of the texture
}

GLuint _textureId; //The id of the texture

static void LoadTextureMaping()
{
    Image* image = loadBMP("chessBoard.bmp");
 _textureId = loadTexture(image);
 delete image;
}

At first texture memory is resides in texture unit and then it is uploaded to OpenGL. Lets look the implementation of texture in our code.
// bind the texture and set the "tex" uniform in the fragment shader
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _textureId);
    glUniform1i(program->uniform("tex"),0); //set to 0 because the texture is bound to GL_TEXTURE0
"tex" is the uniform sampler2D variable in fragment shader. Uniform variable is used because it value is uniform and doesn't change. Uniform variable can be used in both fragment and vertex shader. Texture can't be used whithout calling glActiveTexture after that texture is bound by glBindTexture. We call the glUniform1i to upload the texture data form texture unit to "tex" variable of fragment shader. Second argument is 0 because texture is bind in 0 texture unit.
Final step is to get the texture co-ordinate.Texture co-ordinates is pass with vertex data.

// Put the three triangle verticies into the VBO
    GLfloat vertexData[] = {
        //  X     Y     Z     U     V
         -0.5f, -0.5f, 0.0f,  0.0f, 0.0f,
         -0.5f,0.5f, 0.0f,  0.0f, 1.0f,
         0.5f,-0.5f, 0.0f,  1.0f, 0.0f,
         0.5f,0.5f, 0.0f,  1.0f, 1.0f,

    };

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
    // connect the xyz to the "vPosition" attribute of the vertex shader
    glEnableVertexAttribArray(program->attrib("vPosition"));
    glVertexAttribPointer(program->attrib("vPosition"), 3, GL_FLOAT, GL_FALSE,5*sizeof(GLfloat), NULL);


    glVertexAttribPointer(program->attrib("vertTextCoord"), 2, GL_FLOAT, GL_TRUE, 5*sizeof(GLfloat),(const GLvoid*)(3*sizeof(GLfloat)));
    glEnableVertexAttribArray(program->attrib("vertTextCoord"));
You have seen in above code how I pass the texture co-ordinate in attribute variable "vertTextCoord". This is similar to my previous article Playing with color how color data are passed.
This the final output of our program.

Next Chapter: 3D model .OBJ loader/parser

1 comment:

  1. Yeah, I tried everything to get this to compile properly, including using all the library version of what you may have had back then and nothing is working.

    ReplyDelete