I’ve been thinking a lot about how UV maps (rules for how to stick textures on geometry) work, how I expect to use them, and how I can best optimize using them. My first theory was that each mesh (a model made up of vertices and indexes) would have a single associated UV map for how to apply a texture to it. With animated textures and blocks that look different based on what season it is and you start to get way too many meshes that are effectively actually the same mesh with a different way of putting textures on them. Thus, it clearly doesn’t make sense to have only one UV map per mesh, especially when practically everything in the game is a block.
For normal games, a single UV map per model probably makes a lot of sense and is exactly how they work. Normal games have loads and loads of meshes and each one has one way of putting textures on each of them. Even if you have lots of different textures (skins), the mapping is the same.
In QubeKwest there are a small number of models (since virtually everything is made of blocks), and to optimize the amount of texture data being used, there are a lot of different ways to put textures on them. Imagine a block for a moment. I could make just one UV map that details how to put a separate texture onto each of the six sides of a block. That way nearly all possible blocks could be textured the same way. What happens if a block has the same texture on all six sides? In QubeKwest this is actually a pretty common thing since a lot of types of rock look the same from all six directions. If all six sides are placed onto the block separately as described above then there would need to be six copies of the same texture to make that happen. Why have six copies of the same texture if the same thing can be done with just one?
With this in mind, I came up with several ways to texture blocks. They all use the same actual geometry, but this approach improves how much actual texture is needed to make them pretty. For the descriptions below, a block has six sides called North (N), East (E), South (S), West (W), Top (T) and Bottom (B). These are some of the approaches I’ve come up:
- A single texture on all 6 sides of the block (N, E, S, W, T, B). (1 total texture.)
- A single texture on each of the 4 edges of the block (N, E, S, W) and another on the Top and Bottom (T, B). (2 total textures.)
- A texture on each of the 4 edges of the block (N, E, S, W) and 2 different ones for the Top (T) and Bottom (B). (3 total textures.)
- A different texture on each of the six sides of the block (N, E, S, W, T, B). (6 total textures.)
- A single texture on all 6 sides of the block (N, E, S, W, T, B) where the texture changes for 4 seasons. (4 total textures.)
- A single texture on each of the 4 edges of the block (N, E, S, W) and another on the Top and Bottom (T, B) where the textures change for 4 seasons. (8 total textures.)
- A texture on each of the 4 edges of the block (N, E, S, W) and 2 different ones for the Top (T) and Bottom (B) where the textures change for 4 seasons. (12 total textures.)
- A different texture on each of the six sides of the block (N, E, S, W, T, B) where the textures change for 4 seasons. (24 total textures.)
- A single texture on all 6 sides of the block (N, E, S, W, T, B) where the texture is animated for 8 frames. (8 total textures.)
- A single texture on all 6 sides of the block (N, E, S, W, T, B) where the texture is animated for 8 frames and where the textures change for 4 seasons. (32 total textures.)
This collection of UV maps allows me some interesting things without chowing down massive amounts of texture space for the same texture over and over. Number 1 in the list allows simple things like blocks of rock that are exactly the same on all 6 sides. Number 3 allows things like dirt with grass on it. The top would be grass, the sides would be something like grassy roots and dirt, and the bottom is just dirt. Number 10 allows something like water to be awesome. Water is always animated because it’s water. In the spring time, there could be little chunks of left over winter ice floating in the water. In the summer it’s back to just water. In the autumn, there could be leaves floating in it. Winter it may be frozen solid with little icy glimmers as it catches the light.
This presents another problem however. That’s a LOT of UV data to have to manually come up with (anyone that’s tried to sit there with pen and paper to try to come up with UV data knows what I mean). To that end, I’ve created a way to wrangle together all of the UV maps into one fun self calculating collection. Now when I provide a UV map for number 10 above, I can provide the data for when the season is spring and I’m showing animation frame 0 and all of the other related UV maps are derived mathematically.
With all this stuff in place, I’m getting ever closer to being able to get a textured block on the screen. For the old fans of QubeKwest, you may remember when I created enough JavaFX code to get a textured block on the screen and how that took me about an hour. Now roughly a year later (granted I wasn’t working on it for 7 months) I’m almost back to the point where I can get a textured block on the screen again, but this time with LWJGL.