Sunday, 25 September 2016

Fixing texture distortion on deformed polygons

An odd effect that can be very noticeable in 2D games is the distortion that happens when deforming a texture. Especially when tapering a polygon the art can become really weird. This has been a problem in our engine for years, but since strong taper isn't used often I didn't think it needed fixing. However, when I added trails last year the distortion became much more problematic and I had to look for a solution.

If you're not very familiar with how videocards work this looks really weird. To a human it is very clear how the texture should be squashed when tapering a polygon, why can't my computer figure this out?

The reason is that videocards only handle triangles. They don't really know what a square is so if you want a square, you need to create two triangles that happen to form a square together. Many 3D tools hide this, but that's what happening under the hood.

When applying this taper to a square that consists of two triangles we can see why the weird distortion is happening. Those two triangles aren't the same size anymore: one gets squashed much more than the other. Since half of the texture is on one triangle and the other half is on the other triangle, we get this ugly malformed texture.

Another way of looking at the problem is to look at the centre of the image. The middle of the diagonal corresponds to the middle of the texture. But if we taper, then the middle isn't quite the middle of our object anymore!

Does this mean all deformed polygons always look broken? Luckily not: this problem only occurs if the texture has a different shape. If you apply a tapered texture to a tapered polygon it will look fine. The problem occurs when applying a square texture to a tapered polygon.

Now that it's clear what the problem is, how do we solve it? My first thought was to do something with shaders and modifying the texture coordinates to compensate. Maybe I could do away with explicit texture coordinates altogether and define the texture placement through a formula instead? I expect this should be possible somehow, although handling more complex geometry like trails might be pretty hard. Also, this seems overly complex and might cost additional performance: calculating the texture coordinates in the pixel shader would cost additional fillrate. Fillrate is the main performance bottleneck in Awesomenauts so anything costly there is probably problematic. (Note this older blogpost about fillrate in Awesomenauts.)

There is a much simpler solution: more polygons! If you subdivide the quad into a bunch of smaller quads the distortion becomes much much less noticeable. After a couple of subdivisions the distortion is usually hardly visible anymore. It isn't actually gone, but if the player doesn't notice it then it's good enough!

Note that a much more efficient subdivision for this particular situation is also possible by not doing a grid-based subdivision. For example by adding a second diagonal, creating a cross with 4 triangles. (Thanks to Reddit users eggfruit and not_a_profi for pointing this out.) A grid-based subdivision is more flexible though as it can also be used for other things than just solving this particular problem.

Solving problems by throwing more polygons at them is generally not a good idea, since those polygons of course cost more performance. However, our games generally use very few polygons so that's not where the performance bottleneck is for us. Also, we don't have all that many objects that need this solution, so the performance impact is negligible. Here we see a common pattern in modern game development: computers are so fast now that many things that may seem like a performance waste really don't matter, unless you're making triple-A games and are trying to beat the competition in squeezing the most effects out of the hardware.

So there you have it: I've solved this problem by simple throwing more polygons at it! Adding an option for subdivisions to the Ronitech (our own engine) had been on my wishlist for quite a while, so this felt like a good excuse to finally do so. This not only fixes the texture distortion problem: now that we have this option we could also add other fun features, like an animatable bend. I have even been playing around in my spare time with using those subdivisions for 3D heightmaps to add depth to objects in Awesomenauts. My tests show this could look really awesome, but this is not in a state where there's anything to show yet. Maybe that will make for a nice future blogpost somewhere next year. ^_^

Saturday, 17 September 2016

A simple way to smooth angular trails

Last week I discussed our tools for making trails. One problem I encountered with trails is that they often don't look very good when attached to a character. Player movement in a platformer like Awesomenauts is not very smooth: all of a sudden you jump, or land, or turn around, and this creates a trail with lots of angles in it. For some effects this is fine, but especially for wider trails a smoother, curvier look is much better. Today I would like to discuss the smoothing algorithm I implemented to solve this.

Before I continue, here's last week's overview video of our trails again, since it also contains some footage of the smoothing:

