/Blog: Maximizing the performance of your Unity game – Part 1

Blog: Maximizing the performance of your Unity game – Part 1


The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.


 

         

 

 

 

       


                                     

              Whenever we make games the main important part we miss is Optimizing the game. Resulting, getting lags, low FPS, and even in High-end devices in the worst case. Most of the people will always consider Optimizing the game as the last phase and that’s where the first mistake happens it should always be first in your list.

          Making sure on every build, every day when we add a new Mechanic or new lighting setup or any physics-based systems for your game its always a good habit of giving build just to check if any performance issues happened because of the new things we’ve added its a good way of developing games.

             In the last phase, it will be a problem for you and your game without spending time on any performance optimization from the beginning of the game. Here I want to share some thoughts and tips on how we can increase your game performance based on a few practical things that I learned through my mistakes over the past 5years.


                     

     First in the list and one of my favorite tools in Unity to monitor the game performance to know what is actually causing performance issues. This is a very useful one to get an in-depth look at how your game is performing in various changes in the Editor.                        

                                 You can find the Profiler under Window->Analysis->Profiler.

 It will display categories such as CPU usage, GPU usage, Rendering, Physics, Audio, and more. We cannot depend on the Editor Profiling as the editor affects the performance of the project while testing and the profiling information can be inaccurate sometimes. Its always good to give a separate build to get accurate profiling data.

     You need to Install Android SDK and JDK and USB debugging enabled to make it work. Always remember its always good to test how your game performing when it comes to mechanics, UI scaling, etc.. Not to check your actual real game performance with this. To check actual game performance you need to give a build for profiling.

      

       To enable Remote Profiler goto Edit > Project Settings > Editor and under Device choose Any Android Device.

       To make sure Unity has access to your build which can be profiled, you should turn on “Development build or Deep Profiling Support and “Auto-connect Profiler” in Build Settings before making a build. This allows the Unity Editor to connect your build automatically. 

           

Once your build is ready keep open Unity Profiler window and open your game. Now Unity will automatically show the current build game performance data in the Profiler Window.

   You can learn more about Profiler here.


                

            Batching is a very good method to improve performance by reducing Draw calls which are the game Objects rendering of similar objects into the same draw call instead of multiple. There are two types of Batching methods Static and Dynamic. There’s some limitation to the Batching which means we cannot batch skinned meshes, cloth, and some rendering components.

        Static batching is used whenever Game Objects set to static, these static game objects shouldn’t be moved, scaled, or rotate and also should use the same Material on all static game objects to make batching work.

       If your gameObjects doesnt interact with your Player or if you don’t change any Transform its always the best option to use Static Batching in most cases Environments in your game such as buildings, roads etc.

                                 

      Dynamic batching is similar to Static which uses the same Materials on game objects but can batch moving objects no need to flag static. Basically Unity can automatically batch GameObjects into the same draw call if they share same Material but they are some limitations to make Dynamic batching work as per Unity:

 

  1.   Batching dynamic GameObjects has certain overhead per vertex, so batching is applied only to Meshes containing no more than 900 vertex attributes, and no more than 300 vertices.
    • If your Shader
      is using Vertex Position, Normal and single UV, then you can batch up to 300 verts, while if your Shader is using Vertex Position, Normal, UV0, UV1 and Tangent, then only 180 verts.
    • : attribute count limit might be changed in future.
  2. GameObjects are not batched if they contain mirroring on the transform (for example GameObject A with +1 scale and GameObject B with –1 scale cannot be batched together).
  3. Using different Material instances causes GameObjects not to batch together, even if they are essentially the same. The exception is shadow caster rendering.
  4. GameObjects with lightmaps
    have additional renderer parameters: lightmap index and offset/scale into the lightmap. Generally, dynamic lightmapped GameObjects should point to exactly the same lightmap location to be batched.
  5. Multi-pass Shaders break batching.
    • Almost all Unity Shaders support several Lights in forward rendering
      , effectively doing additional passes for them. The draw calls for “additional per-pixel lights” are not batched.
    • The Legacy Deferred (light pre-pass) rendering path
      has dynamic batching disabled, because it has to draw GameObjects twice.

    For Particle Systems, Line Renderers, Trails Renderers Dynamic batching works differently compared to how it work for Meshes.

 

  1.   For each compatible renderer type, Unity builds all batchable content into 1 large Vertex Buffer.
  2. The renderer sets up the Material state for the batch.
  3. Unity binds the Vertex Buffer to the Graphics Device.
  4. For each Renderer in the batch, Unity updates the offset into the Vertex Buffer and then submits a new draw call.

 

 There are other ways to improve batching using some Assetstore assets like Simple Mesh Combine, Bakery or we can also use Mesh.CombineMeshes combine several meshes into one mesh which is perfect for performance optimization.


                      

Basically there are three modes Realtime Lighting and Baked Lighting and Mixed Lighting.

Realtime is the best BUT in return, there will be a performance cost. It contributes direct light to the scene and updates every frame when lights and GameObjects are moved within the scene lighting will be updated immediately.

Whenever you have the possibility of baking your lights in the scene simply go for it because it’s perfect for improving performance, especially if you are targeting mobile devices.it’s always good to use minimal lights in the scene to achieve your desired look.

So all your Lights will be precomputed offline in a process called Lightmap Baking. When you make your GameObject Lightmap Static Flag, Unity will bake the Gameobject Light, shadows, and bounced light and soft shadows data information in textures that can enlighten your scene.However Lightmaps have some limitations, lighting cannot be updated dynamically for the objects you chose Lightmap Static Flag.

I made a SCIFI scene in my spare time a few months back and I guess this is the best example to show how Baked lighting works of course I used Emission.

If anyone interested in the breakdown of the SCIFI scene how I achieved this look let me know, maybe I could make a separate article.

Here’s the video in case you are interested!


                            

This is very good way to increase your game performance by using Unity’s Occlusion. So, basically Occlusion culling means Unity will not render GameObjects that are completely hidden from the Camera point of view (occluded) by other GameObjects.

To open Occlusion Window goto->Window->Rendering->Occlusion Culling

If anyone interested in the breakdown of the Mystery Forest scene how I achieved this look let me know, maybe I could make a separate article.

Here’s the video in case you are interested!

 

By default, Unity will apply Frustum Culling, which means it only Renders camera line of sight showing all game objects. For instance, if the Camera is looking at a wall and all Gameobjects behind that wall will also be rendered. We don’t want that at all, so that why its good to add Occlusion culling in our scene.

          

This is why we have to use Occlusion Culling, which means the camera will only render the wall and not the Gameobjects behind the wall.

 


      I’m a Game Designer and Co-Founder of Street Lamp Games. I’m obsessed over making Prototypes, breakdown core design values, new design techniques, and dedicate an insanely amount of time to create an amazing player experience. And also sometimes I create speed level designs in my spare time.

You can find me on Twitter and LinkedIn