UPDATE: Since some developers remarked on this, this guide is for indie devs (who not necessarily have their own engine programmers dedicated to ensure performance optimization). It might not be relevant for large studios.
UPDATE2: With Unreal 4.14, the forward renderer came out. We are using it for Dashing Dinos and saved ~ 5-10ms. It nearly looks the same, sometimes even better than before, because we can go full 1080p (r.ScreenPercentage=100). The only drawbac, -> no SSAO.
When porting our game to XboxOne, we realized our existing graphic settings resulted in 20FPS (down from 90FPS on one of our killer-PCs). Dashing Dinos needed to run with min 60FPS in order to feel smooth. This proposed a huge challenge, because we obviously didn’t want to lose too much visual quality. Multiple posts already address how to improve performance within UE4, especially since VR got bigger and bigger, but this detailed post will hopefully be helpful for some people struggling with the same issues anyway.
First off: this guide focuses on GPU Performance Optimization, not CPU. No changes to the engine were made for this guide and you should be able to follow easily without any C++ knowledge. You should however, know how to profile your game’s performance. If you don’t, take a look at the thorough documentation from Epic here: Performance Profiling.
Check what limits your performance with the “stat fps” command and if you are GPU bound you’ve come to the right place. Don’t forget to use the GPU Profiler (Shortcut: Ctrl+Shift+,) from time to time when tweaking your performance.
Quality Settings (~80 FPS)
Before we dive into concrete config variables and scalability settings, we quickly discuss how UE4 prioritizes different methods to set these values. Values set with a lower priority will always be overwritten by higher ones, which you should keep in mind when creating different quality levels for your game. Here is the priority order from highest to lowest priority:
2. Console commands
3. Scalability settings
The DefaultDeviceProfiles.ini is a config file inside your projects’ config folder (e.g.: \DashingDinos\Config\DefaultDeviceProfiles.ini). If it doesn’t exist, just create it. You can either set commands directly inside the .ini file or within the editor. Setting it in either is directly related to the other. Here is an example of how you can access the file inside the editor and how the config file looks like within a text editor like Notepad++.
The DeviceProfile commands override all other commands, so be considerate about what you set there. Hence, we use the DeviceProfiles nearly exclusively for XboxOne (which only needs one level of quality). For PC we want the users to be able to switch quality levels, depending on their hardware, and therefore need to set the quality values through console commands/scalability. Only commands shared by all quality levels are written within our Windows DeviceProfile:
We’ll come back to Windows later, let’s focus on XboxOne first. These are all the commands we use for Dashing Dinos:
DeviceType=XboxOne BaseProfileName= MeshLODSettings= TextureLODSettings= ; SetQuality +CVars=sg.AntiAliasingQuality=4 +CVars=sg.EffectsQuality=3 +CVars=sg.PostProcessQuality=3 +CVars=sg.ShadowQuality=1 +CVars=sg.TextureQuality=3 +CVars=sg.ViewDistanceQuality=1 ; SetQualityAdvanced +CVars=r.HZBOcclusion=0 +CVars=r.SceneColorFringeQuality=0 +CVars=r.SSR.Quality=0 +CVars=r.SceneColorFormat=3 +CVars=r.TranslucentLightingVolume=0 +CVars=r.TranslucencyVolumeBlur=0 +CVars=r.TranslucencyLightingVolumeDim=4 +CVars=r.TiledDeferredShading=0 +CVars=r.TiledReflectionEnvironmentMinimumCount=10 ; PostProcessEffects +CVars=r.PostProcessAAQuality=3 +CVars=r.LightshaftQuality=0 +CVars=r.MotionBlurQuality=0 +CVars=r.BloomQuality=0 +CVars=r.EyeAdaptationQuality=0 +CVars=r.LensFlareQuality=0 +CVars=r.AmbientOcclusionLevels=0 ; ScreenPercentage +CVars=r.ScreenPercentage=85
As you can see, scalability commands are being set first (sg.xxx) and individual values will be changed later. When just looking at the scalability settings, one would assume the settings are quite high quality (Effects-, PostProcessing- and TextureQuality = 3), however, most of these settings get overridden later by our individual commands at the bottom.
With all these values it’s a trade-off between visual quality and performance, especially “r.ScreenPercentage”. Setting the value down to 85, impacted our performance tremendously. By rendering less pixels and up-scaling the rendered image you will obviously have quality loss, but we tried to compensate this as good as possible by increasing AntiAliasing and TextureQuality. Just check how low you can set “r.ScreenPercentage” without losing too much visual quality and watch your FPS skyrocketing.
PC – Quality Levels
Let’s get back to Windows, where everything is a little bit more complicated. Players have many individual hardware setups, on which your game will perform completely differently. This will bite you in the ass, nothing you can do about it. What we as developers can do however, is to give players the possibility to change settings according to their needs, to ensure a smooth playing experience. We didn’t want hundreds of individual settings for Dashing Dinos and therefore created some presets for different levels of quality.
Take a look at the code on the left if you are interested in how we create the Data Assets. The Data Assets just hold individual quality settings which can be applied within our graphic options.
You might notice that the values we set inside the Data Assets are quite similar to what we did within the DefaultDeviceProfile.ini for XboxOne. However, this system is much more flexible for different levels of quality, which is exactly what we need for PC.
If you are interested in the individual values for our quality levels or if you want to know how we applied the settings, write in the comments and we will add this information here.
We are done with the main optimizations at this point. The interesting part comes now, where we try to optimize the not-so-obvious stuff.
Advanced Improvements (~55 FPS)
Post Processing and Particle Effects (~10 FPS)
By adjusting some of the Post Process settings in our quality levels/ DeviceProfiles, we already took care of most performance killers related to PP effects. However, for example in Dashing Dinos, we wanted to disable Depth of Field completely. Unfortunately we had one particular scene where we needed DoF and could therefore not disable it within our settings by default. Some PP effects should also vary from platform to platform and just to have a little more flexibility, we created two seperate PostProcessVolumes for PC and XboxOne. We then enabled and disabled them depending on the platform. This is an example of one of our LevelBlueprints where we do exactly that:
In addition to the PP effects, we disabled most of the environmental particle effects on XboxOne. Dust and fog particles for example, are quite expensive due to the overdraw. Enable the Shader Complexity View Mode in the viewport to better see how costly your particles are.
Lights & Shadows (~40 FPS)
Dynamic lights and shadows are a performance killer. Try to avoid them at all costs. Bake everything you can and only use static and stationary lights. We have no dynamic lights or dynamic shadows in Dashing Dinos at all! Some of our lights are set to stationary in order to get nice reflections on ice, crystals and rocks, however, dynamic shadows are disabled in all of them.
All character shadows for example are faked with decals. Whether or not you can do this is obviously totally dependent on the game you create. It will never look the same as with real shadows and you will lose visual quality, but with an isometric perspective like ours, the differences were minimal and the performance gained was massive.
Translucency (~5 FPS)
Translucent objects are expensive, so always try to minimize overdraw. This applies to particles as well. Unreal handles tens of thousands of triangles quite well, so creating some extra meshes to reduce overdraw might be a good idea in some cases. Take a look at our logo below, where we used a unique mesh instead of just a plane, in order to reduce massive overdraw.
We hope this will be helpful for other developers struggling with GPU bound FPS performance issues, if you have anything to add or thoughts for improvements please let us know in the comment section below.
Btw, these are the current FPS on our PCs (CPU: i7-4790K, GPU: GTX 970) and on the XboxOne:
- XboxOne: 60 FPS
- PC highest settings: ~90 FPS
- PC lowest settings: >200 FPS
To round this up, we created screenshots for different quality levels and platforms, which is what you see below:
GL & HF,