Key when smoothing a trail is that the trail should always remain attached to the emitter (in this case a character). If the smoothing makes the trail detach from the emitter just a little bit, it starts to look floaty and incorrect. An artist can work around this by fading out the trail near its start, but this is not always desired. This makes smoothing a challenge: the emitter follows the player's angular movement but the resulting trail should not.

The trail must also look stable: it can't suddenly pop from unsmooth to smooth. The conclusion of these two requirements is that we must apply the smoothing over time instead of immediately or in one step.

The smoothing algorithm I came up with turns out to be really simple. It was inspired by how subdivision surfaces work on 3D mesh smoothing, but without the subdividing.

The basic idea is this: for each segment of the trail I calculate the position in between its neighbouring segments, and then move the segment a little bit towards that centre. On a straight trail without corners this means nothing happens: the segment is already in between its neighbours. But on a corner this achieves exactly what we want: the corner moves inwards a bit, rounding the corner.

By repeating this process every frame with very small steps we get a curve that over time becomes ever smoother. At first it only processes the corners, but every frame it grows to smoothen further along the straight parts as well.

To control the smoothing I've provided our artists with two settings: one sets how strong the smoothing should be, and the other how long it should keep smoothing. If you let the smoothing take too long the trail keeps deforming and starts looking floaty and unstable. What usually works best is to use quite a strong smoothing for a very short amount of time (around 0.5 seconds). This way it stops quickly enough that the player doesn't notice significant instability.

An implementation note is that we ignore the first and last segment, since those have only one neighbour, which happens to also solve the problem that the curve needs to stay attached to the emitter. A small but important detail is that not only the first and last segment should be left out of the smoothing, but also the second and penultimate segment. This is because in my version of trails the start of the trail moves with the emitter, causing it to start really close to the second segment, which gives odd results when smoothing. Something similar happens with the final segment.

Now that I've explained how it works, here's a short video that shows the impact of the various settings that control the smoothing:

A downside of this algorithm is that the strength of the smoothing depends on the number of segments. The fewer segments there are, the stronger the effect is. This means that if an artist tweaks the number of segments after having set the smoothing, she'll need to tweak the smoothing again.

The smoothing algorithm I've described here today gets the job done, is easy to implement and costs little performance. It's nice how sometimes seemingly complex problems can have such easy solutions. :) Next week I'll discuss the texture distortion caused by deformed polygons, which is a problem for both trails and normal 2D sprites.

Sunday, 11 September 2016

Creating crisper special effects with trails

Until recently most special effects in Awesomenauts were either animated by hand or made using particles. This seemed to give enough possibilities, until we played the gorgeous Ori and the Blind Forest, which has very crisp special effects. We analysed how they achieved this and one of the conclusions was that for many things that we would make with particles, they used trails. Trails are quite an obvious concept, but for some reason it had never seemed like a big problem that they weren't an option in our tools. So about a year ago I added trails to our engine.

How to implement trails seems quite obvious: it's just a series of triangle segments, what's interesting about that? However, when I started implementing trails it turned out there are quite a lot of different approaches imaginable. I went with one that's extremely flexible, but also sometimes slightly difficult to control for certain effects. Today I'd like to share how I built our trails tool and what the pros and cons are. But before I get to that, let's start with a video that shows the tools for our trails and what our artists have made with those.

The core idea of my implementation is that a trail is like a series of connected particles, called segments. Each segment has it's own position and velocity, and the trail is formed by creating polygons in between the segments. This is a fun approach: it makes things like gravity, waviness and wind really easy, since you can just apply those effects to each segment separately and then connect them. It also means that the trail automatically stretches when you move quickly, just like a trail should.

An interesting aspect is what to do when standing still. In the case of normal particles you would just keep creating them regardless of your own speed, but with a trail that isn't a good idea: connecting segments that are nearly on the same position results in jumpy segment orientations. My solution to this is to have a minimum distance between segments and only emit another segment if you've moved enough. Doing this naively does have a weird side-effect: you get small holes in between the starting point of the trail and the newest created segment. To avoid this I move the newest segment along with the position of the emitter until a new segment is made.

