Chris McCole

View Original

Culling in UE4/UE5 (Precomputed Visibility Volumes, and Cull Distance Volumes)

Culling and Visibility Volumes

If you are making a game, you will need some kind of culling, there are multiple methods, and you may not use all of them, but culling is a very important part of making an optimized game. Even if your game is relatively simple and runs well on low-end devices, culling can further reduce processing power which is important to extending battery life and cutting energy cost.

What is Culling?

Culling is the process of determining what objects in your scene you don’t need to see, and cutting them out. It is generally more performant to not render or consider objects that are out of the player’s view. There are multiple methods of culling including: Distance, Precomputed Visibility Volumes (Baked Occlusion Culling), View Frustum, Dynamic Occlusion Queries. In this article I’m going to cover these methods, talk about how and when to use them and what the drawbacks are.

View-Frustum Culling

View frustum culling is on-by-default in Unreal, and is already doing work inside your game! This method is not baked, thus it is determined at runtime. This can be a more expensive method for culling as you need to determine what needs to be culled dynamically. Simply, it takes what is called the view-frustum, or the trapezoidal area in front of the player camera that represents where you can see, and checks which objects are outside of this bounding area. This frustum is made up by the camera’s FOV, as well as the near clip plane and far clip plane. If the object is outside of the bounded area, the object is culled from view. This is very powerful, but can be expensive determining what needs to be culled each frame.

You can visualize the view-frustum area and what is being culled dynamically by clicking on Show->Advanced->Camera Frustum.

If you possess your camera in your scene, you may bring up the command prompt with the ` key. Once up, type in freezerendering and press the “Enter” key. Eject from your view and you can see exactly what objects were rendered and which were not. This is really handy!

Distance Culling

Probably the most simple form of culling is distance culling, and it’s about as simple as it sounds. An object will be culled (not rendered) if the distance of the bounding box on the object is farther than a certain distance away from the camera. There are multiple ways to effect the cull distance of an object. Each Actor has a “Min Draw Distance”, “Desired Max Draw Distance”, and “Current Max Draw Distance”. This allows you to set cull distance per actor, but there also exist Cull Distance Volumes that allow you to bulk-specify cull distances for objects of certain sizes. This is used by the CPU to reduce what it sends to the GPU.

You can use the Cull Distance Volumes to specify a shape to encapsulate, as well as how to cull objects within it. You can use the Cull Distances array to specify, for objects of size X, cull them once you are Y distance away from the center of the volume. These can be really helpful for rooms with many assets, especially if you can’t see them around a corner, you can have a relatively low cull distance and gain much benefit from the cheap culling method.

Precomputed Visibility Volumes

You may also be familiar with this technique as “Baked Occlusion Culling.” Precomputed visibility culling is “baked” offline before the game is built. It would be baked when the static lighting is baked. This method generates many volumes to store data about what objects are visible from certain areas of the level. This works well for small to mid-size levels, and is not good with an open-world approach or having multiple sub-levels that additively load, as the culling must all be baked at once, meaning all the geometry and lighting must be enabled when baking the culling.

This works very well on low-end devices such as Mobile or Nintendo Switch. It especially works well when the player stays low to the ground, or is inside of buildings.

To precompute visibility, you can drag in the precomputed visibility volume into your scene, and set the bounds to the area you wish to compute. Next, you will need to configure your World Settings. The main things to play with are Cell size and Aggressiveness. It’s a matter of data over speed. The smaller your cells the more accurate and more data, and bigger memory requirement. The larger they are the less effective, but the smaller memory footprint. You will need to strike a balance in a case that makes sense for your game.

Dynamic Occlusion Queries

Generally the most expensive form of culling, as this uses the GPU to test objects for visibility within your view-frustum. It does this by checking to see if something large is not between itself and the player camera. For instance, if you stand looking at a wall, and there is a trash can behind the wall, this dynamic occlusion query method will check and see the wall is blocking the trash can. This is similar functionality to what is happening in the Precomputed method, however it is dynamic, meaning it is not baked, and happens at runtime.

There is also a setting in the project settings called “Software Occlusion Queries for Mobile” that is in versions 4.2 and later, this takes what is classically a GPU based functionality and pushes the work onto the CPU. The total cost of this method is determined by the number of LOD meshes that can be used as Occluders.


Cost Effectiveness:

I wanted to run through the methods and talk a little about their effectiveness per cost.

  1. Distance Culling

    1. This is the fastest and cheapest, it involves a simple distance check and can be removed right away. This needs no baking and is quite effective.

  2. View frustum

    1. Due to this method being a simple bounds check, you can quickly eliminate most of your scene based on it’s presence inside of a volume. This needs no baking and will drastically cut your scene.

  3. Precomputed Visibility

    1. This method works very well in some game types, but takes up memory and requires constant lookup, it can take time to read the data, and for some scene setups it just does not work. It’s still on the CPU, so you don’t need to send data to the GPU.

  4. Dynamic Occlusion

    1. This runs on the GPU, so if CPU bound this can be good, however, the CPU still needs to send the data over to the GPU, so it will be a matter of balance, this can work in instances where precomputed visibility cannot, as this is dynamic the scene can be very large and/or dynamic.

Check bounds of Mesh Asset

Regardless of culling method, the mesh bounds will determine when that culling takes place, you most likely will not want to edit this, however some objects, especially small objects, you may want to alter, or if the geometry is odd. This can be found on the Static Mesh asset.

If you don’t want to edit the bounds for the asset as a whole, you can also just edit the bounds scale on individual meshes on actors in the world.

You will need culling in your game, you will need to determine which method work for you in your game on your target hardware.


If you found this tutorial helpful and want to help support me in creating this content that I host and publish for free, please consider contributing to my Patreon or Ko-fi!

See this form in the original post