OpenGL Programming/Modern OpenGL Tutorial 06

= Loading a texture =



To load a texture, we need code to load images in a particular format, like JPEG or PNG. Your final program will probably use generic libraries such as SDL_Image, SFML or Irrlicht, that support various image formats, so you won't have to write your own image-loading code.

We'll load the texture using the SDL_Image add-on for SDL2.

Edit your headers: and your Makefile:

Then in  we can:

now contains the uncompressed pixels from the PNG image. contains information on how they are stored (RGB, RGBA...). See SDL_Surface documentation for details.

Note: you can find the GIMP source as res_texture.xcf in the code repository.

= Creating a texture OpenGL buffer =

The buffer is basically a memory slot inside the graphic card, so OpenGL can access it very quickly.

We don't use a "mipmap" for now, so make sure to specify  to something else than the default minimap-based behavior - in this case, linear interpolation.

We specify the source format directly for simplicity, but ideally we should check  and possibly pre-convert it to an OpenGL-supported format.

We set the texture uniform before calling the program (even if it's in this case, we're setting it to slot ).

Caution:  is not the texture id, it's the texture unit slot where we've bound the texture id.

= Texture coordinates =

We now need to say where each vertex is located on our texture. For this, we'll replace the  attribute to the vertex shader with a  :

GLint attribute_coord3d, attribute_v_color, attribute_texcoord;

Now, what part of our texture do we map to, say, the top-left corner of the front face? Well, it depends: We see that multiple texture points will be attached to the same vertex. The vertex shader won't be able to decide which one to pick.
 * for the front face: the top-left corner of our texture
 * for the top face: the bottom-left corner of our texture

So we need rewrite the cube by using 4 vertices per face, no reused vertices.

For a start though, we'll just work on the front face. Easy! We just have to only display the 2 first triangles (6 first vertices):

So, our texture coordinates are in the [0, 1] range, with x axis from left to right, and y axis from bottom to top:

Vertex shader:

Fragment shader:

But what happens? Our texture is upside-down!

The OpenGL convention (origin at the bottom-left corner) is different than in 2D applications (origin at the top-left corner). To fix this we can either:
 * read the pixels lines from bottom to top
 * swap the pixel lines
 * swap the texture Y coordinates

Most graphics libraries return a pixels array in the 2D convention. However, DevIL has an option to position the origin and avoid this issue. Alternatively, some formats such as BMP and TGA store pixel lines from bottom to top natively (which may explain a certain popularity of the otherwise heavy TGA format among 3D developers), useful if you write a custom loader for them.

Swapping the pixel lines can be done in the C code at run time, too. If you program in high-level languages such as Python this can even be done in one line. The drawback is that texture loading will be somewhat slower because of this extra step.

Reversing the texture coordinates is the easiest way for us, we can do that in the fragment shader:

OK, technically we could have written the texture coordinates in the other direction in the first place - but other 3D applications tend to work the way we describe.

= Bumping to a full cube =

So as we discussed, we specify independent vertices for each faces:

For each face, vertices are added counter-clockwise (when the viewer is facing that face). Consequently, the texture mapping will be identical for all faces: Here we specified the mapping for the front face, and copied it on all remaining 5 faces.

If a face were clockwise instead of counter-clockwise, then the texture would be shown mirrored. There's no convention on the orientation, you just have to make sure that the texture coordinates are properly mapped to the vertices.

The cube elements are also written similarly, with 2 triangle with indices (x, x+1, x+2), (x+2, x+3, x):

For additional fun, and to check the bottom face, let's implement the 3-rotations movement showcased in NeHe's flying cube tutorial, in :

We're done!

= Alternate image loading libraries =


 * stb_image: single-header, public domain, image loading library; these are not the official PNG, JPG, etc. implementations though, and have some (documented) limitations; used by SFML
 * SOIL (Simple OpenGL Image Library): public domain, image loading library meant for OpenGL; last release was in 2008 and the maintainer didn't respond to Android patches though

= Further reading =


 * Textures in the legacy OpenGL 1.x section