If no care is taken something similar would also happen at the end, where the tip of the trail just suddenly disappears when its segment times out. Here the solution is to smoothly move the timed out final segment towards the penultimate segment before removing it.

To avoid creating too many segments, the artist sets how many segments he needs. Since I already have this minimum distance between segments I figured this would also be a good way to limit the number of segments. However, I now bumped into another oddity: if you move really quickly you will create a new segment every frame. That means that the number of segments depends on the framerate. Our artists have fast computers and usually have vsync disabled so they often run the game at 200fps or more. They need to go out of their way to see what Awesomenauts looks like on 30fps or even 20fps. To avoid situations where artists unknowingly create effects that only look smooth and good on very high framerates, I've limited the maximum number of segments per second to 60. If on older netbooks the framerate drops below that you will still get less smooth trails, but the difference between 20fps and 60fps is much more acceptable than between 20fps and 200fps.

A fun option you get from treating segments as particles is that you can do more than just leave them. A normal trail only exists when you move, it's literally a trail. But why not shoot segments away, like you often do with particles? With some creativity this can be abused to create effects like flames (shooting segments upwards) or flags (shooting segments horizontally) and get a very dynamic look for them. I also added an option for gravity/wind to change the speed of a segment over time.

One of the most fun things when making tools is when artists (ab)use them to make things you didn't expect. Especially Ronimo artist Ralph is really good at this. He considers it his personal crusade to use every feature of our editors for something. The weirder the feature, the more Ralph considers it a challenge to use it for something pretty. So when making trails my goal was to feed the Ralph by making trails super flexible. For this reason I added four different ways of mapping textures to the trail, and two textures can be combined on a single trail:

When I showed the trails to our artists they immediately wondered whether they could make things like a hair or a cape with it. Doing so with a normal trail would result in a very elastic look: trails become longer and shorter depending on how fast you move, which is usually not desired when making something like a braid or cloth. To fix this problem I added a feature that gives the trail a maximum and minimum length, shortening or stretching it when needed. This turned out not to work too well. The minimum length gave really odd results, especially when the character is standing still, so I removed that feature altogether. The maximum length does work, but in practice it doesn't produce convincing hair or cloth movement, so our artists usually go back to hand-animating those. I think to make good hair or cloth you need a very different approach: those require a real physics simulation, instead of simply emitting segments like I do now.

On top of all of the things discussed so far we got a lot of additional flexibility for free: years ago I made the tools of the Ronitech (our internal engine) in such a way that almost anything is animatable, so our artists can change most of the settings of trails over time. This allows for a lot of fun additional possibilities, like varying the thickness of a trail over time, or making the colour pulsate.

My implementation of trails does have one main downside: textures aren't very stable. The constantly varying length of the first and last segments makes textures flicker a bit, even though I compensate to get the correct texture coordinates. Framedrops can also leave longer holes in between segments, which is not immediately a problem but again it makes textures slightly less stable. I think if I were to ever make another version of trails I would decouple the polygons from the segments, and just create the polygons at equal distances over the path laid out by the segments.

All in all I'm really happy with how our trails system turned out. The approach of treating a trail as connected particles makes some things slightly unpredictable, but it does give a lot of flexibility. I expect our artists will come up with some more unexpected uses of trails in the future.

In the next two weeks I will discuss two more specific aspects of trails: the smoothing algorithm I created to make angular movement produce very smooth and curvy trails, and how to solve the texture distortion that occurs when skewing a quad with a texture on it. Till then!

Wednesday, 23 December 2015

New Awesomenauts expansion announced: Overdrive!

This Monday we've announced a new expansion for Awesomenauts: Overdrive! Lots of cool things under way, like 4 new characters, graphics improvements, new matchmaking and the Starstorm map! Most of that content will be added in free updates to the base game, while 3 of the characters will be sold as a premium DLC. That DLC is coming in March and can already be pre-ordered on the new Overdrive website (pre-ordering grants a free skin for Professor Yoolip). Here's a cool trailer to show what's cooking:

