How to Optimise Playable Build Sizes— Meshes, Textures, Sound & Animation

Ben Greene
Luna Labs
Published in
12 min readOct 7, 2021
Luna Tech Series banner

This is the third article of our Luna Tech Series — a series that deep dives into the interesting technical challenges our engineering team has faced and overcome, with the aim of passing on what they’ve learned here!

Optimizing the size of your playable build is key for giving your user a smoother playable experience. It’s also an important step before going live with the creative you’ve selected for your chosen Ad Network(s).

Before we dive in further, I just wanted to quickly introduce myself.

My name is Ben Greene and I am a Technical Solutions Engineer at Luna Labs. For the past few weeks, I and a few other engineers at Luna, have put together a few articles that cover the size optimization techniques across different asset types that we recommend to our partners who use Luna Playable.

For this particular article, we will be focusing on techniques for meshes, textures, sound and animation. By the way, these best practices are relevant to all playable ads, however, some will be more focused on Unity and Luna-powered creatives.

Without further ado!

Start by only including necessary assets

Your playable build should always only include the necessary assets for your playable. If not, you could end up wasting time optimizing assets you later realise you didn’t need at all.

So, what’s necessary?

If you are building a playable using your base game project as a template, you will likely come across assets and features that won’t be usable in the limited amount of gameplay a playable allows for.

For instance, you want to create a playable scene with only 3 out of the 6 characters from your gameplay. What you can do is just exclude the other 3 that you don’t need from your build.

It is also worth assessing what components in your project are only needed for levels that won’t appear in your playable. These components can be safely removed.
This can additionally apply to scripts that handle level advancement if you’re building a playable that only has one level.

Next up are some tips and tricks to lighten the load of the remaining essential assets in your scene.

#1 Meshes — remove them and simplify geometry

Mesh Size

Meshes are generally quite heavy — they need to store vertex positions (12 bytes per vertex) as well as the instructions on how to connect these vertices to each other in order to create triangles (6 bytes per triangle).

The more mesh features you wish to use, the more space they will take up:

  • Correct lighting behaviour requires the storage of normals (12 bytes per vertex)
  • Texturing mesh requires UV coordinates (8 bytes per vertex)
  • Skinned meshes require bone info (32 bytes per vertex) etc

You can read about the rest of the mesh features that Unity has to offer here.

As you can see all this information is stored per vertex, which quickly adds up.

Unoptimized Mesh Example

Let’s do a quick estimation of a mesh with 17047 verts and 15606 triangles:

(17047 * 64 + 15606 * 6) comes to ~1.18MB of storage space.

It will come as no surprise to you after that example, that if your game is making heavy use of meshes, you should start thinking about which ones you can do without.

Removing them

Before removing any meshes, start by deciding which aspects of your game need to be close to perfect, and which aspects can function with less.

Once you have determined, zero in on the less important areas and start picking out meshes to exclude.

Here are some factors to think about when choosing which mesh to include or remove:

  • If it’s not used in your playable scene, you should remove it.
  • If you have a scene with a big environment, keep only those meshes that are visible.
  • If a mesh is visible only partly, cut all obscured vertices from it.

Simplifying Geometry

Now that we have removed all the unused parts, it’s time to remove more!

You can simplify your geometry by losing almost no visual quality, as original games often have overly detailed meshes for a playable.

Any 3D software that has a tool that allows you to choose how much you want to сut will do for this step (e.g. The Decimate Geometry tool in Blender, Optimize modifier in 3ds Max, & the Reduce feature in Maya).

What you can do here is cut the environment more than you do to your main character(s), as it is likely that the user’s attention will not be focused on the background.

Lastly, by default mesh values are stored in float precision (~6–9 decimal digits), however, you can instead use them with half-precision (~4 digits).

What does this mean? Well, say we take the number 1234, we can add a floating-point anywhere: 1.234 or 12.34 or 0.1234

Keep in mind that for geometry the unit of measurement is meters, meaning you can use millimetre precision for small-sized meshes and centimetre precision for larger meshes.

Here’s an example of how halving the size of your meshes looks for you visual learners:

If your meshes are huge or tiny (in terms of size in 3D space) you may see some artefacts as a result of this method, but in most cases, the difference isn’t visible at all!

#2 Textures — Reduce the solution, examine the colour features, and use HATC

Texture size

Textures are the second biggest space eaters behind meshes, let’s do another quick estimation to demonstrate this:

