CS 480/680 (Fall 2018) Part 2: Texture Loading
Today’s Topics What are Textures? Textures and Assimp Image Libraries Textures and OpenGL References Questions
What are Textures? Textures are a method for giving your objects a more sophisticated and realistic color scheme.
Textures and Assimp const aiScene *myScene = importer.ReadFile(yourObjFile, aiProcess_Triangulate); Remember how myScene points to an impressively large data structure? We then used this data structure to obtain the vertex coordinate info to render our models. Now, we’re going to use that data structure to obtain the texture mapping coordinates for each of our models.
Textures and Assimp First off, we are going to need to change our Vertex struct: struct Vertex { GLfloat position[3]; GLfloat uv[2]; };
Textures and Assimp Why am I replacing GLfloat color[3] with GLfloat uv[2]? Textures specify two coordinates on an image with which to map that portion of the image to your object. The values in GLfloat uv[2] will always be in the range of 0.0-1.0 (inclusive).
Textures and Assimp In an aiMesh object, there is the following attribute: aiVector3D *mTextureCoords; Just like you used the mIndices array to offset into aiMesh’s mVertices array, you are going to use the mIndices array to offset into aiMesh’s mTextureCoords array. This data will go into your updated array of Vertex structs that will be sent to the GPU.
Textures and Assimp You can implement a test to check if the mesh has texture coordinates: mesh->HasTextureCoords(0); // returns a bool For obtaining the texture coordinates: aiVector3D uv = mesh->mTextureCoords[0][face.mIndices[k]]; Where k is the appropriate offset into the mIndices array. vert[i].uv[0] = uv.x; // could also use pointers vert[i].uv[1] = uv.y; // here for offset Where i is the appropriate offset into your array of Vertex objects.
Textures and OpenGL At this point, we have coordinate data and texture data coupled together into an array of Vertex structs. Next, we’re going to use OpenGL functions to interact with our textures, but first, we need to use an image library to read our pictures.
Image Libraries Magick++ What we used last year, recommended FreeImagePlus Any other image library you want. Specify which library you chose in your README. Each library will have it’s own set of functions that you will need to utilize. Note: you will have to modify the LIBS section of your makefile and #include the correct libraries.
Textures and OpenGL Since we have modified our Vertex struct, which is being sent to the GPU (to the shaders), we are going to need to modify some shader code: In the vertex shader: Replace your attribute vec3 color variable with a attribute vec2 variable. Replace your varying vec3 color variable with a varying vec2 variable. Using these new variables, pass the texture to the fragment shader.
Textures and OpenGL Code modifications (continued): In the fragment shader: Replace your varying vec3 variable with a varying vec2 variable. Declare: uniform sampler2D gSampler; Inside main: Assign gl_FragColor to texture2D(gSampler, texture.xy), where texture is your new varying vec2 variable.
Textures and OpenGL Code modifications (continued): You are going to have to initialize a global GLint variable and use that variable to find the location of your new varying vec2 variable in the shaders (just like your old programs have done with loc_position and loc_color).
Textures and OpenGL Textures in OpenGL are somewhat analogous to VBO’s in the sense that they must be generated, bound, and activated (among a couple other things). You’re going to want to create a texture for each object (can have an array of textures). For generating a single texture (do this first; goes in your initialize() function): GLuint aTexture; glGenTextures(1, &aTexture);
Textures and OpenGL Binding textures (functions go in this order; also in initialize()): glActiveTexture(GL_TEXTURE0); Parameter will not change. glBindTexture(GL_TEXTURE_2D, aTexture); Second parameter is different if aTexture is an array of textures. Look up documentation.
Textures and OpenGL Binding textures (continued; still in this order): glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); Here, imageWidth and imageHeight are integers you obtain from the functions provided by your image library and imageData is an array of pixels that you create from your image library. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Textures and OpenGL Inside render(): You’ll want to call glActiveTexture(GL_TEXTURE0) and glBindTexture(GL_TEXTURE_2D, aTexture) so that you bind each texture to the corresponding object. You’ll also want to call glEnableVertexAttribArray() on your new GLint location and use glVertexAttribPointer() to describe the format of the the texture data to the GPU. All of this has been happening in your old programs.
References https://open.gl/textures We suggest reading this page. You’ll get filled in on what’s happening behind the scenes and you’ll better understand the functionality of the parameters in the previous functions.
Questions?