4 Ways To Increase Performance of your Unity Game

September 6, 2016: We are looking for a Unity C# Developer and Node.js/Back-end Developer to join our team. You can find the vacancies here!

Performance is critical for mobile games, especially for fast-paced action games. As you probably know, we are currently making a pinball game for iOS / Android. It features fast physics combined with fully animated characters and a 3D world. Any pinball game needs 60 frames per seconds of performance, and we need to squeeze every drop out of the little CPUs of our target devices to achieve that.

So the challenge for us is to keep the game running smoothly at (at least) 60 frames per second. Any drop below 60 fps will cut the framerate in half! Switching from 60 fps to 30 fps would mean a serious hick-up, and it would kill the “feel” of the game if it happens too much.

To top it off, we want to support the ancient iPhone 3GS, and we need at least a steady 30 frames per second for that.

Above: Momo and Fry are beating up two owl bandits – Four characters on screen at the same time. 

So performance is critical. How do you approach this when you are making an iPhone / Android game with Unity? Here are four Unity tools we used to optimize the framerate of the iPhone / Android versions of Momonga.

1. Use The Performance Profiler

The first thing to look at when you want to improve the performance game is the Unity Profiler. It is a Unity Pro feature that lets you analyze performance bottlenecks. The Profiler is an invaluable tool. With it, you can determine where any framerate issues are coming from. You run the game on your target device, and run the profiler on your PC. When you launch the game, the Profiler starts pumping out performance data.

The good part about this is that even when profiling an iPhone or iPad, you can run the Profiler from a windows machine.

To use the Profiler on your mobile devices, simply build the game in Developer mode. From the Unity documentation:

To be able to connect to a player, the player must be launched with the Development Build checkbox found in the Build Settings dialog. From here it is also possible to tick a checkbox to make the Editor and Player Autoconnect at startup.

The Profiler shows a graph of the CPU usage while you play the game. Simply keep your device connected to your development machine, and play the game. It shows all your bottlenecks and hick-ups, in real-time. The Profiler categorizes the activity in a couple of areas: Rendering, Scripts, Physics, GarbageCollector, VSync and Others.

For mobile games, the issues are usually related to rendering. For Momonga, the rendering takes up roughly 40% of the CPU. This is an area we have to be careful with: we try to cut back on vertex and poly count.

There is the occasional spike in scripts when a scene is loading – but it is not unusual to have a lower framerate in a loading screen. You can still see some spikes, which are mostly related to physics. This will be our next focus area if we want to further improve the performance.

2. Static batching

Static batching is a feature of Unity that saves a lot of CPU cycles. It works like this.

Every time an object gets rendered there is a “Draw Call” – basically a command to the CPU or GPU that the object needs to get rendered. Unity issues several drawcalls and overlays them on top of each other. This is what makes the scene complete. However, each Draw Call has CPU overhead, and you want to minimize the Draw Calls as much as possible. Compare a draw call to a blank canvas on which an object gets painted. Would you rather have 1 canvas to paint on, or 50? I thought so.

This is where Batching comes in. It makes sure that no unnecessary Draw Calls are used. Batching comes in two flavours: Static and Dynamic.

Static gives you the best performance, so we always try to use Static Batching. Learn the details of it here.

To effectively use static batching you want to have as few different materials as possible. To achieve this you could combine all your materials in one big texture. We have opted to use vertex colors and have one pattern texture for all objects. Vertex coloring allows you to give each vertex a colour, which removes the need for real-time lighting. The colors are painted directly on the models by our artists. This means all our props and environment objects use the same material. And that’s great for Static Batching.

Above: Static Batching in action. Note these objects are rendered with a single Draw Call.

Using vertex colors only looks a bit dull. So we have a couple of pattern textures which are multiplied with the vertex colors to give the objects a bit more “texture”.

Above: Vertex colors and a pattern texture. 

The last step is to add a lightmap to the scene. Because we hardly use any texture memory for the objects themselves, we can have a fairly detailed lightmap without running into memory issues.

