Tim Hobson

Visibility Culling Overview

Table of Contents
  • Overview
  • How does it work?
  • Culling Methods
  • ​Settings
  • Stats for Culling Performance
  • Troubleshooting & Tips

overview

Unreal Engine 4 utilizes several methods for visibility, or occlusion, culling in its scenes that can be dynamic or precomputed. Occlusion culling is a feature that renders what is visible on the screen and disables what is not to reduce the number of draw calls, which helps keep performance up by not rendering what isn't needed. This can be determined by occlusion queries with the GPU to more manual methods with volumes surrounding areas you would like to cull.

How does it work?

​Occlusion culling is on by default in the Unreal Engine 4. This is done by tracking the visibility states for each primitive component and issues hardware occlusion queries based on heuristics to reduce the number of queries, but increase culling effectiveness. The queries are read back from the GPU one frame later, so there is a one frame delay before an object is determined visible when coming around a corner, which can cause some popping. 
 
Hardware occlusion queries on the GPU are sent one frame later. ​In some instances this can cause an object to appear like it is "popping" into view when the coming around a corner quickly or turning the camera view rapidly. See the Tips & Troubleshooting section for additional details.
​Because the scene’s depth buffer is used this means that both dynamic and static objects can occlude, along with opaque and masked materials. However, translucent materials will not occlude since they are not captured by the scene depth buffer. This can lead to overdraw if you have a lot of translucent materials.

Camera View Frustum

The View Frustum is an area within 3D space that will appear on screen. This view frustum is taken by creating a pyramidal shape from the camera field of view. The Near Clip Plane is a cross section that is where the camera view starts and the Far Clip Plane is the end of this pyramidal view. Rather than just have a direct value that represents this plane Unreal Engine 4 uses the Scene's Depth Buffer. 

Camera Attributes:
  • View Frustum: The area between the Near and Far Clip Planes. Anything within this view is rendered.
  • Field of View (FOV): The width of the camera's view angle measured in degrees.
  • Near Clip Plane: The nearest point to the camera that will render.
  • Far Clip Plane: The farthest point from the camera that will render.  This is handled by Scene Depth in UE4.
Image source: ​http://encyclopedia2.thefreedictionary.com/view+frustum

View Frustum Culling


The example below demonstrates the camera view frustum from a top-down perspective and the camera's perspective view. The Yellow area represents what is within view of the camera. This area will be rendered. The Red area represents what is out of view of the camera frustum. Actors in this area will not be rendered, unless their bounds are large enough to be within the camera frustum (This is not represented in this example). Also keep in mind that anything outside of the camera frustum view is being culled as well. 

​In this view both the Sphere and Cone actors are not rendered because they are occluded from the view of the camera.
​In this view all three actors are visible within the camera view frustum. Even though the cone and sphere are barely visible they are being fully rendered.
​In this view the camera is facing to the left so the camera frustum does not see the Cone actor causing it to be culled.
​In this view the camera is facing to the right so the camera frustum does not see the sphere actor causing it to be culled.

 

Culling Methods

There are several available methods of culling available in Unreal Engine 4. These methods largely work in conjunction with one another, but in some instances it's necessary to use a specific method for mobile where dynamic occlusion is not present.
 

Distance Culling

​Each object instance in the scene can have a min and max draw distance set. This will allow you to adjust when the object will be rendered and removed from the scene based on distance in Unreal Units.
Property Description
Min Draw Distance The minimum distance at which the primitive should be rendered. This is measured in world space units from the center of the primitives bounding sphere to the camera position.
Desired Max Draw Distance Max draw distance exposed to the LDs. The real max draw distance is the min (disregarding 0) of this and volumes effecting this object.
Current Max Draw Distance The distance to cull this primitive at. A CachedMaxDrawDistance of 0 indicates that the primitive should not be culled by distance.

In the examples below the Min and Max Distance have been set for the cube. These values determine the closest distance to render the actor or the farthest distance that the actor can be rendered from the camera view.
  • Min Draw Distance: 500
  • Max Draw Distance: 1000
The Min Draw Distance means that anything from 0 (center of the actor) to the value entered will not be rendered. Only from that value away from the mesh will be rendered.

