Hey, I apologize if this is a repeat question, but I tried searching and did not find too much that helped me. I've finally hit a point in my game where the frame rate is taking some considerable dives and it's starting to compromise the playability of the game... I'm relatively new to unity and game developement, so I know I've probably cut far too many corners and been lazy with my scripting, but the problem is I don't really know what kinds of things I need to be worried about that will significantly drop the frame rate. So that's my question, what are some of the basics that will drop the frame rate and game performance and how can I fix these?
It is likely not your scripts unless they are truly horrendous. In most cases, it's something you're rendering that causes framerate to drop.
These are general practices of optimization and are also just good ideas in general:
- Recycle. In certain situations, if some small changes will make one GameObject or data structure work in the place of another, it might be better to re-purpose it rather than having a separate one for that purpose.
- Reduce. Don't waste resources on stuff you don't need. Extra function calls, expensive functions, raycasting against layers you don't care about, every object having colliders and rigidbodies, storing and using expensive and large data structures when cheaper ones will do, can all be cleaned up. Try for fewer, less-complex models, simpler shaders and smarter scripts with fewer and cheaper function calls. Set static GameObjects as static. Bake your lighting. Tune your quality and camera clipping settings. Lower texture quality settings. You might try setting up some occlusion culling.
- Re-use. Use the same variables and assets whenever possible. Share materials, share textures, share shaders, use the same prefabs, combine GameObjects, re-use variables by declaring them in a higher scope so you aren't always re-creating them and re-use the variables where applicable. Re-use functions and scripts.
As far as rendering is concerned, the idea is to reduce draw calls. There's a trade-off between fewer more complex, combined models which share fewer textures and more, less complex models (under 300 triangles I think) which share materials, but generally you want to combine the GameObjects into as few as you need and share materials as each separate material generates a separate draw call. Use fewer lights as those generate draw calls, which is why baking your lighting is a wonderful idea because those at least reduce or remove the overhead of calculating the lighting at run-time if you set your baked objects to be ignored by your dynamic lights. There are Unite presentations and docs on this.
As far as code is concerned, there are whole books on optimization techniques and the length of a complete response would be too lengthy and in-depth for most to even spend the time reading it. The simple answer is to really understand what your code is doing and rewrite it so that it does it more efficiently and less often. Combine your logical comparisons, loop jamming and loop unrolling are some techniques that you could consider applying, but if the compiler is smarter enough, it may well do some of this for you. Using less-complicated data structures and functions whenever you can is also a good idea. Cache results rather than recalculating them when applicable (rather than calling transform.forward 5 times in the same block of code, store it and use the stored value). Fewer, less-complicated ray-casts are also a good idea. If you need to take it to extremes, you could even re-implement Unity's built-in functions like those in Mathf and the like, as they are apparently quite inefficient it would seem. Dynamic typing is costly so specify your types.
If you own a pro license, use the profiler. It will quickly point out the bottlenecks of your application so you don't have to shoot in the dark for the problem.
Otherwise, as a rule of thumb:
Graphics:
- try to render as few different objects as possible
- try to have as few materials on them as possible
- rendertargets are memory expensive
- unless you use deferred rendering, many lights (like, more than one) are very expensive
Physics:
- try to have as few objects moving at once as possible. Sleeping objects are much cheaper
- raycasts are very expensive. Never raycast every frame - try to cache results and skip some frames
- try to avoid complicated mesh colliders
Programming:
- check your Update() functions. They run every frame and are thus expensive. Use Coroutines where possible instead.
- avoid declaring useless Update() functions (e.g. empty ones).
- FindObject/s and GetComponent/s are expensive.
- if you use C#, use the generic version of GetComponent: `GetComponent();`
- Using the "transform" "renderer" etc. shortcuts implicitly calls GetComponent. Avoid using those more than necessary:
e.g. instead of:
function Update()
{
transform.position = Input.mousePosition;
}
do
var _transform : Transform;
function Awake()
{
// cache transform
_transform = transform;
}
function Update()
{
_transform.position = Input.mousePosition;
}
This will save you heaps of processing time if you do it for all your objects.
If you are using UnityGUI for your gui elements (labels, button, etc.) then there's a lot you can do just with that, especially for mobile device development. It's currently a draw call hog, and the setup for OnGUI (stuff which runs before your code is even called!) is significant. I blogged about that in detail.
Replacing UnityGUI with something like EZGUI will reduce the number of draw calls. Unity Tech has said that they may improve the built-in GUI options some time during the Unity 3.x product cycle, but that hasn't happened yet.
Other ideas include simply reducing the number of elements shown during gameplay, by combining them into single elements (a panel of buttons could be one button that figures out where the click was) or hiding them until the player needs them.
I was having trouble getting my Android game to run at more than 5 FPS (!!), and I noticed that in this video he casually mentions something about JS slowing things down a little if it wasn’t using strict typing. I don’t know much about strict typing in JS, but I do know C# (which is always strict), so I converted all of my scripts to C# to see if that would help at all, and the difference was HUGE! Here are my before and after profiler outputs, with NO other optimizations made besides switching scripts from JS to C# (and fixing the 100+ errors that came up when I made that switch):
before switch to C#:
V/Unity ( 6257): Android Unity internal profiler stats:
V/Unity ( 6257): cpu-player> min: 212.3 max: 1719.1 avg: 623.4
V/Unity ( 6257): cpu-ogles-drv> min: 1.2 max: 4.3 avg: 1.8
V/Unity ( 6257): cpu-present> min: 1.6 max: 4.1 avg: 2.4
V/Unity ( 6257): frametime> min: 215.7 max: 1723.1 avg: 627.7
V/Unity ( 6257): draw-call #> min: 5 max: 5 avg: 5 | batched: 51
V/Unity ( 6257): tris #> min: 188 max: 234 avg: 216 | batched: 103
V/Unity ( 6257): verts #> min: 436 max: 528 avg: 493 | batched: 207
V/Unity ( 6257): player-detail> physx: 1.1 animation: 0.0 culling 0.0 skinning: 0.0
batching: 0.3 render: 18446744027136.0 fixed-update-count: 10 .. 17
V/Unity ( 6257): mono-scripts> update: 531.3 fixedUpdate: 0.0 coroutines: 0.0
V/Unity ( 6257): mono-memory> used heap: 892928 allocated heap: 1150976
max number of collections: 400 collection total duration: 3190.8
V/Unity ( 6257): ----------------------------------------
after switch to C#:
V/Unity (13591): Android Unity internal profiler stats:
V/Unity (13591): cpu-player> min: 34.6 max: 92.9 avg: 64.1
V/Unity (13591): cpu-ogles-drv> min: 1.2 max: 3.5 avg: 1.5
V/Unity (13591): cpu-present> min: 1.3 max: 3.6 avg: 2.1
V/Unity (13591): frametime> min: 37.2 max: 97.2 avg: 67.8
V/Unity (13591): draw-call #> min: 5 max: 5 avg: 5 | batched: 56
V/Unity (13591): tris #> min: 234 max: 234 avg: 234 | batched: 112
V/Unity (13591): verts #> min: 528 max: 528 avg: 528 | batched: 224
V/Unity (13591): player-detail> physx: 0.3 animation: 0.0 culling 0.0 skinning: 0.0
batching: 0.2 render: 49.0 fixed-update-count: 2 .. 5
V/Unity (13591): mono-scripts> update: 14.2 fixedUpdate: 0.0 coroutines:0.0
V/Unity (13591): mono-memory> used heap: 569344 allocated heap: 643072
max number of collections: 0 collection total duration: 0.0
V/Unity (13591): ----------------------------------------
Of course it still needs a lot more optimization, but as you can see that switch gave me a 10x increase in CPU performance and framerate, and I’ll be doing ALL of my Unity scripting in C# from now on.
well for all that i know using static objects and light mapping combined with # program strict reduced my draw calls from 110 to just 12…the point is if u follow the simple rules and do smart coding 30fps will be awarded…sure light mapping takes ages ,sure not using dynamic typing is pain,and sure compressing every texture is time taking etc etc…but in the end u get something beautiful out of it…
well for all that i know using static objects and light mapping combined with # program strict reduced my draw calls from 110 to just 12…the point is if u follow the simple rules and do smart coding 30fps will be awarded…sure light mapping takes ages ,sure not using dynamic typing is pain,and sure compressing every texture is time taking etc etc…but in the end u get something beautiful out of it…
As others have said make sure to use #pragma strict at the top of your javascript code. Also I had a bunch of framerate hiccups that I found to be associated with my heavy use of iTween, once I moved to a more lightweight tweening engine (LeanTween) I was able to get a more steady frame rate.
Also you could be spending too much time calculating the physics for your scene. Try turning down the “Solver Iteration Count” in Project Settings->Physics to something lower and see if it affects the behavior of your game at all.
Lastly, if you don’t have the money to upgrade to Unity Pro, you can get some of the same stats from FPS Graph.