Saturday, 5 December 2015

Texture formats for 2D games, part 4: Overview

In my last three blogposts I've discussed the details of various texture formats. Now that we've seen them, it's time for an overview. Below you'll find a big table that lists the properties of a lot of different formats and shows their results. I'll also discuss some final considerations on performance.

The important thing here is to realize that there is no perfect solution: every choice has its own drawbacks, so even with the same art style you might end up with different texture formats depending on the platform. These are the main arguments to consider:
  • Quality
  • Size in video memory
  • Size on disk
  • Download size
  • Loading time
  • Framerate
  • Development time

Most of these are pretty obvious and I've already discussed quality and size in video memory extensively in my previous posts. The reason I'm listing them here is that it's important to keep in mind that you can mix and match formats for different goals.

There are also more complex things that might matter to specific games, but if things like memory bandwidth are an issue then you are probably making an extremely complex game and hopefully know more about it than I do anyway.

Let me give an example of mixing formats to achieve a specific combination of desired properties. For the original version of Swords & Soldiers 1 on the Nintendo Wii we wanted to minimize size on disk and size in video memory. In video memory we used palette textures, but on disk we also ZIPped those. ZIP cannot be used by the videocard but it makes textures a lot smaller. The downside of this is that unZIPping costs additional loading time when starting the game. However, I didn't care much about loading times because the Wii was quite fast compared to the amount of disk space available for downloadable games, so loading times were going to be fine anyway.

Here's the big overview this blogpost is all about. It compares DXT, ETC, PVRTC, palettes and several more basic formats. Creating these was a lot of work so you'd better click them for a good look! ;)

Click for full resolution

Click for full resolution

If there are any mistakes in the descriptions please let me know in the comments so that I may correct them!

An interesting note here is that Android devices differ so much that texture format support varies from phone to phone. Apparently the solution is to either only use ETC1 and uncompressed formats (since those are supported on all Android devices), or to create different versions of the game using different texture formats per type of phone.

It's important to realise that not everything is always what it seems. The benefit of saving your exact texture format on disk (through DDS or TGA instead of something like JPEG) is that you can load the texture right into video memory. You might think this means fast loading times, but this is not always the case: if reading from disk is slow (for example when reading from a DVD) then this might turn out to be a bottleneck. If your processor is fast and your disk is slow then using ZIP or JPEG might actually give you faster loading times, despite the additional processing needed. Note that in the case of Swords & Soldiers 1 this was not the case: the Wii had a small but very fast hard disk.

One final consideration I'd like to mention is framerate. In most cases texture formats don't really influence framerate: the performance bottlenecks are usually fillrate, polygon count, post processing or something on the CPU. As long as all the textures being used all fit into video memory simultaneously they won't influence performance much. As soon as you grow out of video memory however, you're in trouble. On console your game might crash or show broken graphics due to this. On PC you're less likely to see anything so obvious: PC drivers can start swapping textures between video memory and normal RAM. This is devastating to performance but you might not notice this if you're working on a fast development PC. Be sure to keep a close watch on your texture budgets, even if everything seems to still work fine on your own PC!

Texture formats can also influence fillrate. When reading the texture it might get cache misses, slowing down the GPU. I won't go into too much detail here, but the thing to keep in mind is that making your textures much higher resolution than how they're shown in-game might reduce the framerate. If you zoom in and out a lot then mipmapping is a good solution to solve this. It also helps a lot to use a texture format with few bits per pixel, like DXT1.

Some hardware (including some of the current gen consoles) also support tiled textures. Normally a “tiling texture” refers to a texture that can be repeated, but that shouldn't be confused with tiled texture formats: tiled textures in this case refer to a certain memory layout of the texture that reduces cache misses. I won't go into detail on that here either, but if you're running into performance problems due to slow texture reads it might be worthwhile to check whether your specific platform supports tiled texture formats.

Each game and platform has its own requirements and I hope this series of posts has helped you understand the various options for handling textures. Finally, for those who don't have time to seriously look into this and just want some quick and dirty advice: if you're on PC or console DXT1 is usually the best option, or DXT5 if you need alpha.