The Max Draw Distance is the maximum distance at which the mesh will be rendered. Anything beyond this value will from the center of the actor will not be rendered.
1500 CM
1000 CM
500 CM
In the image to the right you can see that as the camera moves closer to the Cube the mesh becomes visible starting at the 1499 unit mark and is no longer rendered once the camera reaches the minimum draw distance of 499 units.













 

 

Dynamic Occlusion

Unreal Engine 4 uses hardware occlusion queries based on the scene depth buffer to reduce the complexity of the scenes and the number of queries that are needed to increase culling effectiveness. This is done by sending queries to the GPU and then reading them back one frame later. Currently there are two methods that can be used for the hardware occlusion queries. 

The Camera Frustum View example above is an example of this type of dynamic hardware occlusion.
 
Console Variable Description
r.OneFrameThreadLag

Controls when occlusion queries are rendered. Rendering before the base pass may give worse occlusion (because not all occluders generally render in the earlyzpass). However, it may reduce CPU waiting for query result stalls on some platforms and increase overall performance.

  • 0: After BasePass.
  • 1: After EarlyZPass, but before BasePass.
r.AllowOcclusionQueries If zero, occlusion queries will not be used to cull primitives.
r.DownsampledOcclusionQueries Whether to issue occlusion queries to a downsampled depth buffer.
r.NumBufferedOcclusionQueries Number of frames to buffer occlusion queries (including the current renderthread frame). More frames reduce the chance of stalling the CPU waiting for results, but increases out of date query artifacts.

Hardware Occlusion Queries (Default)

This occlusion querying is handled by using the Camera View Frustum and the bounds of a mesh to determine if it should be rendered or not in the scene. If an actor is visible within the view frustum it will not be culled, and if the bounds of an actor are no within this view as well, it will not be culled. Since the bounds are considered here to this can lead to the a popping effect where the actor "pops" into view if the camera view is changing too quickly. The blue bounding box around the actors geometry will determine when it should be visible. 

Hierarchical Z-Buffer Occlusion

Hierarchical Z-Buffer Occlusion works by using lower mip settings of the scene depth buffer. This method 

Hierarchical Z-Buffer Occlusion works by looking at an actor based on its relative size in the world and approximates the bounds. This can help reduce the "popping" in of an actor that can happen when the default method is used, which has a tight bounding box around the geometry of the actor. 

​http://nickdarnell.com/hierarchical-z-buffer-occlusion-culling/
http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/
http://http.developer.nvidia.com/GPUGems/gpugems_ch29.html
http://www.gamasutra.com/view/feature/3394/occlusion_culling_algorithms.php?print=1
Hierarchical Z-Buffer Occlusion method's implementation is still considered experimental in Unreal Engine 4, so with that in mind there are some know issues that have not yet been addressed.
Console Variable Description
r.HZBOcclusion If 0, this will use the default Hardware Occlusion Queries system. By using 1 this will use the HZB occlusion system, which will have less GPU and CPU cost with more conservative results. When set to 2 this will force HZB occlusion system which will override any rendering platform preferences.

Precomputed Visibility Volume

​Precomputed Visibility Volumes will store the visibility of the objects placed in your level based on their location in the world. This volume is primarily used to have dynamic occlusion on mobile devices where dynamic occlusion is not used. These can be used in conjunction with other occlusion methods.

For more information on using and setting up Precomputed Visibility Volumes  you can read about them in this page.

Cull Distance Volume

NOT ADDED YET
​Brief overview of what it is and how it works.
Instanced static meshes not supported
Use the keyboard shortcut "G" while working in the Editor to see the game view.

Mesh Bounds

​For each object instance you have the option to adjust its Bounds Scale. This scale is a bounding box around the actor in the scene. The bounds is made up of a blue bounding box around the geometry of the actor and a sphere that centers to this. 

It can be helpful to see the bounds of a mesh in your scene in some instances. You can enable this visualization by going to the Viewport and selecting Show > Advanced > Bounds. To view the bounds of an actor you must select it in your scene.
When you select your actor in the scene you have the option via the Details panel to adjust the Bounds Scale manually. This can sometimes be useful to reduce an actor from "popping" into view, but mostly this setting should not need to be adjusted. 
When you increase the bounds of a mesh you do not have to increase by whole numbers. You can increase the decimal size incrementally until you get the results you're wanting. For example, increase the Bounds Scale to 1.15 rather than increasing to 2.0.

