UV maps and tiled Pixel art

Pontus Alexander
ReCreating Megaman 2 using JS & WebGL
3 min readJul 30, 2015

3D objects today are often built up from a mesh of triangles. To let the object know how to paint a texture on it a UV map is used, which is a set of relative coordinates in an image that references every corner in a triangle.

In the image above we want to map a tile from the texture to a square plane. The plane has two triangles usually referred to as faces. Coordinates in the image are specified as fractions of total size. This allows textures of different sizes to share UV maps.

In the first triangle the first corner is specified as 0.250, 0.875. That should be read as “map this point of the triangle to 25% from the left and 87,5% from the bottom of the image”. I don’t know why the bottom is used as reference for the latter.

When we have defined coordinates for all the points we end up with two sets of three coordinates. One set for each triangle, and one coordinate for each point. Coordinates and points are usually called vectors and vertices.

UV map for tile used. Vector2 is the name of a structure containing 2 unspecified values.

The problem with UV maps and pixel art is that UV maps are floating point numbers while pixel art is quantized to integers. As the computer is rendering the 3D world it is constantly resizing images to make them look pretty on screen and this causes sub-pixels that are not in the original image to be created. This is a problem when using UV maps, since adjacent pixels from the original image will sometimes affect the area inside your UV map, and “shine through”.

Imperfections in the UV map causes adjacent pixels from the original texture to shine through.

I’ve tried a couple of approaches to mitigate this. My first approach was to shave of a fraction of a pixel from each UV map, giving a little more head room for miscalculations. But I had to shave off a quarter pixel before the artifacts were completely gone, and at that point you have a worse problem with cropping.

Shaving too much off from pixels causes tiles to look crammed together or missing width, for example the first M in Metal Man looks a bit thin.

You can also tweak the way textures are filtered. I played around with different filters, but it doesn’t seem to help with this particular problem, and the filtering is needed for more important reasons like avoiding Megaman from looking weird.

This particular Megaman is not the sharpest of Megamans.

A method you can use to mitigate the artifacts is to create a border around every tile with the outermost pixels repeated.

Sprite sheet with 1 px border of repeated pixels for every tile. UV map size depicted in green rectangles.

This seemed like a lot of work to begin with. I thought about doing it live using canvas, but there were reasons regarding textures ideally being in sized to the power of 2 and not having to spend too much time initializing textures that prevented me from taking that path.

The method I came up with requires me to first separate all tiles by at least two pixels so that there is room for repeating. Then I can duplicate that layer, offset it and duplicate it again until all eight directions are covered. In Photoshop, thankfully I have a macro for this.

--

--

Pontus Alexander
ReCreating Megaman 2 using JS & WebGL

I’m a software engineer, living in Stockholm. I write about random things that interest me.