See also:
-Texture formats for 2D games, part 1
-Texture formats for 2D games, part 2: Palettes
-Texture formats for 2D games, part 3: DXT and PVRTC

PS. We're looking for interns for the coming period! We have openings in the fields of C++ coding and 2D art! Check here for more info: internships at Ronimo. Note that a basic understanding of the Dutch language is a requirement.

Saturday, 21 November 2015

Texture formats for 2D games, part 3: DXT and PVRTC

DXT is the most used texture format in games and it is what we use most in Swords & Soldiers II and Awesomenauts. DXT is easy to use but provides some weird compression artefacts, so a good understanding of how it works is very useful for both artists and graphics programmers. Since DXT is not supported on iOS I will also shortly discuss the quite similar PVRTC format. This is part 3 in my short series on texture formats for 2D games. Here are part 1 and part 2.

Note that DXT is often also referred to as DDS because DXT textures are usually saved as .DDS files. DXT is also known as S3 Texture Compression.

There are several versions of DXT. The most versatile type is DXT5, which stores an alpha channel that can be used for transparency. DXT5 uses only 8 bits per pixel, making it 75% smaller than full 32bit RGBA. If no alpha is needed or only on/off alpha, DXT1 can be used, which is even smaller: 4 bits per pixel, making it 87.5% smaller than RGBA. That's quite a spectacular win, so where's the catch?

The downside is that DXT can bring serious quality loss due to how it compresses textures. The quality impact of this compression heavily depends on the type of art: some textures will look really bad but in most cases it will look fine as long as you don't zoom in on the compression. Zooming in that far is not common in 2D games so DXT is very usable despite the quality loss.

The most basic type of DXT is DXT1. Here's how it works:

This means that if a single 4x4 block contains few different colours, there won't be any significant compression artefacts. Having more colours inside the block is also fine if those colours are near the others. For example, if the block stores red and yellow then it can also store orange well since that is in between. Heavy artefacts occur if the block contains more really different colours. For example, if a 4x4 block contains red, green and black, then one of those will be lost and replaced by one of the others (whichever is nearest to reduce the artefacts).

This sounds absolutely horrible, but the fun part is that we are only talking about tiny 4x4 blocks here. In practice few blocks contain many different colours, and even if they do the next block will be able to choose different colours, so artefacts usually remain small. In practice in 2D games DXT artefacts will mostly appear in spots where three coloured areas touch each other, and around thin outlines. Have a good look at the image below to get an idea of which situations result in serious artefacts and which are fine.

As you can see above, if your art contains lots of thin outlines it will be damaged severely by DXT1. However, fixing this by going from DXT1 to 24bit RGB makes your textures 6 times bigger. Auch! Luckily there is an awesome compromise: if you store your DXT texture at a slightly higher resolution it will look a lot better and still be smaller than RGB. Upscaling makes the outlines (or other small details) thicker, greatly reducing the artefacts. If you make your texture 41% wider and higher it becomes twice as big, which is still 3 times smaller than RGB. As a huge bonus you also get sharper textures, so this probably looks way better than the lower resolution RGB texture would have. We've used this trick in Awesomenauts on all the characters: they're stored a bit higher than required for a 1920x1080 screen to reduce artefacts.

The format I've explained so far is DXT1, while DXT5 is what you'll want to use most. Colour is stored in the exact same way in DXT1 and DXT5. The difference is that DXT1 only has 1 bit alpha, while DXT5 can also store partially transparent pixels. DXT5 stores alpha in the same way as colour, so it stores two alpha values per block. Per pixel it stores an interpolation value for the alpha. So in total DXT5 stores two colours and two alpha values per block, and for each pixel one interpolation value for the colour and one for the alpha. This makes DXT5 exactly twice as big as DXT1 and results in high quality alpha/transparency.

