Ryan has been producing some great new character animations recently, which means I’ve needed to work out how we should pack and store all that sprite animation data.
Traditional sprite sheets place each frame of animation on a regularly-spaced grid in a single, large image. Individual sprites are all identically-sized, and can be referenced by their column and row number within the grid. This approach is ideally suited for tile-based games, in which every cell in the grid contains a 64×64, or 128×128 sprite, say, but they can also be used for any 2d art. Here’s a spritesheet showing Nome’s walk cycle:
When one of these sprites is rendered on 3D graphics hardware, it is typically drawn onto a “billboarded” quad – a primitive mesh made of two triangles that always faces straight-on to the camera. A script cycles through each frame of the spritesheet, drawing them to the quad in sequence in order to recreate the animation.
Quad meshes are very simple and efficient from a geometry point of view. However, the problem with this simple approach is that, as you can see in the image above, there’s a lot of “wasted” space around the outside of each sprite image. This causes two issues:
- The spritesheet itself is often bigger than it needs to be, occupying more space on disk and also when loaded into texture memory
- When drawing a sprite to the screen, the GPU wastes processor time processing transparent pixels which don’t contribute to the final image
The solution to these problems is to use a polygonal mesh which better fits around the true shape of the sprite rather than a simple quad. This means that the sprite textures can be packed closer together in the atlas, and there’s less unnecessary overdraw at rendertime. Creating a tight-fitting polygonal mesh around an arbitrary sprite is not straightforward, however, so I looked into what tools are available to help. Here’s a comparison of the sprite meshes created by four tools I’ve tried this week:
Unity Sprite Packer
This is the packer built-in to Unity (enabled via Project Settings -> Editor -> Sprite Packer). It’s very easy to use and can be enabled without changing your workflow at all – you just add the same packing tag for each sprite that you want to be added to a given atlas, and the engine takes care of the rest. For the sprite above, it created 7 triangles and reduced overdraw somewhat at the corners of the image, but still left a large amount of transparent pixels in the sprite. The simplicity of use comes at the expense of flexibility – there’s very few options to adjust the output, and the other problem I found is that it does not readily expose the created atlas. This is a problem for us as we intend to use normal-lit sprites and need to create atlassed normal maps that match the layout of the regular sprite atlas exactly (it is possible to access the texture using UnityEditor.Sprites.Packer.GetTexturesForAtlas() but it’s cumbersome)
+ Pretty well-documented
– Limited customisation options
– “Black-box” workflow and no easy access to created atlas
Simple Sprite Packer
This is a (free) 3rd party editor extension asset that follows a similar workflow to the inbuilt Unity asset. I believe it was first released when sprite packing was only available to Unity Pro customers, and this was provided as a free replacement – it doesn’t seem to have been updated in the last year but it did still work with Unity 5.3 fine for me. The accuracy of the generated mesh is similar to, if slightly worse than, the built-in Unity packer – once again creating 7 triangles but with slightly looser fit and more unnecessary transparent pixels included. The advantage, however, is that it creates the atlas as a regular PNG file, from which all individual sprites are automatically generated.
+ Relatively easy-to-use
+ Easy to access resulting texture atlas
– Unclear whether still supported
– Slightly worse fitting than inbuilt packer
This is a (free) standalone application rather than a Unity plugin. The workflow is somewhat different and rather more cumbersome than the other tools – it exports generic OBJ (or Collada) meshes rather than Unity sprites, so must be used with a mesh renderer rather than a sprite renderer component, but I found incredibly little documentation to explain the process. If you’ve already got a (non-atlassed) workflow for sprite assets you should expect to have to fiddle around making changes to get this to work. For some reason when I tested the sprite was mirrored left-right! The output actually created the closest-fitting mesh – significantly reducing the amount of overdraw (although increasing the mesh geometry to 16 triangles as a result). However, the biggest problem was that, unlike every other tool I tried, it wouldn’t automatically resize sprites to fit within a defined texture atlas size – I had to resize all my sprite images manually first and then pack them.
+ Generates very close-fitting meshes
– Not integrated or specific to Unity workflow
– Very little documentation
– Does not resize sprites to fit into atlas
– Bizarre mirroring of sprites
This is a standalone application like SpriteUV, and the only paid asset I tried. The output seemed to generate a good trade-off – an elegant mesh of only 7 triangles with less overdraw than the other similar solutions, and there were plenty of configurable options. Unlike SpriteUV, there was much tighter integration into Unity – automatically creating sprites from the atlas meaning little change to workflow, and the documentation seemed pretty clear. It even has a specific setting for creating a normal map atlas that matches the regular sprite atlas. The downside is, of course, that this is a commercial tool; we therefore just need to decide whether the improvement to the mesh fit and more efficient workflow it potentially offers is worth £34 to us….
+ Good results that balance mesh complexity against overdraw
+ Lots of customisation options
+ Specific workflow for creating matching normal atlases
+ Generated atlas is easily accessed