Static Batching requires you to set the flag “Static” in the Object Properties panel. It can only be used on objects that do not move, rotate or scale in the scene.

3. Dynamic Batching

When Static Batching is not an option, Dynamic Batching can save the day. As a matter of fact, it is always active on objects that are not static. To use it you just have to use as little objects as possible with as little vertices as possible.

Batching dynamic objects has certain overhead per vertex, so batching is applied only to meshes containing less than 900 vertex attributes in total.
Our shader is using Vertex Position, UV and Colors. So we can have upto 300 verts per object.

Some useful tips from the Unity manual:

  • Batching dynamic objects has certain overhead per vertex, so batching is applied only to meshes containing less than 900 vertex attributes in total.
    • If your shader is using Vertex Position, Normal and single UV, then you can batch up to 300 verts and if your shader is using Vertex Position, Normal, UV0, UV1 and Tangent, then only 180 verts.
  • Don’t use scale. Objects with scale (1,1,1) and (2,2,2) won’t batch.
  • Uniformly scaled objects won’t be batched with non-uniformly scaled ones.
    • Objects with scale (1,1,1) and (1,2,1) won’t be batched. On the other hand (1,2,1) and (1,3,1) will be.
  • Using different material instances will cause batching to fail.
  • Objects with lightmaps have additional (hidden) material parameter: offset/scale in lightmap, so lightmapped objects won’t be batched (unless they point to same portions of lightmap)
  • Multi-pass shaders will break batching. E.g. Almost all unity shaders supports several lights in forward rendering, effectively doing additional pass for them
  • Using instances of a prefab automatically are using the same mesh and material.

And a little tip on top of that: If an object has an animation but there are parts that never move, you can mark that part as static and it will not interfere with the animation.

Dynamic Batching is very useful for star pickups and other small objects that are animated but are otherwise the same in the scene.

4. Audio Optimizations

We suffered from some serious performance issues, and after some digging it turned out that the audio was causing the trouble.

The Unity Component Documentation has this to say about audioclips:

As a general rule of thumb, Compressed audio (or modules) are best for long files like background music or dialog, while Native is better for short sound effects.

This is good advice, but there is a catch. We found that having the incorrect compression settings can still mess up your memory usage or cause CPU spikes while playing.
Carefully reading the unity manual helped us locate the problems:

“Note that only one hardware audio stream can be decompressed at a time.”

We were seeing CPU spikes because the Iphone can only decompress one audiofile at a time using the hardware decoder.
This can be solved by using the “Decompress On Load” setting. Performance increases, but it causes the memory footprint to skyrocket. So only use this when it’s really needed.

These are our rules of thumb for optimal performance when it comes to different types of audio:

  • Short Clips – Native
  • Longer (or looping) clips – compressed in memory
  • Music – Stream from disc
  • Files which consistently cause CPU spikes – Decompress on load

If you follow these rules, audio should not give you much trouble. Except if you launch a whole armada of sound files all at once.

Concluding

The most important thing for mobile games is to keep your triangles, vertices and drawcalls as low as possible. And if you run into performance troubles, Unity provides a lot of tools to get it back under control. It will surely pay off to read the documentation.

Those are all the tips we have for now!

What are your little tricks to improve performance? Let us know in the comments!

