Search Unity

  1. Are you interested in providing feedback directly to Unity teams? Sign up to become a member of Unity Pulse, our new product feedback and research community.
    Dismiss Notice

Looking for some general performance optimization tips

Discussion in 'General Graphics' started by startas, Dec 21, 2014.

  1. startas

    startas

    Joined:
    Nov 14, 2014
    Posts:
    102
    So, i'm doing a little game for my own needs, and i would like to get some cpu and gpu optimization tips. Yes, i know that there are some tips in unity docs, but i would like to know more things, i.e., i know, that in coding, in update functions it is bad to use GameObject.Find(...), because it uses a lot of cpu. Maybe you know more things, like :
    1) one method to create something (maybe particle effects, shadows, lights, to not draw objects, that you cant see) is faster and better than another;
    2) creating a simple field - is it good to use unity plane object ? Then making it bigger - maybe use scale with texture tiling ? or create many planes without texture tiling ?
    3) using prefabs, lightmaps, other things;
    4) maybe some settings shouldn't be high because of very little to no impact for graphics quality, but visible hit in performance ?
    5) multithreading in short code (right now there is 5 scripts from 30 to 150 lines) - any difference ?
    6) javascript or c# ? Any big performance difference ? Maybe it is useful to use both, like one does some functions faster, and another does some other functions faster ?
    7) the whole world scale - as i am using free models from the internet, to match things, should i scale small objects to make them bigger or scale down bigger objects ?

    And other general game developing techniques. Links to tips and tips are appreciated.

    I'm targeting game to run at 60 fps on my own laptop with i7 + geforce 840m (win 8.1). Right now it runs about at 30-50 fps with some bigger drops (of course - max shadows quality, ssao, DepthOfField, 100% quality on very far objects) :)
     
    Last edited: Dec 21, 2014
  2. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    The only real way to optimise your game is to profile it. Then you will know what are the bits that will have the most performance improvement for you. I mean, creating a quad is always better than creating a plane, but will it really make a noticeable difference to your framerate if you go through your code and painstakingly replace all your planes with quads? I doubt it.

    There is also always a trade-off between performance and other factors - perhaps quality, manageability, or code readability. You could always go for the "best performing" method but, in doing so, you'd probably be sacrificing something else. If there was a method of doing something that was always "faster and better" than another, then the second method simply wouldn't exist.
     
  3. startas

    startas

    Joined:
    Nov 14, 2014
    Posts:
    102
    Yes, i know that there isn't just one best way to do one thing, but i'm just a beginner in unity, and i'm looking for some real life development tips, good practices, and good real life examples of doing one or another thing.
    i.e., i made a simple bush model from 6 planes (30 degrees between each), added a texture to a plane material, added 280 bushes to the scene, and got 10 fps hit :D
     
    Last edited: Dec 21, 2014
  4. phil_lira

    phil_lira

    Unity Technologies

    Joined:
    Dec 17, 2014
    Posts:
    552
    Hi startas,

    I'll try to give some tips off of top of my head, but let me reassure first what @tanoshimi said.

    Profiling is the way to go when optimizing. What you do as developer is to create assumptions on what might run fast and slow on your target platform, but what can really tell you what's going on it's the profiler.

    So, my advice is get to know some common ground in optimization (and you're at the right track here) and when you are about to optimize your game don't assume nothing, profile first. You won't believe how many times I've seen developers spending hours and hours optimizing code that didn't make any difference because that piece o code was not the bottleneck.

    Bottleneck is a really important word here. The bottleneck is the stage in your pipeline that is taking the most time. If you are optimizing something that's not your bottleneck you are wasting time. So, the profiler will help you find that bottleneck for your.

    Also knowing the bottleneck will help answer your questions because without knowing it the answer might be "depends".
    Like your 2) question, is it better to use more detailed geometry or texture tiling. It depends, on your bottleneck, on your lighting model, etc.

    I'll spit this into tree main logical groups and provide you general tips on how to approach them.
    Development wise you can be:
    CPU bound, GPU Vertex Bound or GPU Fragment Bound.

    Really quick way to find which one you are (you should do this on your target device):

    If Main Thread/CPU usage is taking more time thatn Rendering Thread/GPU usage you are CPU Bound.
    If you are GPU bound, render your game in a really small viewport (300px wide for instance). If the fps doesn't change you are GPU Vertex Bound. If the FPS increases you a GPU Fragment Bound.

    CPU Bound tips:
    • Prefer C# as it has more support to it. I don't think it will make much difference performance wise.
    • Only declare Update(), LateUpdate() and FixedUpdate() on the scripts you really need. The more scripts with those methods the more cpu intensive your game's gonna be.
    • Avoid Instancing things during gameplay. You should create all the resources you need prior to game start. For assets that need to be spawned (like bullets) create object pools https://unity3d.com/pt/learn/tutorials/modules/beginner/live-training-archive/object-pooling
    • Skinned meshes are by default animated/blended in CPU. You can make do GPU skinning by enabling it in Player Settings -> Other Settings - > GPU Skinning. Two things to keep in mind when using skinned meshes: Quality Settings -> Blend Weights. This is how many bones influence a vertex when skinning. Try to keep it max 2. And of course the number of bones your skinned mesh has.
    • The same way particle effects animations are done in CPU. Keep it to reasonable levels.
    • Dynamic Batching. When this is enabled (Player Settings -> Other Settings) Unity will try to batch all object not marked as static in execution time. This helps offload some gpu work by decreasing the number of draw calls. Again, if you are not GPU bound you should afford this. Keep in mind that for unity to batch it need to have the same material for different meshes.
    • Physics and Collision. I don't know much about Physics, but for the world mesh collision you should use a much lesser low poly than the rendering mesh. Take a look at nav mesh: http://docs.unity3d.com/Manual/Navmeshes.html
    • Unity does Frustum Culling (culling triangles that are outside camera frustum). So, the more triangles you have the more this should take to compute.
    GPU Vertex Bound:
    • Batching, Batching Batching. Issuing a draw call with 1.000 triangle is MUCH faster than 10 drawcalls of 100 tris. Unity try to batch as much as possible for you. What you can do to help is mark all static geometry in your scene as static. This is done by ticking static checkbox in the inspector. In order for multiple object to be batched they need to have the same material. Use an atlas when you can. Turning on dynamic batching will help at a cost of CPU time. You can batch for instance many skinned meshes together this way.
    • If you have maximized your batches but still vertex bound try to cull more triangles. Check your camera frustum. You need to have the smalles frustum possible as this will cull more objects sending less vertices to gpu. Do occlusion culling. http://docs.unity3d.com/Manual/OcclusionCulling.html
    • Make sure your shaders cull back faces. (Done by default) This is a really cheap culling technique. So if you have a character gpu will cull back face triangles so only the ones that you are seeing get to be rendered. For instance, if a character if facing you, gpu does not render the triangles on its back.
    • Use technicques to fake geometry: like impostors billboards. On your bush example you should use one quad or two at max and make them face your camera. http://docs.unity3d.com/Manual/Example-CreatingaBillboardPlane.html
    • LOD supported meshes. http://docs.unity3d.com/Manual/LevelOfDetail.html
    CPU Fragment Bound:
    • Get your scene ordered. The order should be 1) all opaque object drawn front to back. 2) all alpha tested objects. 3) skybox, 4) all alpha blended objects from back to front. This avoid overdraw and get you scene right when doing alpha blended objects. You can do this but setting objects to layers and the order in the layer.
    • Avoid using too much alpha blended objects.
    • Avoid full screen effects/shaders.
    • Try to reduce MSAA from 4x to 2x.
    • Bake all static object lighting. Use as few dynamic lights as possible. Forward rendering is faster than deffered.
    • Use texture compression!!!
    • Use mipmapped textures. Not only this improves performance but also resolve a few visuals issues. Check texture import setting for filtering. Point is faster than Bilinear which is faster than Trilinear.
    There are much more to fragment but I runned out of time writing this. :D
     
  5. startas

    startas

    Joined:
    Nov 14, 2014
    Posts:
    102
    Thanks, trying some optimizations, now draw calls reduced to max 136 (saved by batching - 848), max tris - 326k, max verts - 253k, renderer - 1.8-2.5 ms, main thread - 22 ms, min fps ~40.
     
    phil_lira likes this.
  6. startas

    startas

    Joined:
    Nov 14, 2014
    Posts:
    102
    And how about making optimized objects, i.e. grass, bushes and others ? I made 280 bushes from quads - 1 bush == 6 quads, and quad material was a texture (~500x500 pixels) with transparency shader, and it was a big performance hit, about 10 fps hit in general, and a big fps drop for a moment when i look where there is no bushes, and then taking a look at a place with bushes. There isnt anything heavy in that, so the only thing that could have made fps drop was transparency shader, am i right ?
     
  7. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    Transparency is expensive. Especially on mobile devices.
     
  8. startas

    startas

    Joined:
    Nov 14, 2014
    Posts:
    102
    So better variant would be to make a 3d model of bush and matching texture ?
     
  9. Dolkar

    Dolkar

    Joined:
    Jun 8, 2013
    Posts:
    576
    A good option for optimized grass, bushes, foliage, etc is to use alpha testing instead, which is a lot cheaper than full blown transparency. It sacrifices a bit of quality though.. You can at least optimize transparent objects by culling the fully transparent areas in the pixel shader and offloading the fully opaque areas to an alpha test shader using a two pass algorithm: First render the fully opaque pixels in the first pass (clip the rest), that also writes depth. In the second, transparent pass, you only render if the current depth is not equal, thus discarding all the opaque bits. By combining the two, the transparent shader only needs to worry about 10% of the pixels as before, in the case of grass, foliage, etc...

    Also, batching actually helps with CPU performance, not GPU, as every draw call and state change has rather significant driver overhead.
     
  10. asad_asm

    asad_asm

    Joined:
    Oct 17, 2014
    Posts:
    23
    CPU optimisation can be achieved by reducing Draw Calls count by Draw Call Batching. But Draw Call batching only possible with objects sharing same material.

    Material Converter helps you to prepare a shared material from two or more identical materials which differ only in textures and colours. It combines different textures into a texture atlas that can be used by shared material.It auto remaps mesh's uv into texture atlas.

    Material converter is available in the assetstore http://u3d.as/3fn
    Also visit http://support.spinoffstudio.com/Material_Converter.html
     
  11. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,727
    Don't forget about optimizing your scripts where possible. Efficient programming is a whole thing of its own.

    In particular, choosing the right algorithm for the job. e.g. if you had to search through 1000 items to find one that matches some criteria, you're better off with a binary search than `brute force`. Beware of brute force approaches unless they happen to be efficient or they are running so quickly or on so little data it doesn't make a big impact.
     
  12. moco2k

    moco2k

    Joined:
    Apr 29, 2015
    Posts:
    294
    Thanks for sharing these hints.

    You've written that there are much more measures to address fragment/fillrate bound GPU performance.
    Is anyone out there who can add more to this list?
     
    Last edited: Jan 23, 2017
unityunity