There's also DXT3, but in practice I've so far never found it useful. DXT3 does not store two alpha values to interpolate between: instead it just uses 4 bits per pixel to directly store alpha per pixel. Since it's only 4 bits this means DXT3's smallest alpha step is 16. In other words: DXT3 is really bad at doing subtle alpha gradients, but really good at doing strong alpha contrasts (like object outlines). Since DXT5 is already good enough at doing strong alpha contrasts I've so far never used DXT3 in an actual game.

DXT1 can also store alpha, but only 1 bit alpha, so only on/off. A clever yet simple trick is used for this. Remember that each 4x4 block stores two colours. If the first colour is brighter than the second colour, then a block can store four different colours: the two main colours and two interpolated colours. This is how I explained it above. If however the first colour is darker than the second colour, then the block can store only three different colours. The fourth colour is used for fully transparent pixels. This results in slightly less colour quality around edges in the texture. Unfortunately it's only 1 bit alpha, so any anti-aliasing on object edges is lost.

There is another type of quality loss happening with DXT compression that I haven't mentioned yet. Colours are stored with 16 bits instead of the full 24 bits. This means that on top of the compression artefacts already mentioned we also get less colour depth. For most textures this is not a problem, but for subtle gradients it is. For this reason in Awesomenauts and Swords & Soldiers II we don't store pure gradients using DXT. We use simple 24 bit TGA instead. This is much bigger, but gradients are usually very thin, so storing a bunch of 256x1 textures with less compression is no problem.

Since DXT is used by so many games there are plenty of tools and plugins to work with it. For example, Nvidia has released a free Photoshop plugin for handling DDS files. When using this for 2D games, be sure to turn off mipmaps to save some more texture space (unless you actually need those mipmaps of course). Image browsing tool XnView supports DXT right away and I've heard there's even a plugin for Windows to see thumbnails of DXT files directly in Windows Explorer.

A fun aside here is that we've tried writing our own DXT compression tool to achieve DXT with less visual artefacts specifically for 2D games. We indeed managed to slightly reduce compression artefacts, but at the cost of more flickering in animations, so we ended up not using our own DXT compression tool. Maybe I'll get around to writing about that some day, let me know if you're specifically interested in this.

An important note on DXT is that iOS doesn't support the DXT format. Instead it has PVRTC. I haven't made any iOS games myself (Proun+ and Swords & Soldiers 1 were ported to iOS by respectively Engine Software and Two Tribes) so I don't personally have any experience with PVRTC). The rough concepts are pretty similar though. The big difference is that PVRTC doesn't have the little 4x4 block artefacts that DXT produces. Instead, PVRTC's compression artefacts come in the form of a slight blurriness.

One trick to improve quality with PVRTC is the same as with DXT: saving at a slightly higher resolution than what you really need will massively reduce the compression artefacts. Aaron Oostdijk from Gamistry (creators of the mobile hits Gold Diggers and Munch Time) mentions it also helps a lot to first smear the RGB colours our across the transparent areas. “A tool called Solidify B does this very nicely. And sometimes a light dither after that will improve results even more.” Note that I didn't use those tricks when compressing the image below.

On iOS you get the additional requirements that textures need to be square (same width and height) and power-of-two (16, 32, 64, 128, 256, 512, etc.). In many cases these two extra requirements demand a huge waste of texture space, unless you work around them through clever usage of texture atlases. On PC and console these requirements have been abolished around a decade ago, making efficient texture usage much easier there.

DXT results in serious compression artefacts but it provides such powerful compression that it is by far the best option for the vast majority of games. Next week I'll wrap up this series on texture formats by giving a big overview of all the formats discussed. See you then!

See also:
-Texture formats for 2D games, part 1
-Texture formats for 2D games, part 2: Palettes
-Texture formats for 2D games, part 4: Overview

Friday, 13 November 2015

Texture formats for 2D games, part 2: Palettes

After last week's introduction to texture formats we are going to look at palette textures today. Palette textures are an interesting and underused option for 2D games. Using them is quite a hassle since normal videocards don't support them, but for certain art styles they offer high quality and small texture size.