Each pixel of uncompressed texture with transparency holds red, green, blue and alpha values with 1 byte each.

If for example, the resolution of your texture is 1024x1024, that makes ~4.2MB of data! (1024 * 1024 * 4)

This is why eliminating all unused textures is a fantastic way to save space.

On top of that, if you have two textures that are quite similar, include only one of them and remove the other(s).

As you can see in the previous estimation, the resolution of a texture is both a blessing and a curse: A high resolution allows for increased visual fidelity but comes with a greater size cost.

Reduce the resolution

The approach here is similar to when we spoke about meshes; reduce the resolution.

Due to the physical size difference of mobile devices compared to say a desktop monitor, your playable’s textures don’t need to be overly large.

If a texture is likely to only take up around ~100x100pixels on a device, then there is no need for its resolution to be any bigger than that. When reducing resolution the texture quality will become more blurry, but due to the screen space on mobile devices, it will be unlikely to affect what the user sees.

Here you can find what happens when you decrease a texture by a factor of 2. It reduces the size for both axes, and in turn, it decreases the size to a quarter of its original:

1024x1024 = (2 * 512) * (2 * 512) = 4 * (512x512)

Halved Texture Resolution Size Comparison

We also should take into account the 2 types of compression; lossy and lossless: lossless resulting in a higher quality but at the cost of size, and lossy being the opposite.

Taking their differences into account, lossless should only be used on important textures (e.g. those for the main character). Whereas lossy should be applied to menial textures (e.g. those for the background) in order to further reduce size.

Essentially, you should select resolutions for your textures according to their usage. If a texture is used, such as a small icon in the UI, then there is no need for it to have a high resolution.

Also, don’t forget Unity’s Sprite Editor tool for 9-sliced / tiled sprites!

This editor allows you to define border chunks and centre chunks for your texture, and is especially handy for UI elements.

Examine the colour features of your textures

Checking what colour features your textures are making use of can also lead to saving space:

For example, textures that don’t make use of transparency can have their whole alpha channel stripped out.

Or if a texture is used (e.g. a grayscale filter), you could leave only one layer and remove other unused channels, or move other grayscale textures onto other channels. So you would have one RGBA texture, RGB and A textures, or just four R textures packed into one single image file.

For low-poly games, it’s also worthwhile to bake texture colours to vertex colours in the case of detailed meshes using less detailed textures.

Doing so will save you both texture space and increase runtime performance, as you won’t need to sample the texture of each frame.

Use Hardware Accelerated Texture Compression

To make working with textures even better, you can also use Hardware Accelerated Texture Compression. Unity supports a lot of them out of the box and you can start learning about them from this great Unity docs article.

To clarify what we mean by Hardware Accelerated, it’s the GPU that can work with compressed textures even without uncompressing them.

This allows for smaller sizes for textures in a build, much faster loading into memory, as well as less space being taken up on the GPU’s memory!

However, this means that it’s very GPU-specific:

Between Android and iOS, GPU-supported formats are different and using both platforms might require 2 separate builds.

On the downside, WebGL1 devices only have access to older and less efficient compression methods. But, when WebGL2 becomes available to all mobile devices, it’ll mean you can rely upon Hardware Acceleration across the board.

It’s also good to keep in mind that texture compression is more effective when working with PowerOfTwo resolutions (512x512, 1024x1024, 1024x256 etc).

#3 Sounds — strip out unnecessary sound and use mono sound

Sound Size

Sounds are an integral part of sculpting a satisfying experience, without them a game doesn’t feel complete. Unfortunately while essential, they can also take up a fair bit of space.

Let’s begin with the most RAW format for storing audio, PCM:

Its sampling frequency is between 44100HZ & 48000HZ, which equates to 44100–48000 samples per second, with each sample is a float value taking up 4 bytes.

That means 1 second of audio takes up 48000*4=192KB, and for more relevant example of 30sec audio: 48000*4*30=5.760MB

This is why audio is always shipped compressed by default.

Knowing this let’s now see how much 30 seconds of audio for a good quality stereo format (2 channels of sound) will take up:

Generally, for this level of quality, the storage will require 320Kbit per second of recording. This is after factoring in compression. With that said, how much would you guess a 30-second stereo track would take up?

Well, the answer is in fact around 2.4MB. [( 320000 / 8 ) * 30 * 2]