51 Comments
  • Tim Miller
    Posted at 16:32h, 30 July Reply

    Hi Yorick, great article – especially the Static Batching tips. I’d like to hear more about your modeler’s vertex lighting workflow. I’ve played around with vertex lighting in Maya but couldn’t figure out all the steps to bring it into unity properly.

    • Derk
      Posted at 17:06h, 30 July Reply

      Hi Tim,
      It has been a while since I used vertex lighting in Maya. What I recall from that, it could be that the exporter or shader is discarding vertex color information because it uses vertex lighting.

      Hope that helps!
      Derk

      (Also note that we use Max, and we are not baking the vertex colors but we manually paint it)

    • Nabeel Saleem
      Posted at 01:14h, 02 April Reply

      I see sometime static batching wont work i dont know why , then we use third party plugins 🙁
      but lightmapin, culling and lightprobe can give you more speed,
      http://t.co/onqog7qQe2

    • Nabeel, the gamedev (@Nabeelshaikhd)
      Posted at 23:00h, 05 August Reply

      check it out : http://t.co/bjpAa0BoSm

  • aerique
    Posted at 20:14h, 30 July Reply

    Nice to see you guys show up on Reddit!

    I worked from November 2011 to February 2012 on the floor above you 🙂

    • Derk
      Posted at 22:11h, 30 July Reply

      Hey that’s awesome Aerique! Great to see you on the blog 🙂

  • gianluca
    Posted at 11:10h, 31 July Reply

    Nice article! Sometime ago I wrote a blogpost on how to use Coroutines instead of Update() when possible, which has helped with my game quite a lot: http://www.doorapps.com/2012/07/04/proper-coroutine-use/

    • Derk
      Posted at 10:07h, 01 August Reply

      Cool, thanks for sharing!

  • Luuk Waarbroek
    Posted at 15:54h, 31 July Reply

    Great article!

    Some lower level tips:

    When using GetComponent, try and store them once instead of looking them up multiple times. Also try to get the component you directly need; for instance if you want to do something with a Rigidbody of a GameObject directly get the Rigidbody, first getting the GameObject and then the Rigidbody will take up more performance.

    Cheers,
    Luuk

    • Derk
      Posted at 10:31h, 01 August Reply

      Thanks Luuk, that’s a good tip!

  • 4 Ways To Increase Performance of your Unity Game | Sanneblad.com
    Posted at 00:20h, 01 August Reply

    […] 4 Ways To Increase Performance of your Unity Game (paladinstudios.com) Share […]

  • xdegtyarev
    Posted at 09:29h, 01 August Reply

    Hi there, great article. Thanks for tips.

  • Mark Cooke
    Posted at 23:12h, 02 August Reply

    While building a 2D game the majority of our performance problems came from overdraw due to lots of overlapping transparent triangles. We ended up building geometry along the edge of characters / environments and split the objects into two materials, one for the opaque core and one for the transparent edge.

    It resulted in a lot more verts/tris and more draw calls but ultimately was significantly faster than quads since we weren’t geometry bound.

    Just a quick tip for those who are building 2D experiences.

    • Derk
      Posted at 15:13h, 05 August Reply

      Thanks Mark, that’s great advice!

  • Paul Hansen
    Posted at 16:08h, 05 August Reply

    Under “2.Static batching” 4th paragraph down the link is broken it should be this: http://docs.unity3d.com/Documentation/Manual/DrawCallBatching.html Unity has been removing “iphone” from stuff lately because of android.
    Great article btw.

    • Derk
      Posted at 11:07h, 06 August Reply

      Thanks Paul! Fixed the link, should be good now.

  • Ali
    Posted at 08:13h, 19 November Reply

    Derk, I am unable to open that “2. Static batching” link

  • Niki.j
    Posted at 07:51h, 21 December Reply

    Hi,

    thats really very helpful article,specially for the static batching and audio optimizations.
    thanks!

    guys i am working on a 3d game having four scene and all of them have great polygon count,i am using all of the tricks mentioned above in the article/posts.but still facing the problem in my last level.the terrain in the level draws very slowly and it looks like that it gets unfolded while character going near to it.

    Thanks in Advance!
    Niki.j

    (Tip :- 1. don’t declare variable in update/OnGUI kind of functions.
    2. create references for the objects/components in start and then use them rather then accession them using GameObject.Find() or GetComponent().)

  • Emmanuel Henné
    Posted at 12:31h, 20 January Reply

    Hi, I get that scaling part wrong probably: does it mean no scaling when IMPORTING objects or no scaling when they have been placed in the scene ? Thanx 😀 Gorgeous looking game 😀

    • Derk
      Posted at 15:37h, 22 January Reply

      Hi Emmanuel, you can scale it any way you like in your modeling package, but you should keep the scale the same for each instanced object in Unity.

      Suppose you have a tree model, you might want to use that several times in the Unity scene. You should keep the scale the same for every tree in the scene, or dynamic batching won’t work.

      Good luck!

  • rbsavage
    Posted at 22:37h, 24 January Reply

    Here is another tip that wasn’t obvious to me: Cache positions, every time you access anything in transform, it has to calculate the position based on the current location of it’s parent objects (if you are accessing the position of many nested objects this can get quite expensive).

    Also for those of us who can’t put out the extra bones for Unity Pro, there is FPS Graph, which can give you some of the same performance feedback (although not nearly as detailed as the Unity Pro Profiler, it can still be helpful for $5).

    FPS Graph link: http://u3d.as/content/dented-pixel/fps-graph-performance-analyzer/400

    • Derk
      Posted at 14:40h, 28 January Reply

      Thanks for the tips! 🙂

  • Ben Morris
    Posted at 20:00h, 31 January Reply

    Thanks for the tips, the audio section was particularly helpful. Is there any performance downsides to streaming music from file, I imagine it could be slow depending on the hardware?

    You mentioned that iPhone / iPad could be profiled on Windows. I have searched all over for how this can be set up but I can’t get it working. I built for iPhone with “Development Build” checked using Unity iOS Basic. On Windows, I have Unity Pro with Android set up. However the iPhone device never shows up in the profiler window. Are there any other steps that need to be taken.

  • Matfink
    Posted at 21:02h, 24 February Reply

    Great info – thanks for sharing!

  • ankit khetrapal
    Posted at 10:35h, 04 March Reply

    thanks a lot guys i never expected audio to be such a big issue….

  • Lea Hayes
    Posted at 01:21h, 10 March Reply

    I totally appreciate what you say about non-uniform scales. Presumably flipping objects will also act as non-uniform right? i.e. Scale: (-1, 1, 1)

    If that is the case, is there an efficient mechanism for having flipped versions of prefabs?

    • Derk
      Posted at 15:25h, 15 July Reply

      Depending on your needs, you could probably flip the object in your 3D editor (not Unity) and save it as a separate prefab (“ObjectX Mirrored”). An alternative is to rotate it 180 degrees, even though that’s technically not really flipping it.

  • 80sOGRE
    Posted at 04:30h, 01 June Reply

    thanks for the helpful advice. i was just wondering seeing as the default Unity scale of 0.01 is useless ( if you care to get close to work on your objects ) and scaling them up simply stops batching from working ( i scaled up in 3ds max and still they won’t batch and yes both batch options are ticked ) how do you fix this problem ?

  • Michal Kolasinski
    Posted at 09:03h, 29 June Reply

    We also found out, that unity3d skybox is using up to 6 drawcalls! This is guite a problem on devices having limits of max 30DCs!

    We solved this by implementing KGFSkyBox which reduces the drawcalls to 1 if you have terrain (Hides bottom sky hemisphere). If you do not use terrain KGFSkyBox will render using 2 drawcalls which is still better than 6!

    Check it out here:
    http://u3d.as/4Wg

    If you have any questions or suggestions just contact us here: support@kolmich.at

    Best wishes,

    Michal

  • neogene79
    Posted at 22:04h, 12 July Reply

    “Don’t use scale. Objects with scale (1,1,1) and (2,2,2) won’t batch.” And what scale is scaled?

    • Derk
      Posted at 15:27h, 15 July Reply

      As far as I understand, you need to keep all the object scales the same for batching to work.

  • Leonard
    Posted at 18:17h, 08 August Reply

    I want to be as good as you at using colours, looks just more than awesome

  • Leonard
    Posted at 18:48h, 08 August Reply

    Static batching saves me, I was using a lot of lights lightening up a tiny simple scene, but it just didn’t get me anywhere and runs painfully slow, thx for your useful tips~~

  • Reality is a Game » Blog Archive » Mobile Optimization Tips for Unity
    Posted at 20:56h, 15 August Reply

    […] Paladin Studios has a post on getting your Unity game ready for iOS and Android using four […]

  • Unity Learning Resources – Next Numen
    Posted at 22:39h, 29 October Reply

    […] Four Ways to Increase Performance of Your Unity Game @ Paladin Studios […]

  • Rothana
    Posted at 10:43h, 13 November Reply

    I am wondering, How could you setup the scenes(levels)? Did you model everything and combine them as a single object in 3d application then export or export them separately as individual objects from 3d application and then re organize them to create scenes in unity? and for facial animation are you using blending shape or bones ?

  • Mohamed Emam | Windows Game Development With Unity3D
    Posted at 20:11h, 28 May Reply

    […] 4 ways to improve performance by Yorick – http://www.paladinstudios.com/2012/07/30/4-ways-to-increase-performance-of-your-unity-game/ […]

  • Six weeks in the making (v0.0.3) … | Hristoz Stefanov
    Posted at 19:08h, 28 October Reply

    […] And one last point, I optimized the level rendering by combining all similar static meshes into a bigger one (kudos to Alex for this script). This in turn sped up the dynamic shadow rendering, which make the game look so much nicer, so shadows are now on by default. One other optimization I could do (later on, when the time comes) is to combine all textures into a single texture atlas and render all blocks with a single material as described here. […]

  • Jan Davidsson
    Posted at 17:13h, 04 December Reply

    Hi! Thank you for this post! It clarified and most importantly showed production tested ideas!
    I know it’s been a long time since this was documented but i figure you are even more experienced now!

    First: Have you noticed that there seems to be a hard limit in Dynamic Batching where if you have many groups of prefabs (that fulfill all DB rules) and when you reach a certain vertex count they no longer batch as 1 draw call and instead as 2 DC and then 3 and so on? For us its about 15-20k.

    Second: Do you know of a good way to remove UV vertex attribute data so that the the model can be 450 vertices with vertexcolor?

  • mnewps
    Posted at 00:24h, 10 December Reply

    I’m a bit confused by the uniform vs non-uniform scaling. Should I attempt to leave the scale in the transform alone (all 1,1,1) or is it better to have them all be something close, but not quite (1,1,1.1)?

  • Be The Better » So you want to be a Unity3D game developer?
    Posted at 06:26h, 17 December Reply

    […] 4 ways to improve performance by Yorick –http://www.paladinstudios.com/2012/07/30/4-ways-to-increase-performance-of-your-unity-game/ […]

  • Jelly Button Games Blog - Increasing Mobile Game Performance Through Vertex Color
    Posted at 16:48h, 03 September Reply

    […] Here are a few other resources we suggest: Andrew Maximov Site So You Like Them Shadows? A Game of Tricks II – Vertex Color AO Baking Tutorial 4 Ways To Increase Performance of Your Unity Game […]

  • David
    Posted at 01:42h, 09 November Reply

    Thanks for this article. It helps me a lot. One question. What is Native? There is no Native in Load Type in Unity 5.2.2. I wonder how to set audio clips to Native.

  • Unity: Documentação e Tutoriais |
    Posted at 19:20h, 09 March Reply

    […] 4 Ways To Increase Performance […]

  • Yanaka White
    Posted at 15:32h, 29 May Reply

    Thanks a bunch!
    Didnt know what that static checkbox does till now…
    Btw if i check it, will it still interactable?
    Example if i static objects called food… can it still be eaten? Read= destroyed in contact.

    Oh and my trick in increasing performance? Simply turn off all shadows…
    Yeah, i know… im a noob.

  • carlosed127
    Posted at 17:01h, 14 July Reply

    You = God. Thanks.

  • Erick Subero
    Posted at 17:27h, 14 July Reply

    Guys, you saved my ass. Thanks :v

  • 4 วิธีเพิ่ม Performance ให้โปรเจค Unity !! | Thai Unity3D
    Posted at 07:01h, 19 September Reply

    […] [คลิ๊ก !!] (ค้นหาคำว่า “Some useful tips from the Unity […]

Post A Comment