Mobile VR performance optimization tips

This section will provide you some tips for optimization on Mobile VR.

1. Use profiler to check current bottle neck is on CPU or GPU

When you port your game or application from PC to mobile device, you may encounter performance issue, please open profiler and check where the bottle neck is, if it’s CPU bound, it’s usually caused by game logic scripts or draw call. If it’s GPU bound, it’s usually caused by the pixel fill rate. Once you know where the bottle neck is, you can make the smallest effort to solve it.

2. Reduce draw call

  1. Decrease the number of Renderers/Materials is a way to reduce draw calls. You may shorten the distance of far clipping plane of camera, or disable the objects far than a specific distance and use fog to hide them.
  2. Use static and dynamic batch. If the object never moved in the scene, set it to “static”. Small meshes which the number of vertices are under 900 and use the same Material, Unity will batch them dynamically. (Note: dynamic batch leads CPU overhead)
  3. For UI, compact all UI textures/sprites into one or two Atlases. (And may need to reorder UI layers to prevent using more than one UIPanel if using NGUI)

3. Reduce the calculation of physics

  1. In Edit > Project Settings > Physics, there’s a table about the interaction matrix of all layers, disable the interactions not needed.
  2. Raycast takes a lot, better to use “Mask Layers“ if you know the target has specific layer.

4. Prevent large GC and leak

  1. Avoid use “foreach“(GC alloc problem was fixed in Unity 5.3.5p8), Please use “for” as much as posible。
  2. When executing StartCoroutine, please remember to use a reference to handle it and set it to null after “StopCoroutine” (Or do not use coroutine)
  3. It’s not recommended to “new WaitForSeconds()” in coroutine, every time you “new” it takes 20Bytes GC.
  4. Prevent to create and destroy object frequently. Implement an object pool to reuse your objects.
  5. Use “RaycastNonAlloc” to replace “RayCastAll”, because the first one will not allocate another instance of memory.

5. Cache the “convenient properties”

Unity provides “gameObject.transform”, “gameObject.renderer”, “Input.touches”, “Camera.main”, “Screen.width”....etc. because Unity uses “GetComponent”, or “FindWithTag”....etc. to get them, these calls are slow.

6. Optimization tips of UGUI

  1. When changing any UI elements under the UGUI canvas, Unity re-generates the UI meshes so try to group the UI to several canvas to eliminate the mesh re-generation.
  2. It’s not recommended to use the Layout system, use the UIAnchor. (https://unity3d.com/learn/tutorials/topics/best-practices/other-ui-optimization-techniques-and-tips)

7. Use Mobile simplifier shaders first, and avoid using “Standard” shader

There are several simplified shaders under “Mobile” category on Unity Mobile platform. These shaders can provide significant performance advantage. For example, some shaders support only one directional light and not support alphaTest or ColorMask.

8. Optimization tips of lights

  1. Use light and reflection probes. Check if you really need the lights to be “Realtime”. The lightmap provides GI, it might look better.
  2. Shadows, in QualitySettings, adjust the settings by projects, especially the “Shadow Distance”.

9. Use compressed textures to decrease the size of your textures and use ASTC to decode image for better performance

This can reduce load times and also reduce build size. Texture compression is dependent on GPU in Android. ETC2 is default in Unity. By using ASTC, image can be decoded by hardware and it will have better performance.

10. Miscs

  1. Put game logic to other thread. Unity uses the main thread and its APIs are not thread safe, but you can create other thread and put your game logic running in it.
  2. “Cast and Receive Shadows” are enabled in default setting, please consider to disable them if needed.
  3. Try to reduce the Skin Mesh Renderers.
  4. Load an empty scene first then load to the target scene to prevent 2 heavy scenes loaded in memory at the same time.
  5. Use animation culling, if the model is not inside your sight, consider to pause or stop its animation.
  6. Decrease the alpha pixels from your particle effects textures, and check the collisions off inside particle system.
  7. Translate transforms? Use Dotween, it saves more resources and time than other tweeners and legacy animation.
  8. Seal the class which is designed no other class will inherit it
  9. Set the “emit” to zero instead set “SetActive(false)” of the particle. Because the Particle system has a lot of “children” and “SetActive” will take a lot of time.(Set emit to 0 is legacy method, please call ParticleSystem.Stop() with the new particle system)
  10. SetActive() will affect all children objects and take time, you can consider to move the object far away if it works fine in your game.
  11. Remove all empty event functions of Monobehavior, such as “Start()”, “Update()”....etc.
  12. If possible, use Arrays, not List and Dictionary.
  13. Prevent String operations every frame.(https://jacksondunstan.com/articles/3015
  14. Use native types(int, float) as key in Dictionary, don’t use string or other types.(Other types will use Equal() to compare the key, it takes time)
  15. Multiple SE are played in the same time usually, please preload them in a proper time.
  16. Use the “UnityEngine.JsonUtility”, which is faster than other Json libraries.(Please notice the limitation of Unity’s) (https://jacksondunstan.com/articles/3714)
  17. Use “AssetBundle” instead of “Resource.Load”.(https://blogs.unity3d.com/2017/04/12/asset-bundles-vs-resources-a-memory-showdown/)