Settings

Project Settings

​In the Project Settings there are several settings that you can adjust for culling that will affect your project, such as warnings, disabling occlusion entirely, to even lights in your scene.

​You can access the Project Settings by going to the Menu > Edit > Project Settings in the Rendering category.
Stat Description
Occlusion Culling Allows occluded meshes to be culled and not rendered. If this is disabled all occlusion culling will be disabled for the project which can have performance implications.
Min Screen Radius for Lights This is the screen radius at which lights are culled. Larger values can improve performance but causes lights to pop off when they affect a small area of the screen.
Min Screen Radius for Early Z Pass Screen radius at which objects are culled for early Z pass. Larger values can improve performance but very large values can degrade performance if large occluders are not rendered.
Min Screen Radius for Cascaded Shadow Maps This is the screen radius at which objects are culled for cascaded shadow map depth passes. Larger values can improve performance but can cause artifacts as objects stop casting shadows.
Warn about no precomputed visibility Displays a warning when no precomputed visibility data is available for the current camera location. This can be helpful if you are making a game that relies on precomputed visibility.
​If you're developing a mobile game it would be beneficial to enable the option for Warn about no precomputed visibility option in the Project Settings since mobile does not use dynamic occlusion culling.

Stats for Culling Performance

Performance

​When developing your games and filling your scenes you will want to keep your performance as high as possible. In real-time rendering you will want to manage your scene so that you can keep your frames per-second (fps) as high as possible because the more computations that are required based on the number of assets in your scene will take away from your overall performance. This is done by saving CPU power by rendering only the number of objects that need to be in the view. While this is not solely reliant on occlusion culling it can play a larger role in a densely packed scene.

Stat Window

In your game or in the editor you can use the console command Stat Initviews to bring up the stats that are relevant to visibility culling.
Stat Description
View Visibility
Occlusion Cull
Frustum Cull
Decompress Occlusion
Processed Primitives
Frustum Culled Primitives
Visible Culled Primitives
Occluded Primitives
Occlusion Queries
Visibile Dynamic Primitives

Visible static mesh elements is the single biggest contributor to rendering thread time and should be carefully watched and optimized.

Here are the culling methods listed in order they are applied to each primitive, which is also from least to most expensive in terms of rendering thread cost.
  • Distance culling
  • View frustum culling
  • Precomputed occlusion culling
  • Dynamic occlusion culling (hardware occlusion queries)
Occlusion culling methods cost much more than distance culling, so it's a good idea to setup cull distance volumes for distant stuff even if they will be occluded from a certain part of the map.

Of course, it's even better if that distant section of the map could be streamed out completely.
When testing occlusion culling there are a few things to be aware of.
  • Occlusion culling is disabled in Wireframe viewmode
  • Use the Console Command 'Stat Initviews' in PIE or Standalone games.

Troubleshooting & tips

  • ​In larger scenes or those with long view distances use large occluders where possible to limit distance that can be viewed. This will help reduce the number objects drawn to the screen
  • Point lights are culled based on their screen size. This is set by default in the Project Settings > Rendering
  • BSP culls each face and not based the entire mesh like Static Meshes
  • For dark areas, like caves where you can sometimes get pop-in, this can cause a bright flash of light depending on what is located on the other side of the object. To address this, use a large static mesh that can encapsulate or block the backside of that object.
  • Use large Static Mesh occluders in place of increasing mesh bounds.
  • Construct assets in a thoughtful way that does not over modularize the level. This can reduce the number of draw-calls, occlusion queries, and reduce instances where the pop-in from one frame lag can happen.
  • Enable the Console Command r.VisualizeOccludedPrimitives in the editor. This Editor-Only command will show the bounding box of any primitive that is occluded. 
  • Enable the Console Command FREEZERENDERING  to freeze the scene at this point in the editor. You can now freely move around to inspect specific rendering issues you may have. This is extremely helpful for troubleshooting and inspecting occlusion culling issues.

Tips