Map Optimization Guide (Killing Floor 2)
This page will give a comprehensive guide to increasing the performance of your map while also optimizing the player experience; looking at making smooth player movement around the map and general bug fixing. It is recommended that you read through the entire guide and apply all the principles to your map before you release it on the workshop.
The techniques below are listed in order of the stages you should implement them; starting from being able to apply them at anytime and ending with final/last stage tweaks before publishing a map.
Lighting and Dynamic Shadows
PointLights VS SpotLights
SpotLights perform better than PointLights. SpotLights cast in 1 particular direction, While Pointlights have to cast multiple SpotLights in directions around the entire radius (PointLights are 2x more costly in performance; however in saying this - you are able to have many combinations of PointLights and SpotLights without too much of a performance hit).
Both lights are affected by the size of the Radius that they have - as you would expect, having a larger radius has a larger impact on performance. It is recommended to adjust the radius size to be just enough to get the desired effect and not to be over generous. You may be able to achieve the same lighting intent with a smaller radius and larger brightness.
The PointLight Pitfall
One trap a lot of new maps fall into is the unintended over-use and mishandling of dynamic shadows with PointLights. This is not entirely the level designers fault as one particular variable: Cast Per Object Dynamic Shadows is enabled by default. This is located under the PointLight Properties > Light Component > Light Component. See Figure 1.1. You always want to make sure that this variable is DISABLED for any PointLights in your map. Dynamic Shadows should only be reserved for SpotLights.
This particular option may not seem problematic when playing in the editor, this is because the performance hit only occurs when there are many actors (Zeds/Players) within the light's radius. Each of these actors will be casting dynamics shadows, which are already quite demanding. During gameplay, you may see huge fluctuations with your FPS based on the action/number of zeds present in the screen within the vicinity of these lights. This performance hit can be magnified quite significantly when you end up having a cluster of PointLights also casting multiple dynamic shadows in the same area.
You can easily check and disable this variable on all PointLights on your map by:
Doing this trick alone should see a significant increase in performance if they were previously enabled.
SpotLights casting Dynamic Shadows
Dynamic Shadows are quite an intensive features to use in a map. Their performance impact is proportional to the complexity of the geometry of the mesh and actors (Players and Zeds) that they cast shadows from. Poor performance can be magnified if there are a cluster of SpotLights that cast Dynamic Shadows as well.
Try to use them sparingly and avoid clustering them together. Try to use them to accent certain parts of the map, as opposed to making all SpotLights cast them, this allows them to have a larger visual impact; less is more (eg: Casting shadows from car high-beams/floodlights, using them on alarm systems or around a fireplace - usually locations/lights that are quite bold).
Mesh Density and Material & Particle Effect Complexity
Although there really aren't any guidelines for using meshes and materials, mappers should still take notice of things such as the amount of tris in meshes and the complexity of materials applied. It can be very easy to take good looking complex meshes for granted and place them generously around the map, resulting in clusters of high tri densities that may impact performance when looking at them. Anything with a tri count in the 3,000 or more range should be used with regards to their complexity; reducing frequency as the tri count increases.
The same thing can be said for materials, you should be aware that the following types of materials may impact performance when you have high densities of them:
Tree and foliage assets fall into both of these categories (especially Zed Landing assets). Tree meshes usually contain a large number of tris to display leaves. These leaves also use transparent and displacement materials. When coupled together, small clusters of trees and foliage can immediately hit performance. This can be very easy to do since they look decent placed anywhere, so we can get carried away placing many different combinations of trees and foliage. This isn't so much saying "Never use them", more or less just use them wisely; if you can turn the coverage of some foliage from 5 meshes to 2-3 (or even 4) without any major visual impact, definitely do it.
The same principles apply to particle effects, especially those that create fog, smoke or use transparent textures/materials. An overuse and mishandling of them can quickly lead to poor scene performance.
Figure 2.1 Shows some examples of assets that when overused may see a performance hit in your scene, these mainly contain high tri counts or/and use complex materials.
What and Why?
All players can relate to the frustration of kiting around a map only to get stuck on a random part of it which leads to their death.
Movement optimization is based on a general understanding that although in the real-world we can contort our bodies around objects as we move, the game-world does not provide that luxury due to engine limitations with collisions. Because of this, we have to dedicate some additional time to work around the limitations of in-game collisions to make sure that players do not clip or get stuck on parts of the level.
You can download a sample map of the issues and solutions discussed below here: KF-MovementOptimizationExample
Figure 3.1 shows a typical corridor, on the surface it looks fine but there are a couple of problems that will frustrate players that should not exist:
Ideally we want to make sure that no collisions stick out and players move along walls smoothly. A lot of small props (like the alarm and window frame shown) only stick out a small fraction, but that is enough to stop the player.
Although some issues may not seem obvious, we can check the collisions of the map in one of two ways (See Figure 3.2):
Fixing Issue 1: Small Prop Collision
This issue is the easiest to fix. Small props that don't really have a large profile or are too small to really be considered for collision can be fixed by:
Figure 3.3 shows the final properties of these props.
Fixing Issue 2: Props that stop player momentum
We can't really use the same technique above for larger props (such as pillars); doing so allows players and rigid bodies to enter into them which gives a bad feeling of polish and can break immersion. The best option here is to encompass these props in a KFPawnBlockingVolume that angles some of the side-faces as to 'ramp' the player off them. Doing this allows the player slide along the wall without stopping forward (or backward) momentum. See Figure 3.4.
It is a good idea to make sure that all walls allows the player to slide along them without being caught. The nature of KF2 higher difficulties often sees teams kiting around a map, and the last thing they want to encounter is a small object on a corner, wall or in the middle of their path that stops their movement.
By default the KFPawnBlockingVolumes have their properties to block rigid bodies. This can also be argued to break immersion or make the volumes feel out of place (especially for objects that act as small islands in the middle of an open room - not being able to throw dosh over them). If you wish to change this go to the volume's Properties > Collision and disable Block Rigid Body. Also displayed in Figure 3.4. This will allow rigid bodies to pass through the volume but also collide with the actual geometry of the meshes.
Fixing Issue 3: Props that players can stand on or stick out too much
The trim here can use either of the fixes from Issues 1 and 2. However, it would be best to use the blocking volumes. Disabling collision on may have problems previously discussed where items can clip partially inside them. So a simple rectangle volume could be used to cover the trim and the wall instead.
The crates will definitely need a blocking volume, however they also introduce new issues:
Simply putting a volume around the crates is 'Okay', but not the best. In these situations it would be good to reconsider the placement of crates as well, in this case you can:
Ultimately it will be up to you to make the best judgement call here, but you should always consider what the player experience will be, and it should always take priority over prop decoration. In this case, I decided to slightly move the crates and introduce a small crate to fill in the 'empty space' created by the volume.
When you bring all these techniques together you can further optimize the volumes themselves. In Figure 3.5 I created a single volume that covered the entire wall of the corridor. I did not need to change the collision of any of the props apart from the alarm which stuck out from the wall just a little bit too much.
Looking For Map Exploits
Much like the discussions with movement optimization (especially with situation 3): If it sticks out, a player can stand on it, and they may be able abuse this to get in positions where Zeds cannot get to them. You will need to go over your map with a fine-toothed comb to make sure that no props can be used as jumping islands to escape the map or get into positions that would be considered an exploit.
Here are a couple of tips to find and fix exploitable spots:
Fixing Zed Pathing
Just like how players can get stuck on props, Zeds encounter the same problems, however it is usually with the floors they run on. If you ever see a red/coral pathing with an 'X' in the middle of it like in Figure 3.7, most chances are that Zeds will have issues pathing between these path nodes. These are usually caused by:
These issues are extremely common in parts of the map where Zeds spawn outside the map and enter through ramps or areas that are usually off-limits to the player. In most cases tweaking the position of path nodes, meshes and volumes can fix the issues. However, if this does not work due to how props are placed to form ramps or the ground, we can employ a neat little trick to 'flatten' the ground.
Instead of trying to perfectly align meshes or using volumes for Zeds to step on, we can place a hidden mesh over the props which acts as the ground while still looking like Zeds are running over the props. This is done in 2 parts:
This is usually good enough to fix most pathing issues and is a pretty nifty trick that Official Maps use as well (Tragic Kingdom and Krampus Lair use these techniques). Just to be absolutely certain we do not get any weird pathing issues it is also good to:
One last thing to mention, you do not want to use KFPawnBlockingVolumes as floors or ramps, doing so makes the Zed animations bug-out making them look like they are floating and stuck in a single animation as they move.
What and Why?
Mesh merging is a step that all level designers should do to their maps as they approach completion. It aims to further enhance the look of your map by combining multiple static meshes on the same plane/axis so that:
It also has the added benefits of increasing performance by:
This is because you are now calculating collisions and drawcalls for 1 mesh instead of say 4, 8, 20 and even up to 30+ meshes in some cases.
Before you dive directly into Mesh Merging you should do a preliminary pass over your map to see if you can replace smaller modular kit pieces with larger configurations when possible (eg: Two 1x1 floor pieces next to each other can be replaced with one 1x2 floor piece). See Figure 4.1.
Comprehensive Wiki Guide: Setting Up UV's and Mesh Merging (Killing Floor 2)
Community Video (by Seanchaoz): KF2 SDK Tutorial - Combined Meshes
Setting Render Distance
What and Why?
When we are not looking or cannot see meshes, particle effects, lights or any other actors, it makes sense that they should not be rendered on the screen, especially if they are really far away. We can statically set the distances that these actors can render at to help improve performance of the map. This saves the Dynamic Occlusion System (discussed below in Precomputed Visibility) from having to determine if the object is still visible or not past a certain distance; ultimately increasing performance.
This step can be done before or after mesh merging, but it is recommend doing it after so you do not have to go through all the meshes again and double check render distances after merging.
We can set the render distances on any actors by assigning a value to the Max Draw Distance variable under an actor's Rendering Properties (Lights, StaticMesh, Particle Effects, nearly all render-able actors contain a Rendering category). See Figure 5.1.
The value you set for the Max Draw Distance is highly dependent on the mesh's location on the map, so you will need to select portions of your map and assign them individually. Here are some general guidelines to help speed up the process:
Below is an example breakdown of a portion of KF-Desolation and how rendering distances was approached and assigned.
|Step 1 - Initial Ruling on Line of Sight through rooms
|Step 2 - Setting Render Distances working on Largest Distance to Lower Distances
|Step 3 - Tweaking render distances after playtesting
Splatter Map Resolution Standardization
What and Why?
Towards the end of the creation process and after mesh merging you should take some time to address the Splatter Maps around the map. Having consistent Splat Maps around your map gives it an additional layer of polish; as during gameplay the map will be sprayed with blood on all sorts of walls, floors, props and ceilings and we want to make sure the scaling and presentation of the blood is consistent.
You can check the consistency of Splat Maps on your map by selecting the SplatterMap Density [TW] View (yellow) and you can rebuild them by selecting Build Splatter Maps [TW] (red) shown in Figure 6.1.
You can set the Splat Map resolution on any static mesh by opening the properties and enabling Override Splatter Map Res and Setting the value for Overridden Splatter Map Res under Static Mesh Component > Persistent Splats. See Figure 6.2.
You should aim to keep all the splatter maps consistent. It can be a time consuming process of selecting, tweaking and rebuilding splats but the end result provides a much more professional looking map when it is covered in that delicious KF2 blood.
There are a couple of console commands to help you debug when playing in the editor (these require you to enablecheats):
Figure 6.3 shows a before and after of Splatter Map Resolution Standardization.
A good scale for Splat Maps is also present in the image. You can gauge and check the scale in comparison to Zeds by pressing '\' which will hover a clot around the map. Generally Splat Maps should be able to tightly fit a single clot within them.
What and Why?
Precomputed Visibility is a final optimization step that you can add to your map to squeeze the last amount of performance out it. Although we set the mesh and lighting render distances in a previous step, this was only one technique used to help actor culling in our map. By default the maps will use UDK's Dynamic Occlusion System, this is a fine approach in a general sense but it can have a performance cost with calculating what should be culled dynamically while playing. Utilizing Precomputed Visibility will allow us to statically save some occlusion culling around the map to increase performance.
Comprehensive Wiki Guide: Setting Up Precomputed Visibility (Killing Floor 2)
All the above techniques are used in Official KF2 maps to optimize the player experience. If you wish to make official quality maps that people would like to play and have good performance, you should implement all techniques discussed on this page.
It may seem like a lot to do, and it can be, but there is a certain charm and endearing quality to map optimization; especially when you see the performance of your map increase, even by a little bit.
Best of luck to all those who strive for the best out of their work!