Optimize Unreal Engine levels with visibility culled Stand-Ins

Written by Jesper Tingvall, Product Expert, Simplygon

Disclaimer: The code in this post is written using version 10.3.5200.0 of Simplygon and Unreal Engine 5.4. If you encounter this post at a later stage, some of the API calls might have changed. However, the core concepts should still remain valid.

Introduction

This blog will cover how to use Stand-Ins in Unreal Engine to replace distant meshes with simple proxy meshes. We will use visibility culling to cull away any geometry not visible from the player's perspective.

Problem to solve

We have a Unreal Engine level which we want to optimize. The level contains distant meshes that we will never see up close. We would like these to be replaced by cheap proxies. The scene is rendered using traditional rendering techniques.

Game world with distant churches

Player's view of the level.

Level from above showcasing floating models

Level from above. We can see that lots of the distant objects will never be reached by the player.

Prerequisites

This example will use the Simplygon integration in Unreal Engine 5. It is applicable to Unreal Engine 4 as well.

Stand-Ins and Nanite Virtualized Geometry

If you are rendering your game with Nanite Virtualized Geometry then small triangles and triangle count is less likely to be the bottleneck. However, there are more things that can impact performance that can be solved with Stand-Ins.

With Simplygon's updated remesher it is possible to create very dense Stand-Ins meshes that works well with Nanite. But you must keep in mind that dense unique meshes comes at memory and disc cost.

Solution

We will replace the distant meshes with simple proxy meshes using Simplygon's Stand-Ins tool.

Create Stand-Ins

The Stand-In outliner can be opened from Window → Stand-In Outliner.

Window → Stand-In Outliner

We can then select groups of models and click Create to create a Stand-In. We will create three Stand-Ins corresponding to the three different clusters of distant assets in out scene.

Cluster of models

Stand-In 1

Cluster of models

Stand-In 2

Cluster of models

Stand-In 3

Once we have created our Stand-Ins we need to assign which pipeline to use. There are three types of Stand-Ins:

In our case we want to optimize distant actors so we pick the far pipeline. The quality is determined by OnScreenSize. We also add material casters corresponding to the channels in our materials; Base Color, Normals, Metallic and Roughness. We use screen size 600 for Stand-In 1 and 3. Stand-in 2 gets a OnScreenSize of 1000.

Settings window for Stand-In

Once that is done we can process the Stand-Ins by clicking Build.

Visibility culling

After building the Stand-Ins we notice that some of the assets now are double faced. This is because the remesher always create a watertight output mesh. So if our input only has one side, it will have 2 sides after optimization. This can be solved in two ways. First contender is geometry culling which is often used for models intersecting the landscape. In our case the model is floating in the air, so we will go for the second option which is visibility culling.

Original
Stand-In

Visibility culling uses cameras scattered in the game world. In Unreal Engine Simplygon can use the navigation mesh to scatter these in the game world. We add a Nav Mesh Bounds Volume to the game world.

Navigation mesh in UE

After that we add a SimplygonVisibilitySamplerVisualizer by selecting Simplygon → NavMesh Samples.

Simplygon → NavMesh Samples

This actor is responsible for creating cameras by sampling the NavMesh. To generate samples we click Asset Actions → Update. We can now see lots of yellow camera samples in our scene.

Navigation mesh with samples

We can now in our Stand-Ins enable Cull Occluded Geometry found under Visibility Settings. We rebuild our stand-ins.

Cull Occluded Geometry enabled

After enabling visibility culling we can see that the mesh is no longer two sided, and a lot more of the mesh has been culled away.

Original
Stand-In

Double sided shadows

After using adding visibility culling on our scene we notice that one of the Stand-Ins are much more bright then the original.

Original
Stand-In Shadow Two Sided = False

This is because we have removed a lot of the triangles from the Stand-In that, while not visible, still casted shadows on the visible geometry. We can decide that this is not a big issue, since we will not see a LOD pop between original and optimized model. Another way to solve this in some cases is by enabling under Lighting → Advanced → Shadow Two Sided. Now light that hits a back face on our stand-in also casts a shadow. With this enabled our stand-in looks much closer to original.

Original
Stand-In Shadow Two Sided = True

Result

Let us start by inspecting the scene from the view of the player. It looks very similar to the original view. We have some minor visual differences, but it does not matter as we will never switch between the original scene and the optimized one. The player will never see how the original scene looked, so we can be quite aggressive with how we optimize the scene.

Original
Stand-In

If we compare the wire frame we can see that in our optimized scene the distant objects are much less dense.

Original
Stand-In

A top down view showcase that visibility culling have removed a lot of triangles never visible to the player.

Original
Stand-In

Lastly we can inspect the most distant actors. Here we can see that we gone form a highly detailed model to a simple proxy model intended to only be viewed from one direction.

Original
Stand-In

Let us compare what we saved with replacing our distant meshes with Stand-Ins.

Stand-In group Original triangle count Stand-in triangle count
Standin 1 14 M 11 k
Standin 2 4 M 11 k
Standin 3 779 k 3 k

Replacing the distant meshes with Stand-Ins has saved almost 19 million triangles. This should give a welcome performance boost.

⇐ Back to all posts

Request 30-days free evaluation license

*
*
*
*
Industry
*

Request 30-days free evaluation license

*
*
*
*
Industry
*