Performance Optimization #1: Shaders
During the last project I did I have constantly be running into troubles and pitfalls while trying to push Unity to its boundaries concerning level sizes, textures used and triangles rendered. It was especially hard to keep down the draw calls and thereby ensure a acceptable fps count. There are a few useful tipps to keep draw calls down, like atlas textures, mesh merging, and implementing a simple LOD system. I will talk about all those in the future. Today I want to focus on another important aspect when it comes to rendering performance: Shaders!
Once all the above mentioned is done and only a couple of hundred draw calls are left for your level environment to be rendered you still can increase the performance dramatically by optimizing shaders and not using builtin-shaders. For a city scene as shown here I went from around 2000 draw calls to around 350 just by restructuring the texures and meshs used in the scene, which went along with a great performance increase. After optimizing the shaders used in the scene I managed to increase performance a little more and get twice the fps rate out of the same scene.
Unity’s builtin VertexLit Shader Collection assumes that pixel lighting and dynamic shadows might be used in any scene in your project and therefore it might become neccessary for objects that are rendered with the standard VertexLit shader to cast and/or receive dynamic shadows. The shaders use a second pass to enable shadow casting and shadow receiving.
Depending on the structure of your game world this might very well be a redundancy. It certainly was for me as I did not plan for pixel lighting or dynamic shadows to be used for the game world itself, i.e. buildings, props, vegetation, AI traffic and NPCs.
To ensure this I used two directional lights to simulate sun light instead of only one:
- a pixel light affecting the player objects (the player vehicle and player driver) and casting dynamic shadows
- a vertex light for all other objects: buildings, props, plants, AI vehicles, etc.
I used the culling masks of the lights to make sure that only the objects I need to are affected by the respective light. The missing ability of VertexLit objects to cast shadows was supplemented by a pre-rendered shadow map that was projected onto the level’s floor.
Once this preparation is done creating optimized shaders is easy. You just take the builtin VertexLit shaders and take out the second pass.
You can do this for all sorts of shaders. For the city scene as shown in the last post I used the following set of optimized shaders: VertexLit, Transparent Cutout VertexLit, Transparent VertexLit, VertexLit Detail (a vertex lit version of the Diffuse Detail shader).
I put together a basic shader package to get you started. Twitter me about your results if you have done some performance tests yourself - I am curious to know whether anybody can reproduce my drastic performance boost.
fixed the Download link






