As part of the on going Unity 3D introduction articles FARM FIGHTERS programmer, Barnaby Smith talks about the Unity3D software used to create the game. This week Barnaby delves into performance tips for Unity on iOS. If you’re thinking about a career in video game development, this series of articles will serve as an insightful introduction to the Unity engine, which is a useful learning tool as well as a great platform for creating games for a variety of devices.

Kwalee use a mixture of technologies to create games for mobile, one of which is Unity3D. Unity is a game creation tool and game engine used for rapidly developing games for a range of platforms, such as iOS, Android, Web, PC, Mac and console.Object Movement

All objects that never move should be marked as static, this allows Unity to perform a number of optimisations since it’s now been told these objects cannot move.

All objects that move must have a rigid body. For an object that is moved by a script and should not have physics calculations, check it as a kinematic object. If an object does not have a rigid body it is assumed as part of the static collision mesh (which underneath PhysX generates and optimises). So moving an object without a rigid body forces Unity to recalculate the static geometry for the level, per frame if the object is moved every frame.

Materials

All materials should be using shaders designed for mobile. Mobile shaders are optimised for the architecture and sacrifice functionality or precision for efficiency and performance.

On mobile it’s also very important to keep draw calls and texture swapping to a minimum. A great way to achieve this is to use as few materials as possible. By combining textures onto a texture atlas, the same material and texture can be shared by many models. Also, making sure you use texture space optimally can help you get as many textures as possible onto the same atlas.

Remember to take into account how much detail a particular texture really needs. For example if it’s a building in the distance you can never reach you can make the texture relatively small in the atlas. Using a sharpen filter on textures can also help counteract downsizing.

Pre-Calculate

Being smart about what you calculate and when can be very important to achieving high performance and making certain effects possible. For example if you use displacement mapping (which on iOS 5/6 necessitates a CPU based approach, since Apple has disabled support for vertex texture fetch) then rather than regenerate the entire mesh per frame, pre-calculate as much as you can (such as the vertex array, uvs, indices), then just calculate the vertex positions and set them on the mesh per frame.

Taking the approach of calculating as much as possible at the start of execution (or offline into data files or prefabs at development time) can have a great impact on performance and this is what makes techniques like light maps, occlusion culling and normal mapping (over heightmap bump mapping) so attractive.

Script Call Optimization

In player settings Script Call Optimization should always be set to Fast but no exceptions. Unhandled exceptions will now crash Unity builds, however you gain a lot of performance here for games with a lot of scripts – the performance boost at the start may not be significant, but by the end of the project it makes a big impact.

Light Maps

By using light maps for static geometry, dynamic light calculations can be kept just for dynamic objects. It may be worth looking into using light probes for dynamic objects, this is how some great looking Unity iOS shooters achieve very good-looking lighting on characters and dynamic objects.

Occlusion Culling

Use the occlusion culling to bake the occlusion for the level, this bakes data based on static geometry so that at run time the visibility of objects can be determined and allows objects that would be hidden by overdraw to not be drawn.

Level of Details (LOD)

Use LODs to achieve different levels of detail for different devices and for different distances. An object that is far as way doesn’t need the same level of detail as an object that’s close to the camera.

Component Caching

Caching component references rather than using the built in shortcuts (http://docs.unity3d.com/Documentation/ScriptReference/Component.html – rather than using the “variables” listed there, with the exception of tag, make sure to cache them.) The term “variables” is a misnomer in the documentation, they are actually properties and execute GetComponent<TYPE_HERE>() which is not a very fast function. Every time GetComponent is called it uses reflection (or some custom mapping equivalent) on every attached component until it finds one that matches.

It’s better to do something like this:

Transform transform;
void Start()
{
transform = base.transform;
}

In the above code, the transform is cached in a field with the same name. By using the exact same name, the cached variable always takes precedence. So you can’t accidentally cache the reference and use the lookup.

Full Screen Alpha

On iPhone 4 and iPad 1, alpha is in general a massive issue, both for full screen alpha and for alpha overdraw. For particle systems, where possible it’s better to use sprite animations generated with a tool like TimelineFX (http://www.rigzsoft.co.uk/) and for smoke it’s often possible to get a nice effect using UV scrolling.

Accelerometer

If your game doesn’t use the accelerometer, Unity by default still polls that data at 60 hz, this can be disabled in Player Settings. You can also adjust the accelerometer poll rate to a rate that most suits your game.

Target Platform

In Player Settings (Unity 3.x only, Unity 4 has dropped support for Arm6) – target platform should be set to Arm7 (this will reduce the file size by excluding devices the two first generation iPhones that aren’t targeted).