Map Optimization Guide (Killing Floor 2)

From Killing Floor 2 Wiki
Revision as of 06:38, 9 October 2018 by Delta-ranger (talk | contribs)
Jump to navigation Jump to search

Introduction

This page will give a comprehensive guide to increasing the performance in your map and also optimizing the player experience; looking at such things as making smooth movement around the map, avoiding getting caught on props and general exploit fixing. Its 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 of the sphere (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. NEVER use dynamic shadows with PointLights. 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 dynamic shadows in the same area.

You can easily check and disable this variable on all PointLights on your map by:

  1. Right Clicking any PointLight
  2. Selecting Select > Select All PointLight Actors
  3. Pressing F4 to open the properties and Disabling Cast Per Object Dynamic Shadows located under Light > Light Component > Light Component for all selected lights.

Doing this trick alone should see a significant increase in performance if they were previously enabled.

SpotLights casting Dynamic Shadows

As mentioned previously, 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 map and the amount of moving 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.

It's recommended to use them sparingly and to avoid clustering them together. Try to use them to accent certain parts of the map, as opposed to making all SpotLights cast them, as they can have 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 bold and already stick out).

Figure 1.1: Disabling Dynamic Shadows on Lighting

Mesh Density and Material & Particle Effect Complexity

Although there really aren't any guidelines for using meshes and materials, mappers should still take notice 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. I would say 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 and you should be aware that the following sort of materials may impact performance when there are high densities of them:

  • Transparent Materials like glass, water, smoke and foliage/leaves
  • Materials that move and displace the mesh like leaves (in the wind) and water
  • Animated and moving textures within the material like fire or smoke

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 usually 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 can 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 exact same thing can be said about 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.

Figure 2.1: Deceptively Complex Assets

Movement Optimization

General Player Movement

Looking For Map Exploits

Fixing Spawns and Pathing

Mesh Merging

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:

  1. Light Maps generated by the Engine will be consistent and look better
  2. Splat Maps will also look connected and part of the same object (eg the same floor) instead of being disconnected

It also has the added benefits of increasing performance by:

  1. Reducing the amount of drawcalls required to render the object
  2. Simplifying and reducing collision calculations

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.

ALL MAPS SHOULD MERGE THEIR MESHES WHERE POSSIBLE

How?

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 (e.g. 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

Figure 4.1: Replacing smaller kit pieces with larger configurations. In this case I can replace 4 single wall pieces with 1 2x2 piece.

Setting Render Distance

What and Why?

When we aren't looking or cannot see meshes, particle effects, lights or any other actors, it make 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 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.

If you cannot implement Precomputed Visibility, you must at very least set proper render distances for ALL actors on your map.

This step can be done before or after mesh merging, but I recommend doing it after so you don't have to go through all the other meshes to double check render distances set.

How?

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:

  • You can check the distance of one mesh from another by using the orthogonal views in the main viewport (eg: Top, Side, Front views). If you press the middle mouse button while in these view modes, you can draw a ruled line across a portion of the map which will give you a distance in units. You can use this distance to gauge what value to put in for the Max Draw Distance. See Figure 5.2.
    • You can also accurately mass select portions of your map in these view modes while also in wireframe display.
    • Pressing Ctrl+Alt+Left Mouse allows you to quickly Box Select.
  • Try mentally break your map up into specific sections based on the viewing angles in which they can be seen. Once you figured out the different areas, select all the relevant meshes, lights and any other actors and assign them to a Layer. This is so you can easily toggle rendering of them on and off in the viewport; especially useful for multi-leveled maps
    • You can access the Map's layers by selecting the Layers tab within the Content Browser
    • Alternatively you can get to it by going to: View > Browser Windows > Levels
  • Try and break your map up in a High to Low fashion. Eg: Start of with the sections that will have the highest rendering distance, set them first, and then work down to those areas that might have lower distances
  • You can only set Render Distances of multiple actors of the same type. If you have selections of Lights, Particle Effects and Meshes the Rendering category will not show up.
    • This is why I suggested setting portions of the map to layers. You can easily select a single type of actor and change their properties in mass.
  • After you set all the render distances, make sure you playtest your map and look at the different sections to make sure everything is rendering properly, and nothing is accidentally set incorrectly. Adjust accordingly.
  • You will need to do this for all render-able actors. Including:
    • StaticMeshes, SkeletalMeshes, InterpActors, Lights, DecalActors, ParticleEffects/Emitters, KFCollectibleActors, KFDoorActors, KFDestructibleActors, KFFracturedMeshGlass

Examples

Below is an example breakdown of a portion of KF-Desolation and how I approached rendering distances and viewing angles.

  1. Originally I started off breaking the map down in the different room sectors. I drew lines through the visible viewing angles (going through doors and transparent meshes) and noted the distances.
  2. From the initial ruling, I broke the areas down based on the longest distances working down. Meaning long corridors would break up the traditional rooms, and the remaining sections would receive that area's render distance (ie: the Mess Hall was split due to the long back corridor cutting down the back of it, that part of the Mess Hall received the 7.5k render distance, while the remaining parts of the room got the 4.4k render distance shown in the 2nd image).
  3. After setting render distances, I playtested the map in the editor and found additional viewing angles that would need additional tweaking. The 3rd image shows the view angle (dotted line) and the meshes that had additional tweaking (highlighted areas).

Figure 5.1: Max Draw Distance Property
Figure 5.2: Distance Ruler indicated by the red line

Image
Description 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.

How?

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 static mesh object 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):

  • ToggleSplatterGun - Will allow you to spray the map with splatters, left click will toggle constantly placing splatters
  • SplatterGun - Same as above, just requires constant left clicking
  • ClearSplatters - Does what it says
  • ClearCorpses - Does what it says
  • SpawnZed ZedName[FString] - Spawns Zeds - not as efficient as just using the splattergun

Examples

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 fit a single clot within them

Figure 6.1: SplatterMap Density View (yellow) and Build Splatter Map (red) Buttons
Figure 6.2: Splatter Map Override Properties

Figure 6.3: Splatter Map Standardization Before and After


Precomputed Visibility

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.

How?

Comprehensive Wiki Guide: Setting Up Precomputed Visibility (Killing Floor 2)

Final Words

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 frankly it is, but this is game development and we have a responsibility to deliver the best experience we can for the players. Personally I find a certain charm and rewarding quality 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! -Delta