Palette formats are similar to GIF files. The idea is that we have a palette, a list of all the colours in a specific texture. In the actual texture we don't store the colour of each pixel, but rather a reference to the palette. If the texture doesn't have a whole lot of colours we can get away with using only 256 different colours. References to these can be stored in 8 bits per pixel, so this format is 75% smaller than uncompressed RGBA.

Palette textures are particularly useful for cartoony styles with flat shading, since those have fewer colours per texture. If your textures have more than 256 colours, you can reduce the number of colours. Depending on the art style this loss in quality might be acceptable. For a style with lots of colours and gradients, it probably isn't.

Most textures in Swords & Soldiers 1 on Nintendo Wii were stored using palettes. Some textures even had few enough colours that we could get away with only 16 different colours in the entire texture. This means we needed only 4 bits per pixel. That's 87.5% smaller than uncompressed RGBA! This would bring a 4096x4096 texture down from 64mb to 8mb. Of course such heavy compression is only suitable for some art styles and some textures.

The big caveat is that most videocards don't support palette textures directly. Older videocards like the one of the Nintendo Wii support it, but none of the modern Nvidia, AMD or Intel cards do. Swords & Soldiers 1 was originally a Wii game so we could easily use palette textures there.

This doesn't mean that using palette textures is impossible, just that it's more involved. It's quite easy to write a pixel shader that uses the colour from a greyscale texture as an index for a lookup in a 1D palette texture.

The problem with doing this yourself is that you can't use texture filtering any more. Interpolating palette indices results in random colours. To implement standard bilinear filtering you need to sample and interpolate the colours yourself in the pixel shader. Including the lookups in the palette this means 8 texture reads per pixel. If you happen to also need trilinear filtering for mipmapping this increases to 16 texture reads per pixel. Luckily not all 2D games need mipmapping, but still: 8 texture reads per pixel is significant and costs performance. However, the fun part is that many 2D games have plenty of performance to waste. If this is the case for your game and you have the time to write a good pipeline for them, then palette textures might be an excellent choice.

An interesting side effect of reducing the number of colours for a palette texture is that it makes ZIPping the texture much more effective. With less colours in the texture there is less variation so it can be compressed more effectively. This only helps for download size and for the size of the texture on disk: videocards can't handle ZIPped textures so the texture needs to be unzipped before it goes into video memory.

We used this extensively in Swords & Soldiers 1 to reduce download size. Since the Nintendo Wii had an extremely small hard disk keeping the install size of the game small was really important. For this reason we reduced the number of colours even in cases where it didn't make the texture itself smaller. For example, the size in video memory is the same for a texture with 200 colours or 256 colours. However, the texture with only 200 colours can be ZIPped further. Often there is no visible quality loss when reducing the number of colours a bit further, so we did this with a lot of textures on the Wii version of Swords & Soldiers 1.

When saving an image for the web in the GIF format it's common to turn on dithering. Dithering makes a palette texture alternate between two different colours in a noisy pattern to achieve what looks like smoother gradients with fewer colours. This works quite well for the web, but is totally unsuitable for games. Dithering makes the art flicker like crazy when an object moves around, so in games it can only be used on objects that are rendered pixel perfect, like the backdrops in old adventure games.

A huge benefit of palette textures is that team colours and colour variations can be done extremely efficiently. By simply swapping the palette you can change all the colours. This costs hardly any memory or additional performance.

In Awesomenauts we don't use palette textures so we have to store each character twice: once for the red team and once for the blue team. With palette textures this wouldn't have been necessary. To add to the fun this would also have allowed us to let the player customise his team colour (not that we would want that in a team-based game in which the visuals are all about readability). Lots of other fun tricks can be achieved through clever usage of palette swapping.

Since palette textures aren't supported by videocards by default they are quite impractical to use. Their limitation of a maximum of 256 different colours per texture is also very limiting. However, with certain art styles this technique will give you powerful, lossless compression and easy colour swapping, unique benefits that no other texture format can provide.

See you next week for a look into the master: DXT texture compression!

See also:
-Texture formats for 2D games, part 1
-Texture formats for 2D games, part 3: DXT and PVRTC
-Texture formats for 2D games, part 4: Overview