“Premature optimization is the root of all evil.”
― Donald Ervin Knuth, Art of Computer Programming, Volume 1: Fundamental Algorithms
Optimization is a term which is familiar to any developer. Game developers are more aware of this because of three reasons,
- They realize the importance only at the fag end of game development.
- They see this as a game-specific term.
- They think that this only applies to mobile devices.
Optimization should be considered even before starting the game. In fact even before choosing your assets more importantly 3D Meshes. Let me provide you some important tips which I collated after reading some books, web links and going through videos.
Tip # 1:
Minimize Vertex Count
The unity renderer has lots of techniques and optimizations built in to draw meshes quickly and efficiently across different devices, but you can really help that renderer do its work even more efficiently if you reduce the vertices in your meshes so far as possible. Note that the
Stats panel displays the number of triangles and vertices currently being rendered—and not the total number of vertices and triangles actually in the scene, which will often be more because the camera usually does not see the entire scene at once.
Tip #2
Minimize Materials
Unity allows you to create as many materials as you need for your meshes and objects and you can even assign multiple materials to the same mesh. Using materials comes at a performance cost, however, in terms of draw calls and draw calls are relatively expensive on any platform. Try to avoid using multiple textures for a single mesh; instead, share the same image for all parts. Using Atlas Textures for 2D games, Objects could share the same texture and material. Sharing materials in this way between objects allows the Unity renderer to internally batch those objects into the same draw call, and this typically improves on performance than if those objects had been drawn in separate calls. Refer Texture2D.PackTextures.
Tip #3
Use Per-Platform Texture Settings
If you select a texture in the Unity Project Panel and examine its settings in the Object Inspector, you’ll see its options regarding size and compression are customizable on a per-platform basis. This means you can adjust the size and compression of textures differently for each target platform: Windows, Mac, Android, iOS, and so on. The trick is to try and build your game so that optimization is possible without being too noticeable, using tricks such as reducing the amount of alpha transparency in textures so that you can use a nonalpha compression system, system, or using texture atlases to put everything onto a single texture rather than several separate ones.
Scripting Optimization:
Tip # 4 -Cache Components and Objects
One of the most common C# scripted statements when working with the Unity API, is
- transform,or just transform. This statement (and others like it, such as audio) accesses a C#property, which returns a reference to the transform component of an object. From this, you can directly set the GameObject’s position, orientation, and scale. However, accessing the transform component in this way indirectly calls on additional functionality that can have an accumulative impact on performance, if called enough times in events, such as Update or OnGUI. You can optimize such expressions from the outset, however, by using Object Caching. That is, by getting a reference to the component or object, and by storing it in a local variable. An example of object caching at work.
[code language="csharp"]
void Awake()
{
//Cache Transform (MyTransform is a class variable)
MyTransform = transform;
}
void Update(){
//Update position using cached transform
MyTransform.localPosition = MyPosition;
}
[/code]
Tip # 5 : Avoid Using Update
This is not a good idea since Unity has to invoke the update function and you are performing work every frame. A better solution is to disabling the behaviour until the player comes closer. There are 3 ways to do this:
- Use OnBecameVisibleand OnBecameInvisible. These call backs are tied into the rendering system. As soon as any camera can see the object, OnBecameVisiblewill be called, when no camera sees it anymore OnBecameInvisible will be called. This is useful in some cases, but often for AI it is not useful because enemies would become disabled as soon as you turn the camera away from them.
[code language="csharp"]
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
void OnBecameVisible() {
enabled = true;
}
void OnBecameInvisible() {
enabled = false;
}
}
[/code]
- Use triggers. A simple sphere trigger can work wonders though. You get OnTriggerEnter/Exit calls when exiting the sphere of influence you want
[code language="csharp"]
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
void OnTriggerEnter(Collider c) {
if (c.CompareTag("Player"))
enabled = true;
}
void OnTriggerExit(Collider c) {
if (c.CompareTag("Player"))
enabled = false;
}
}
[/code]
- Use Coroutines. The problem with Update calls is that they happenevery frame. Quite possibly checking the distance to the player could be performed only every 5 seconds. This would save a lot of processing power.
Tip #6—Avoid OnGUI and the GUI class
The OnGUI function and the GUI class can be two of the biggest drains on performance, especially for mobile games. OnGUI is expensive primarily because it’s called multiple times per frame. This means you almost never use it to perform game-logic or core functionality—the purpose of OnGUI is exclusively for drawing GUI elements. The GUI class can work well for smaller and simpler interfaces, but should really be avoided for complex interfaces with many interactive elements, such as inventories, statistic panels, mini-maps, option screens, and type-in dialogs. I’ve almost never seen high-performance come from the default GUI class when implementing more feature-filled GUIs. To implement these, Unity offers very little native support. There are two main and popular solutions to this: either a custom solution is developed, using Atlas Textures and, or a third-party add-on must be purchased, such as NGUI or EZGUI.
Tip #7—Use Object Pooling
Imagine this: the player character is firing a fast-reload weapon (such as a chain gun) and each shot spawns a new bullet into the level. The fire-rate for this weapon means that two bullets are generated per second. Assuming the bullet object is created in the project as a prefab, how should the bullet generation be scripted? One way to handle this is to call the Instantiate function for each bullet, whenever the gun is being fired. This method might be called “Dynamic Object Creation.” However, there’s another method: at level start-up you could generate a large batch of bullets (perhaps 30), and store them off-screen. Then, whenever the player fires a weapon, you would continually show, hide, and move these pregenerated bullets, as required, to simulate bullets being spawned, as opposed to really spawning them. This latter method is known as Object Pooling. In general, Object Pooling is to be preferred over Dynamic Object Creation because it avoids the performance issues that sometimes comes from dynamic memory allocation, especially on mobile operating systems. The upshot of this is: avoid instantiating and destroying objects dynamically. Instead: generate objects at level start-up, and then show and hide as required to simulate object destruction and creation.
Profiler (Pro only)
What Is the Profiler?
The profiler is an advanced tool for finding out all kinds of important information about your system resources during playback. It can be used to profile CPU, rendering.memory, audio, and physics so that you can find ways to optimize toward a better-performing game.
Simple Checklist to make Your Game Faster
- Use skyboxes to “fake” distant geometry.
- Learn benefits of Occlusion Culling and use it to reduce amount of visible geometry and draw-calls in case of complex static scenes with lots of occlusion. Plan your levels to benefit from ccclusion culling.
- Do not use fog when it is not necessary.
- Use compressed texture formats when possible, otherwise prefer 16bit textures over 32bit.
- Do not use dynamic lights when it is not necessary - choose to bake lighting instead.
- Do not use Pixel Lights when it is not necessary - choose to have only a single (preferably directional) pixel light affecting your geometry.
- Set Static property on a non-moving objects to allow internal optimizations like static batching.
- Keep the number of different materials per scene low - share as many materials between different objects as possible.
- If you’re using built-in shaders, pick ones from Mobile or Unlit category. They work on non-mobile platforms as well; but are simplified and approximated versions of the more complex shaders.
- Keep vertex count below 200K..3M per frame when targetting PCs, depending on the target GPU
- Use pixel shaders or texture combiners to mix several textures instead of a multi-pass approach.
- If writing custom shaders, always use smallest possible floating point format:
- fixed / lowp - for colors, lighting information and normals,
- half / mediump - for texture UV coordinates,
- float / highp - avoid in pixel shaders, fine to use in vertex shader for position calculations.
- Minimize use of complex mathematical operations such as pow, sin, cos etc. in pixel shaders.
- Choose to use less textures per fragment.
Courtesy : Unity3D
As I knew, unity is used to develop 3D games. Does it has other usage?
ReplyDeleteWith unity version 4.3, they are into 2D development too.
ReplyDelete[…] Optimization is the process of reducing memory usage of your assets. For example, models are optimized by reducing their polycount without drastically affecting its silhouette. […]
ReplyDelete