Tutorial 03: texturing

downloadDownload the ready to use Eclipse project for this tutorial

In the previous tutorials we’ve seen how to draw triangles, then quads, and even how to assign a color to the scene or to a vertex. Now we are going one step further with texturing. Texturing is just the process of wrapping an image over a polygon.

A brick wall texture, from ~Captain-Nintendork

A brick wall texture, from ~Captain-Nintendork

So basically, it’s wrapping a flat 2D image onto a 3D polygon. The good news is that we’re going to texture a quad, and therefore, it’s easy to map a texture to a quad since it’s a rectangle, just like a texture. Texturing 3D objects is much more complicated and will in most case require you to use a dedicated software such as 3DS Max.

Anyway, texturing a quad is done through UV mapping. UV mapping is just a name for texture coordinates: U is the horizontal axis, V the vertical axis. The origin of the image is top-left corner and the texture will always be 1.0f in height and width.

UV Mapping

UV Mapping

So when we want to texture a quad, we just need to tell OpenGL that each vertex of the quad matches a UV coordinate.

Before we do that, though, we need to tell OpenGL we’re going to use textures. In order to do so, we use the glEnable function. This changes the state of OpenGL so if you want your game to exit cleanly you must disable what you have enabled. To sum up; put this in your “create” and “dispose” methods:

@Override
  public void create() {
    Gdx.gl10.glEnable(GL10.GL_TEXTURE_2D);
}

@Override
public void dispose() {
  Gdx.gl10.glDisable(GL10.GL_TEXTURE_2D);
}

Now you need to actually load the texture. Libgdx provides a class for this and it encompasses all the background work needed to load an image, respects its format (24 / 32 bits) and sends it to the GPU. If you are interested you can have a look at the class “Texture” but for now we are just going to use it. Within your libgdx project, create a folder named “data” and copy your texture in there. Another important thing to consider is that in OpenGL 1.x the size of textures must be a power of 2. This means that 64×64 or 128*256 images are perfectly acceptable but a 320×240 image will simply not load.

To get around this, you can simply fit your image in the nearest power of 2 image size. For instance a 320×240 image would fit in a 512×512 image. In that case when you do the UV mapping the bottom right corner of the image would have a coordinate of (320/512 = 0.625f, 240/512 = 0.46875f) instead of (1.0f,1.0f).

Let’s declare and load our brick wall texture now:

private Texture brick;
brick = new Texture(Gdx.files.internal("data/brickwall.png"));

The next thing is to specify in our mesh we’re going to use UV texture coordinates, and we map each corner of the texture to a corner of our quad:

    quadBrick = new Mesh(true, 4, 6, 
                new VertexAttribute(Usage.Position, 3, "a_position"),
                new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords"));   
    quadBrick.setVertices(new float[] {
                -1.0f, 0.0f, 0, 0.0f ,1.0f ,  //bottom left
                1.0f, 0.0f, 0, 1.0f, 1.0f,    //bottom right
                1.0f, 1.0f, 0, 1.0f,0.0f,    //top right
                -1.0f, 1.0f, 0, 0.0f, 0.0f });  //top left
    quadBrick.setIndices(new short[] { 0, 1, 2, 2, 3, 0});

In our “render” method, before drawing the quad we just have to bind the texture. Binding a texture tells OpenGL that everything that will be rendered after the binding will use this texture. It’s useful when you want to draw seamless textures in a 3D world, but not so much in a 2D world where most quads will carry a different texture. In any case, you should group together the quads sharing the same textures when drawing your scene because binding is an expensive process performance and resource-wise.

The drawn brick texture

The drawn brick texture

Similarly, I do the same to texture the bottom of the screen with cobbles.

quadCobble = new Mesh(true, 4, 6, 
                new VertexAttribute(Usage.Position, 3, "a_position"),
                new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords"));   
    quadCobble.setVertices(new float[] {
                -1.0f, -1.0f, 0, 0.0f ,1.0f ,
                1.0f, -1.0f, 0, 1.0f, 1.0f,
                1.0f, 0.0f, 0, 1.0f,0.0f,
                -1.0f, 0.0f, 0, 0.0f, 0.0f });   
    quadCobble.setIndices(new short[] { 0, 1, 2, 2, 3, 0});

cobble = new Texture(Gdx.files.internal("data/cobble.png"));
512x256 cobble texture...

512×256 cobble texture…

 

... And once rendered

… And once rendered

The last thing we want to add to the scene now is a character so that this epic rendering is complete.

Ryu in all its 256*512 glory.

Ryu in all its 256*512 glory.

This texture is a 32 bits PNG. It means we have an alpha channel in addition to classic red, green and blue channels. The use for it is simple: we want the sides of Ryu to be transparent. We want a a transparent texture because otherwise the character wouldn’t blend in the picture. Back in the days when there was no 32 bits colors, programmers were defining a color to be transparent (for instance black 0,0,0) and when a texture was drawn with this color they used techniques to not draw the pixels of this color. This technique is still found nowadays with the GIF file format.

As of today this thing should be a thing of the past and I strongly encourage you to use 32 bits textures. A free tool like Paint.NET can handle this properly. So let’s draw our Ryu!

Ryu drawn on top

Ryu drawn on top

Oops, this is not the expected behavior! In fact, pretty much like telling OpenGL that you want to use textures, you also need to tell it you want to use alpha blending. For this, we specify the following:

Gdx.gl10.glEnable(GL10.GL_BLEND);
Gdx.gl10.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

And there you have it:

Ryu with alpha blending

Ryu with alpha blending

The magic lies behind the “GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA”. There are a lot of way to blend two pixels together, and the process is thoroughly described in theĀ OpenGL documentation. If you find this subject interesting I highly encourage you to browse this URL for a few minutes.

And this concludes our texturing tutorial!

fssqdf

downloadDownload the ready to use Eclipse project for this tutorial

1 Comment

Leave a Reply

css.php