Monday, February 17, 2014

Texture UV Coordinates

Last time I threw a texture onto a cube and was very unhappy with the results.  Since the point of the post was to load a texture let's start by fixing that.  In doing so we'll discover two details.  First with all the data being loaded from the OBJ file we can fix the texture without touching a single line of code.  Secondly when I slapped together that texture I did a bunch of things wrong.

The problem with the texture isn't how it's being drawn, but rather that it's all being drawn.  What I wanted was to have a portion of the texture on each face of the cube, making it look like a die.  Instead I put the entire texture on every face.

This all comes down to the UV coordinates used, so let's explore those a bit.  OpenGL uses a pair of float values, called the UV coordinates, to line up the texture with a vertex.  The top left of the image is coordinates 0, 0 and the bottom right is 1, 1.  So if we create a triangle and set UV coordinates to 0,1 1,0 and 1,1 then it will cut out the corresponding potion of the texture, stretch and deform it as needed, and draw it on your polygon, like this:



This means that all we need to do is change the UV coordinates in the OBJ file to match where the edges of the dice sides are and the cube should be rendered correctly.

If you're going to have a single image file need to be cut up like this to apply to a bunch of polygons and you're smart you'll be sure each portion is a nice round division of the image size.  For example if your image size is 512 pixels across, and you want four cube sides across make them all 128 pixels across.  Then the UV coordinates will work out to nice round numbers, like 0.25.  If you aren't smart and go with 114 pixels, then your UV coordinates will be ugly, like 0.222656.

Also if you're going to have a bunch of textures in a single file, and you're smart, you'll have all the textures right next to each other with no gaps.  Then you won't need to work out as many UV values since each texture in your image will share coordinates with it's neighbors.  If you aren't smart and put a 1 pixel border around each texture you can enjoy working out four coordinates for every texture in the image file.

You learn from experience, and clearly this experience taught me a few things.

Let's muddle through the math to get all the UV coordinates for my image file.  Plug them into the OBJ file, and we come up with this:
1:  # Blender v2.69 (sub 0) OBJ File: ''  
2:  # www.blender.org  
3:  mtllib Cube.mtl  
4:  o Cube_Cube.001  
5:  v 1.000000 -1.000000 -9.000000  
6:  v 1.000000 -1.000000 -7.000000  
7:  v -1.000000 -1.000000 -7.000000  
8:  v -1.000000 -1.000000 -9.000000  
9:  v 1.000000 1.000000 -9.000000  
10:  v 1.000000 1.000000 -7.000000  
11:  v -1.000000 1.000000 -7.000000  
12:  v -1.000000 1.000000 -9.000000  
13:  #1 face  
14:  vt 0.000000 0.000000  
15:  vt 0.000000 0.222656  
16:  vt 0.222656 0.000000  
17:  vt 0.222656 0.222656  
18:  #2 face  
19:  vt 0.225900 0.000000  
20:  vt 0.225900 0.222656  
21:  vt 0.444900 0.000000  
22:  vt 0.444900 0.222656  
23:  #3 face  
24:  vt 0.449900 0.000000  
25:  vt 0.449900 0.222656  
26:  vt 0.669400 0.000000  
27:  vt 0.669400 0.222656  
28:  #4 face  
29:  vt 0.674400 0.000000  
30:  vt 0.674400 0.222656  
31:  vt 0.893500 0.000000  
32:  vt 0.893500 0.222656  
33:  #5 face  
34:  vt 0.000000 0.225900  
35:  vt 0.000000 0.444900  
36:  vt 0.222656 0.225900  
37:  vt 0.222656 0.444900  
38:  #6 face  
39:  vt 0.225900 0.225900  
40:  vt 0.225900 0.444900  
41:  vt 0.444900 0.225900  
42:  vt 0.444900 0.444900  
43:    
44:  vn 0.000000 0.000000 -1.000000  
45:  vn -1.000000 -0.000000 -0.000000  
46:  vn -0.000000 -0.000000 1.000000  
47:  vn -0.000001 0.000000 1.000000  
48:  vn 1.000000 -0.000000 0.000000  
49:  vn 1.000000 0.000000 0.000001  
50:  vn 0.000000 1.000000 -0.000000  
51:  vn -0.000000 -1.000000 0.000000  
52:  usemtl None  
53:  s off  
54:  #left/1 face  
55:  f 3/4/2 7/3/2 8/1/2  
56:  f 3/4/2 8/1/2 4/2/2  
57:  #bottom/2 face  
58:  f 1/8/8 2/7/8 3/5/8  
59:  f 1/8/8 3/5/8 4/6/8  
60:  #back/3 face  
61:  f 5/9/1 1/10/1 4/12/1  
62:  f 5/9/1 4/12/1 8/11/1  
63:  #right/4 face  
64:  f 1/16/5 5/15/5 2/14/5  
65:  f 5/15/6 6/13/6 2/14/6  
66:  #top/5 face  
67:  f 5/19/7 8/17/7 6/20/7  
68:  f 8/17/7 7/18/7 6/20/7  
69:  #front/6 face  
70:  f 2/24/3 6/23/3 3/22/3  
71:  f 6/23/4 7/21/4 3/22/4  

The numbers look ugly, but it does improve how the rendered image turns out:

There's still no way to tell that we're rendering a cube though.  We'll need to apply some transforms to our model to get to see the other faces.  I want to work through some ideas I have on how to get this into my model class before explaining how it works.  Be back next time I guess, and we'll see how to make polygons move around a bit.

No comments:

Post a Comment