All things regarding... Game Optimization

Lets talk about game optimization methods here. Intermediate to advanced knowledge like this is hard to find in one location. So I thought I would attempt to gather most of the info in one place.

I have a few questions of my own, and (hopefully) as I get answers I will update this main post with all the info.

Draw calls

The holy grail of optimization. Its simple really, keep the amount of draw calls as low as possible. There are a few ways to do this.

This post on Unity Answers covers a lot of them. Thanks to Duck for the elaborate answer.

http://answers.unity3d.com/questions/7247/whats-the-best-way-to-reduce-draw-calls

Texture Atlases

This section needs to be expanded.

Combining Meshes

The other topic is Mesh Combining. There is a C# script in the Standard Assets folder for that, called CombineChildren.cs. If you have a lot of meshes that use the same material its a good idea to combine them into one, as this reduces the draw call to one (for those meshes).

Polygon Count

This section needs to be expanded.


Some questions I have:

Texture Atlases:
Can someone explain how this can be used with Unity? How does it support it?

Draw Calls:
In terms of CPU and GPU combinations, is there a way to calculate on paper whether the amount of draw calls are too much for the CPU and GPU?

Polygons:
What is the optimal triangle count for a mesh? Is there a point where extra triangles won’t necessarily have a performance cost. And then on the other hand, is there a point where its more efficient to split a mesh into two different ones?

would make more sense to direct the question and answer to answers.unity3d.com especially if you bring up quotes in relation to that.

the system over there is much stronger for answering “fixed questions” kind of :slight_smile:

Fixed it! :slight_smile:

The holy grail of optimization is profiling. I have said this many times and will probably say it many times again.

Mesh combining or reducing polygon count can both help to reduce rendering overhead (or make it worse, if you go about it wrong), but won’t help you anything at all if your game spends 99% of the time doing physics.

Find the most time consuming part of your game first, only then start looking into ways of improving that specific part. Only if profiling shows rendering to be your main bottleneck and your drawcall number is very high (where “high” is extremely platform dependent), reducing drawcalls may indeed be the way to go.

While not a huge issue on a desktop, on the iPhone you really want to reduce your update calls.

Instead of each object checking if it’s been clicked have a click manager. Use Delegates to make one input poll passing off to interested components through a custom event system. Use Coroutines to make short term update events (like MoveTo).

Update calls use Reflection and Reflection is extremely slow on older devices.

That said, always profile first. No point trying to fix issues that don’t exist, and needlessly making your code more confusing to create.

Good point! I was referring to optimizing the rendering pipeline itself, but I do want to discuss all kinds of optimization. Can you give a short description of working with profiling your game, and the steps you usually use?

Can you give examples of using Delegates and Coroutines in that manner? I will add a scripting practice section above.

actually not just update but all of the “SendMessage callbacks”.

having update / start / awake / onXXX in even if you don’t need it and just return is a horrible idea as one of their major hits happens when they are called. Unity does not call them through obj.Update() and alike but through something send message alike so for them to not eat performance at all, they must not be present

I can, but I will need to strip them of all but basic functionality

For Delegates, I created an Input Manager.

This manager takes what was originally about 50 objects all checking MouseButtonDown(0) with a single Update function call that passes out functions to objects that register.

This is an incredibly stripped down version

using UnityEngine;
using System.Collections;

public delegate void TouchEvent(Vector3 position);

public class InputManager : MonoBehaviour {

	public event TouchEvent OnTouchDown, OnTouchUp;
	
	int prevTouchCount = 0;

	private static InputManager instance;
	
    public static InputManager Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new GameObject ("InputManager").AddComponent(typeof(InputManager)) as InputManager;
			}

            return instance;
        }
    }

    void Update()
    {
		int touchCount = Input.touchCount;
		if(touchCount != prevTouchCount)
		{
			if(touchCount > prevTouchCount)
			{
				OnTouchDown(Input.mousePosition);
			}
			else if(touchCount < prevTouchCount)
			{
				OnTouchUp(Input.mousePosition);	
			}
		}	
		prevTouchCount = touchCount;
    }

}

and for event objects:

using UnityEngine;
using System.Collections;

public class Event: InputBehaviour {

	public static bool isPlaceable = false;
	
	void Start()
	{
		InputManager.Instance.OnTouchDown += OnPressed;
	}
	
	public override void OnPressed(Vector3 position)
	{
//Perform Events
	}
}

I have a singleton pattern for the InputManager and an abstract class and Interface for events, but it allows you to create an event system that reduces Update calls significantly on the iPhone. You register only for events you want to use, or use an array of delegates to create an order to your event operations. I found it sped up event handling significantly.

Note: The InputManager never has to be explicitly created. As soon as a single object attempts to register with it it will be created. That is what the Instance stuff is for. It only creates itself if it will be used.

Coroutines are more just understanding what exactly can be done with them. I have an easy example while also using the Event system.

using UnityEngine;
using System.Collections;
using System.IO;

public class BasicTest: MonoBehaviour, IInputBehaviour 
{

	bool isGrabbed;

	void Start () 
	{
		isGrabbed = false;

		InputManager.Instance.OnTouchDown += OnPressed;
		InputManager.Instance.OnTouchUp += OnReleased;
	}
	
	public void OnPressed(Vector3 position)
	{
		if(isGrabbed == false)
		{
			isGrabbed = true;
			
			StartCoroutine(Grabbed());
		}
	}
	
	public void OnReleased(Vector3 position)
	{
		if( isGrabbed == true)
		{
			isGrabbed = false;
		}
	}
	
	private IEnumerator Grabbed()
	{
		while(isGrabbed)
		{
			//Do Stuff
			yield return new WaitForFixedUpdate();	
		}	
	}
}

I register with the previous InputManager and while having no update loop, I can still maintain an action while the inputs are held down.

This creates a temporary Update cycle through coroutines that will only exist when necessary. It operates through a faster system than reflection and is therefore faster than an Update function.

You can add parameters and checks to when it is initiated, and the cycle gets maintained by a boolean.

You can optimize even further with events that are not very time dependent by using WaitForSeconds in this situation and therefore only updating every half or full second if necessary.

Note: These optimizations are probably not nearly as crucial on desktop builds, as they have much faster hardware, you could be better off optimizing somewhere else if coding in this sort of event logic would not be as fluid for you.

I usually open the profiler and check which color takes most space in the graph :P.

Without Unity Pro, profiling is nowhere near as easy. The only way to profile there, is to disable certain parts of your game you suspect are the problem (like all renderers, for instance) and measure the effect on performance. If this effect is significant, it makes sense to make improvements in that area, if not, continue looking.

Thanks for the replies!

Can anyone explain how texture atlases work with Unity? Especially regarding the setup of the mesh UVs.

Good post this. Thanks

Can anyone answer this?

Maybe a moderator can turn this into a sticky, since its a helpful collaboration of all the knowledge about game optimization, with everyone’s contribution.

here are a couple of BIG performance hogs thats i found that i didn’t expect to be any kind of problem:

“scrolling textures”

in most engines this is the cheapest of cheap fx that you could possibly do but if you are using that script that comes with the unity tutorials it will kill your frame rate even if it is assigned to as few as 5-20 objects ! this would be way fast if the scrolling was done within the shader !

“mesh colliders as children to animated objects”

even if they are not actually animated O_O if you are like my and you build your levels in maya and import it with this “generate colliders checkbox” you will get a root object in your scene that has an animation script attached but no actual animation in it. and than the actually level geometry below it with mesh colliders. the animation script on the root will be attached EVEN if you untick the importation of animations on the scene !!! (this is a bug all by it self as far as i am concerned !)
so yeah mesh colliders as children to object with animation nodes eats a ridicules amounts of framerate and this is kind of the default setup unty will do for your level so go make sure you get rid of those animation nodes !!

“scaling of bones”
its very expansive try to plan your models and anims in a way that doesn’t require you to scale any bones !

“rigid objects as children under animated bones”
skinned mesh renderer are expansive but what is even more expansive is dragging solid/static/rigid objects under them ! example: i have a palm-tree model in my game that i used to animated with 3 bones on the trunk nd 3 per leaf that totaled in 40 or so bones for the model and i wanted roughly 50 of those trees in my scene that was way too expansive so i made myself a benchmark scenes with 1000 trees and looked what performed best and its pretty linear as far as the amount of bones go less is better than more … duh. but as soon as i realized that i only really needed one bone to make the tree sway in the wind convincingly i found out that using a “soft skin” attachment with 1 bone influence was alot cheaper than just exporting model and bone separately and dragging the model under the bone in unity ! i did not see that coming !

results may differ from hardware to hardware and maybe even form game to game (asset to asset script to script) but this is what i found to be useful/helpful for my game !