Texturing a surface

BlitzMax Forums/MiniB3D Module/Texturing a surface

TrickyRic(Posted 2012) [#1]
Hi,

I'm sure this is an obvious one, but the documentation isn't too clear on the B3D texture commands.

If I create a mesh with vertices at 0x0, 1x0, 2x0, 0x1, 1x1, 2x1, 0x2, 1x2 and 2x2, then create triangles between these vertices so I effectively have a 2x2 grid of squares - How do I then go about texturing each of the squares individually?

I've read that I need to set UV maps but absolutely none of the documented commands give detail on doing so. Also there doesn't appear to be anything about the size each texture needs to be to fill a 1x1 square.

Regards.


Yasha(Posted 2012) [#2]
How do I then go about texturing each of the squares individually?


For a start, you can't actually do that. One surface has one texture - more textures can be plastered over the top in further layers, but it can't have multiple textures on the same layer. So if your textures are separate, you'll need to create four separate surfaces next to each other instead (within a surface/texture layer, a vertex can only have the one UV coordinate, so it also can't mark the border between two "areas" by itself).

I need to set UV maps but absolutely none of the documented commands give detail on doing so


U and V coordinates are optional parameters to AddVertex, coming after the X, Y and Z. You can also change them later with VertexTexCoords.

Deciding what the UV coords should actually be is largely an artistic matter. If you don't yet understand them: U is X-position-on-the-texture, and V is Y-position-on-the-texture. They're measured proportionally as a floating point value between 0 and 1, rather than as pixel value. So to have a simple quad show the whole of a texture, you'd give the top left vertex UVs of 0.0, 0.0; the top right UVs of 1.0, 0.0; the bottom left 0.0, 1.0; and the bottom right 1.0, 1.0.

there doesn't appear to be anything about the size each texture needs to be to fill a 1x1 square.


Since, as described above, textures are used only in proportional terms, this question has no meaning. The texture will fit if you define the UVs as spanning the whole texture, and it will not if you don't. The pixel size of the texture is not used or exposed at any point by the 3D engine.

(There is a ScaleTexture command, but all it does is multiply the UVs. In general, you won't need to use it, as it's better to have your modellers export the right coordinates in the first place.)


TrickyRic(Posted 2012) [#3]
Hi Yasha,

Just as I thought I was doing quite well with this, it now sounds like I'm going about it completely the wrong way :-(.

Basically I'm trying to create a tilemap using a text file heightmap and a text file texturemap - the idea being that it shouldn't be too complicated to create a map editor that just saves it's arrays into these text files.

So, for a 2x2 grid I could have the following heightmap (each number being a vertex),

0 1 2
0 1 2
0 1 2

Then for the texturemap I could have the following

water.png sand.png grass.png
water.png sand.png grass.png
water.png sand.png grass.png

In code, I'm then 'simply' looping through each row of the heightmap and splitting by the spaces, then looping through the resulting array to do addVertex()'s until the whole heightmap is set, then joining everything up with addTriangle()'s.

The problem now is that I only have one surface and I've to somehow work through the texturemap. If I can only have one texture per surface then I guess I'd need to do a createSurface() for each individual tile too, which would surely result in an incredibly demanding tilemap?

What would be a more sensible way to do this?


Yasha(Posted 2012) [#4]
Well the first thing would be to unweld your tiles from one another, because as mentioned above, a vertex can only have the one UV coordinate. Therefore if two quads share a vertex, they will have to share that texture point. All you have to do to do this is create a few duplicate vertices - there should be little visual difference (you might find it easier to change the loop from "creating vertices" to "creating quads", and let the duplication handle itself).

With that out of the way, remember the rule about one texture per surface is only a hardware one. If you can fit more than one piece of artwork into the same file, the engine considers them the same texture. By placing your tile-textures in a grid formation on one larger image file, you can create what is commonly called a "texture atlas"; apply this texture to the surface, and all of the subtextures you wanted will be available.

To draw a specific subtexture, you just need to know its position in the atlas. Say your atlas is 4 by 4, with 16 elements. If water is the first element, then the UVs for the quad that you want to display a water texture should be set to 0,0;0.25,0;0,0.25;0.25,0.25 ...etc. The rest of the texture will not appear on the quad in question.

This is a very commonly used technique, especially for tile-based engines, so you should be able to find a decent amount of information on it from various sources. Done properly, it's very efficient.


TrickyRic(Posted 2012) [#5]
Hi Yasha,

I think that makes sense, thanks. Fingers crossed I can get something off the ground now! Pun completely intended...

Regards.


TrickyRic(Posted 2012) [#6]
Bingo!

Thanks Yasha, I've gotten it working using the texture atlas technique. I'll post the code in a little while after more testing for anyone that finds it useful.

Regards.


TrickyRic(Posted 2012) [#7]
It's not fantastic and I haven't commented the code at all well enough yet, but here's the resulting tilemap engine (well it's not really an engine yet). There's hardly any code involved so I figured this would be useful for anybody else looking to build something similar.

main.bmx is the file to load and compile. It uses MiniB3D so the code isn't as daunting, for me at least, and it builds the map from a heightmap and texturemap file. Both are just text files.

The actual magic is in loadmap.bmx, which provides the function loadMap(), taking paths to the heightmap, texturemap and the actual textures graphic as params, as well as 2 other params to define the number of tiles in the texture graphic and the pixel size of each tile (required for the math at the moment, though hopefully I can drop this requirement!)

Criticism is very much welcome, however harsh, and thank you to everyone on these forums that's helped me get started with this thing.

http://www.qweb.co.uk/tilemap-engine/basics.zip

Regards.