Global Illumination (GI) is a fundamental lighting technique used in video games and computer graphics…
There’s a great chance that you landed on this article because you may have performance issues with your project. You might be starting, in the middle, or about to finish, but you just found a great wall on your way, which doesn’t let you continue your project journey. In this article, we would like to cover some of the optimization solutions that we found helpful when creating our scenes in Unity. Keep reading to see the 5 Best Unity Optimization Tips & Unity Graphic Performance.
7 Unity Optimization Tips – Unity Graphic Performance
Adjust Your Quality Settings.
If you’re using the built-in pipeline, you would create or customize the quality settings under Project Settings > Quality. Unity will adjust that configuration to high performance when creating your project by default. Adjust them manually until it fits the device you are aiming for in the final render. There are a few more parameters you might want to take a look at, like “Rendering,” “Textures,” “Particles,” “Terrain,” & “Shadows.” Remember to play with their different available settings to match the performance to your needs.
However, in URP pipeline, quality settings are stored in URP pipeline assets (think of them as Scriptable Objects that hold quality and other rendering-related settings):
Please note that URP assets must be assigned into Project Settings / Quality – OR -Project Settings / Graphics. Unity will use the URP asset assigned to the current quality level first. If there’s none assigned there, it will use the URP asset assigned into Project Settings / Graphics. It’s a common mistake to enable “Depth Texture” in the URP asset assigned into Project Settings / Graphics and forgetting to also enable it on the URP assets assigned into Project Settings / Quality causing some effects to not work properly when run on mobile or devices that use different quality levels than in Unity Editor or desktop.
In URP, one useful setting to improve performance is “Render Scale”. Use this option to either upscale (increase quality, especially edges) or downscale (improve performance) the size of the camera render target. Our asset, X-Frame FPS Accelerator, will manage this setting automatically based on an array of preferences (plus other features like shadow or pixel light control, etc.)
Btw, did you know the URP is much more performant than built-in due to the way it produces the “Depth Texture”? This shows up in scenes with a large number of shadow casters.
Go to your hierarchy and select your terrain. Next, go to the inspector panel and select the settings gear icon. Look for the “Tree & Detail Objects” option, and there are four key parameters we suggest you mainly play with to obtain a high increase in performance. Detail Distance, to adjust the distance at which the grass and general details will be drawn in the terrain from your main camera. Detail Density, to control the density ammount of the drawn details mentioned before. And finally, the same for the trees with Tree Distance option and Billboard Start. Another cool thing I usually do is to toggle the “Draw” option, which drastically increases the performance when building my scene in the editor’s view.
When using several cameras (ie. a zenithal mini-map or a custom depth prepass camera), you can use the “Preserve Tree Prototype Layer” option to differentiate trees from regular terrain during rendering.
Use LODs For Your 3D Models
LODs stands for Level of Detail. This is a general design term for video game landscapes in which closer objects are rendered with more polygons than objects that are farther away. Generally speaking, the level of detail is dictated by the game’s system requirements. Create a parent game object and assign in the inspector panel the “LOD Group” component. Keep in mind you should already have your 3D objects, each one with a different polygon count. Add each one in the LOD Group component you created before. Remember that 0 is the one with the highest polygon count, and going further, you must add them based on the lower polygon count for each number; we usually do between 3 to 4.
Occlusion Culling will prevent objects from your scene from being drawn if they are not in the main camera view range. I consider this is a fantastic performance solution, given the fact that those culled objects are not necessary, as they are not being seen. Go to Window > Rendering > Occlusion Culling, adjust the area inside the scene where you want the culling to occur, and finally bake it. In the visualization tab, you can now see how objects will be culled behind your camera view, which decreases general polygon count allowing your performance to be multiplied by tens of times.
Shaders & Image Effects
The gaming industry has evolved considerably in visual aspects in the past few years. For developers, this can be something that can create an inner pressure of taking their game to at least that graphic standards users nowadays expect. To reach that level, sometimes you have to consider adding image effects, customized shaders, and making lighting adjustments that require a lot from that performance you are aiming to increase by reading this article. In many cases, it will be difficult to avoid it, but remember, you should allow yourself the necessary time to make these adjustments equilibrated in order to optimize the game while keeping a good visual aspect. We want to give a quick and easy solution right out of the box to this matter. Our X-Frame FPS Accelerator asset can cover this part of the optimization for you in just a few clicks. X-Frame FPS Accelerator reduces lag and contributes to higher FPS (Frames Per Second) providing a smooth gameplay to your users when using your mobile app.
Because mobile use very high dpi, you can use lower resolution to boost your performance and battery life without affecting too much to the visual quality.
With X-Frame FPS Accelerator you can customize:
• Downsampling method (2 static + 1 dynamic adaptative algorithms).
• Desired FPS.
• Minimum acceptable quality. This minimum can range from a very low value to get the maximum FPS when needed to a high value to get some extra FPS but without loosing too much image quality.
• Mnimum quality when camera is not moving or rotating.
• “Nice FPS” factor, beyond this X-Frame seamlessly deactivates, reactivating itself again if FPS drops.
• Optional antialias + sharpen pass.
• Automatic and dynamic control of pixel light count, shadows and LOD bias.
• Advanced options based on users feedback based on real cases – quality adaptation speed, rendering methods, …
Reducing build size and compilation time
Shaders can impose a lengthy compilation time if not managed properly. This is an issue especially if you import advanced asset from the Asset Store which make use of commonly known “uber-shaders”. These uber shaders pack lot of features and abuse shader keywords causing the compiler to generate hundreds (or sometimes thousands) of shader variants. Although Unity will cache the result of the shader compilation (so next time you make a build, you shouldn’t have to wait so long), the truth is that lot of unused shader code goes into your build!
By using a tool like Shader Control, you can learn which shaders in your project generate the most variants and prune the keywords that correspond to features or options that your game or app is not using. This can reduce dramatically the number of shader variants that go into your app. Fast iteration is key for productivity and make your project progress properly.
On the other hand, Beautify for URP includes options to automatically strip Post Processing shader variants further reducing the time to pack and size of your app.
Analyze CPU & GPU bottlenecks
• Use the Profiler in Deep Analysis mode to identify performance spikes and find expensive loops, instructions and memory allocations during the game loop.
• The Frame Debugger is an excellent tool to understand how draw calls are sent to the GPU, in what order, and detect batching issues.
• The Memory Profiler will provide you with details about how the memory is being used by your application. Useful to detect leaks or systems that can benefit from object pooling.
Learn more about optimization in this great Unity blog post.