With that being for just 30 seconds of audio, you can see how this will start to add up quickly!

Strip out unnecessary Sound

Identifying audio that players likely won’t hear or notice during the brief playable scene should be stripped out.

You can also think about excluding all but 1 from a group of sound effects that differ only in pitch (e.g. piano notes). The one you choose to leave can then be pitch-shifted in order to produce the sound of the other excluded clips.

Use mono sound

Stereo sound is nice to have, but for users to really be able to appreciate it they’ll need to be wearing headphones with limited background noise around them.

As a playable can be encountered in a multitude of environments, we suggest using mono instead of stereo, which will instantly reduce the audio size by half (at the cost of audio fidelity).

But, please do take into account that if in your playable, audio is crucial for driving performance, this may not be something you wish to do.

Also, as seen in the previous estimation, the quality (bitrate) of the track factors largely into how much size it takes up.

320Kbit/sec is likely a bit much for a playable, going instead for around 160Kbit/sec will save a lot of space and get the job done just fine.

Reduce the length of your clip

I’m sure it is of no surprise that the longer your tracks are the more size they will take up.

In lieu of this, aiming for shorter tracks is another good way to lessen the size of audio in your playables. 30 seconds is ok, but try for shorter repeatable tracks (7–14 seconds tends to be long enough to avoid a monotonous pattern in most cases).

#4 Animations — Minimise animation data, reduce keyframes and remove scale keys you don’t need

Animation Size

Animations are represented by keyframes defining curves, and at times are references to other objects (e.g. sprite switching animations). In these cases of structural simplicity, well-produced animations usually take up relatively little space.

However, some animations can end up being rather large, such as humanoid animations containing masses of keyframes in order to represent fine movements of the human body.

This takes us to what I’m sure by now is everyone’s favourite, estimation time!

To begin, we need to understand that every keyframe is a struct. It has Time, value, inTangent, OutTangent, InWeight, OutWeight & Mode properties.

This first 6 being floats that take up 4 bytes each, as well as 1 byte for the mode, which means each keyframe requires 25 bytes of storage.

However, for animations of vectors (position/rotation/scale etc.), you need to animate on each dimensional axis (x,y,z) — which means triple the storage of the previous calculation, coming to 75 bytes per Vector3.

Taking these facts into account, let’s now do a calculation for an animation with 4337 keyframes: 25 * 4337 * 3 + 25 * ( 30536–4337 ) = 0.981MB

Putting this into the context of the average maximum file size limit being 5MB, you can see how animations can quickly get out of hand for a playable if not optimized.

Minimise animation data

Similar to meshes, we can use half-precision floats for storing the animation data (which will be half the size needed to store the animation). The impact on the quality of the animation will likely be hard to notice, as the floats still have 3 precision digits.

Another way to minimise data is by decreasing the framerate of the animation (e.g. from 60fps to 20fps), this will reduce the keyframes and overall size as a result.

Remove unneeded scale keys

When creating a transform animation, Unity will automatically create scale keys even if you aren’t using them. If you are indeed not using scale in your transform animation, you can safely remove these keys to save space.

Avoid duplicate frames

If you have animations that have the same frames duplicated, cut them out in favour of simply looping the animation however many times needed.

If it is the case of having recurring segments in a longer animation, it would be best to cut out the unique segments into separate animations and then piece them together as a sequence, replaying the recurring segments when needed.

Reduce keyframes/samples

Lowering the number of keyframes or samples per second in your animations will also aid in slimming them down.

If you are worried about the loss of smoothness, note that a lot of mobile devices are limited to a maximum of 30 frames per second.

As for animations using curves, proper use of smooth curves can alleviate the need for a lot of keyframes. You can read more about using curves in Unity animation here.

What’s next

Congratulations, you’ve made it to the end!

We hope that these optimization techniques will help your creative process, and while we have covered a fair few of them in this post, we aim to cover even more in upcoming articles.

As a sneak preview, the asset types we will be optimizing next are:

Sprites, Sprite Atlases, Scenes, Prefabs, Shaders, Fonts, and Engines.

We will also later be discussing easy-to-use features of Luna Playable that handles optimizing all these asset types.

Be sure to keep an eye out for the next articles 👀

As always, we’re eager to hear your feedback so please reach out and tell us what you think! In the meanwhile, you can follow us here on Medium, Linkedin, Twitter, Facebook, or Instagram.

--

--