Sprite Optimisation in Unity

This blog post outlines how to create efficient sprite sheets within Unity.

A typical game will contain many images, usually in the form of sprites for 2D and textures for 3D games. Loading each of these images individually unnecessarily consumes memory and processing cycles. To prevent this, most games use sprite sheets. A sprite sheet simply groups a number of images into one texture, which can then be loaded in one pass.

Sprite sheets can be imported into Unity and it is easy to define specific image frames within the sprite sheet. However, this article is not about this process but what we can do if we have imported a number of single images into Unity and we want to increase performance by leveraging the power of sprite sheets. It will also show you how many calls are required to draw your sprites (very useful when optimising your game) using the Frame Debugger.

Frame Debugger

Built into Unity is a tool called the Frame Debugger (found in the Window menu). It shows you the number of draw calls and what is being done during each call.

Frame Debugger in Unity can be used to optimise draw calls.
Frame Debugger in Unity.

Click on the enable button to start analyzing draw calls.

You can step through each call in a particular frames render. The debugger can be used whether the game is running or not. However, the results may be different because at runtime Unity does a number of things to optimize each frame render (including packing sprites, which we will setup shortly).

You can drag the slider or click the arrows to view each draw call individually. As you step through you’ll notice the calls being rendered in the Game view.

Frame Debugger Step Through. You can step through draw calls and view each call in the Game window.
You can step through draw calls and view each call in the Game window.

As you move through your draw calls you may notice that sprites are not being batched and are being drawn individually or a couple at a time. Not taking advantage of sprite batching wastes draw cycles and can be detrimental to your games performance.

So what can be done about it? We can use Unity’s built-in sprite packing feature to reduce draw calls dramatically.

Start by selecting all sprites you would like to batch and assign them a common packing tag (we used the tag ‘Sprites’). This packing tag will be used to group together individual textures into a single texture.

Packing Tag in Unity. Packing tag set to 'Sprites' for 8 textures.
Packing tag set to ‘Sprites’ for 8 textures.

Once the new packing tag has been applied you need to press play for changes to take effect. Once done, check the frame debugger to see your new reduced draw call count.

You may sometimes notice that your packed sprites are still not drawn in one call. To find out why we need to look at how Unity packs sprites.

Sprite Packing

Let’s open the sprite packer window (also found in the window menu) to see how Unity has packed our sprites.

Sprite Packer. How the sprites are packed by Unity.
How the sprites are packed by Unity.

This window shows how your sprites have been packed, including the new texture size. If you make changes to the sprites associated with this sprite pack, then you can repack them by clicking on the pack or repack button.

You can also change the way the sprites are packed by setting the packer policy. Play around with these policies to determine how they effect the overall packed sprite size for your game. The default policy should be fine if your sprites have the same dimensions.

If you had the issue where your packed sprites were not being drawn in one call, then the most likely cause is that they have been assigned different groups.

The sprite groups in my Unity game.
The sprite groups in my game.

Sprites with different compression methods are packed into different groups. You’ll notice in the image above that there are currently two sprite groups in my sample game. This is due to the fact that all but one of my sprites have a transparent background and are encoded using RGBA Compressed DXT5. The lone sprite is encoded as RGB 16bit, shown in the image below.

RGB 16Bit Group.
RGB 16Bit Group

To rectify this and include all sprites on one sheet we need to modify all sprites so they are all the same format as shown in the image below. If any of your sprites you want to combine have transparency, then you will need to select a compression that takes into account the sprites alpha channel.

Sprite Compression Technique.
Setting 8 textures to RGBA Compressed DXT5 format.

With this complete, re-run your game and once again check the frame debugger. Hopefully your draw calls have been reduced even further. You may now only have two draw calls (the first call simply clears the screen with the specified background colour).

The Frame Debugger showing two draw calls.
The Frame Debugger now shows two draw calls.

External Tools

You can of course import pre-made sprite sheets and ignore the sprite packer all together. My favourite (although I have not tested many!) is TexturePacker, which can be found here. They also provide a Unity Asset that helps with importing your created sprite sheets.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *