Unity iPhone Game Development tricks

Optimizing factors:


·    Combining textures into atlases and combining meshes is always a good idea. For each separate mesh or mesh subset you pay not only the cost of OpenGLES render-call, but also Unity has to do work processing shader/material settings. This is a global way of rendering.

·    Use as less different textures (combining them into atlas is the way,
·    however you should be careful about PVRTC compression artifacts).

·    Use less different materials (same shader with different parameters is counted as different material) as possible.

·    Even if you can’t combine meshes, it will not increase performance for you today, but will open door for future optimizations.

·    If you have lots of very small dynamic objects, you could try combining them into skinned mesh and animating bones.

·    Be aware in Time scale and Time fixed setting in your project

·    Reasonable with 2-3 characters simultaneously on screen

·    The stats button in the game window in Unity is your friend. Watch there the draw calls. I found those as most limiting parameter for iPhone rendering.

·    Even GUI stuff uses draw calls. Check if you can combine rendering of gui elements to save draw calls.

·    Use the diffuse fast shader, not diffuse or vertex. Speeds up a lot! As test, enable the stats window, look at the draw calls. Now have your test model once use the diffuse shader and once the diffuse fast shader and watch the difference in draw calls.

·    The rigidbody should be fixed in the rotation axis. This is a checkbox you can activate in a rigidbody. Of course does not work for every kind of model, but for less important object we can use it.

·    Removed the background (Sky box) and used a solid color for clearing the background. Reduces the draw calls from 6 to 1 if you used before a skybox.

·    Try to increase the physics timing as much as possible. It’s depending on the project. Greatly affects frame rate.

·    Also watch the texture import settings of EVERY texture. Check if you can live with 2bits compression and only RGB instead of RGBA.

·    Force audio files to be mono. Might save lots of memory.

·    Having lots of audio sources in the game costs performance, at least my experience.

·    Carefully think of your menus if they use lots of images. If they are in the same scene as your game, those images eat a lot of the very tiny ram of the iPhone. Might make sense to put the menu into a separate scene file, otherwise it could happen people complain your game quits unexpectly on their phones (often because of too less free memory available).

·    Try putting on group GO’s the “Mesh Combine Children” script. Had great success with that!

·    Do not use alpha testing on iPhone if you can. Alpha test is way much more expensive than alpha blending on iPhone (contrary to PC/Mac).

·    If you go above about 25-30 draw calls per frame, you will cross the 30fps threshold and it will drop to about 15fps immediately.

·    Each material on each mesh causes one draw-call per frame, per light that affects it and per camera that sees it.

·    If I have 1 mesh with 20 seperate textures, only ambient light, one camera, this will also result in 20 draw-calls. If I would combine the 20 textures into one atlas the scene would now only need a single draw-call.

·    If I have 20 meshes with one texture each, only ambient light, one camera, this will result in 20 draw-calls. If I would combine all the textures into one big atlas, the scene would still require 20 draw-calls, even though all the objects would now use the same texture.

·    The only way to optimize here would be to combine meshes. But you can only do that if your meshes aren’t to move around independently from each other.

·    mesh_draw_calls = visible_meshes * mesh_subsets * number_of_passes_per_material;

·    If you have skybox (+6), gui, particles, trails, projectors etc.

·    Using compressed textures is very important in order to save on memory bandwidth, not that much of just saving memory.

·    PVRTC compression allows to use 8 or 16 times less bandwidth and provides better GPU texture cache utilization. Note that memory between CPU and GPU is shared on iPhone making bandwidth ever more important. For example rendering full-screen quad with 2 512×512 textures takes ~20ms without compression and ~12ms, if textures are PVRTC4bpp compressed. Roughly twice as fast.

·    PVRTC it is for the game, uncompressed for the GUI, 20MB total texture, 60MB for the game, build compressed 1024 atlas’ to blanket the level with breakpoints that balance texture quality with draw calls.

·    You can define OnApplicationQuit() function to handle application termination. However it will work only since 1.0.1 (hotfix) release. Same for PlayerPrefs.

·    GUI.Buttons and GUI.xxx stuff is much heavier than GUITexture. Parts of GUI.xxx are written in C# and rendering is much more complicated due to custom skins. Just use GUITexture in game.

·    There is a bug in OpenAL implementation on iPhone Audio. So, don’t panic about more than 2 sounds at a time. iPhone Unity 1.0.1 will include workaround for it.


·    If you use JS, typing your variables is a must. Had some variables untyped which Unity did not complain about and those in an Update cycle were heavy fps cost. So watch our _every_ variable you use if it is typed or not.

·    Use #pragma strict in every JS script in the first line.

·    Put in every script that uses GUI stuff in the Awake() function this line: useGUILayout = false;

·    Try to avoid lookups like GameObject.Find(“Some GO”); If you can’t avoid, do them one time in the Start() function, but not in update/fixedUpdate. Try to put in your script a variable to your objects you want to reference and assign them via the Unity editor. The best reference is the one statically linked!

·    Don’t do anywhere string comparisons inside Update or FixedUpdates. Ultra expensive. Use integers for comparisons.

·    Don’t use tags on gameObjects to compare something, same as above. Expensive!

·    Try to find out if stuff in your Update/FixedUpdate _really_ needs to be calculated every frame. Use integer counters in Update and do some calculations only every n’th frame.



Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s