Creating Levels of Detail in Blueprints and Python

Choose your OS:

Creating Levels of Detail (LODs) for your meshes can be a good way to increase the performance and frame rate of your game without sacrificing visual quality.

In general, the more triangles your meshes have, and the smaller those triangles are on screen, the harder it is for your GPU to render them. Trying to render too many detailed meshes all at the same time can slow down your frame rate. However, you typically don't need every mesh in the scene to be rendered with the same fidelity: when a mesh is far away, you are often able to swap it out for a less-detailed version of the mesh that contains fewer triangles without a noticeable difference in visual quality.

Unreal Engine 4 offers a built-in LOD management system that automatically chooses the most appropriate version of a mesh to show at runtime, based on the amount of screen space the mesh is currently occupying in each frame. This system relies on you setting up these different alternative versions of your meshes in the Editor ahead of time.

The Editor is capable of generating these Levels of Detail for your Static Mesh assets automatically, by progressively simplifying the mesh to thresholds that you specify. For more information about how this system works and how to set it up in the Static Mesh Editor, see Automatic LOD Generation .

Click image for full size.

However, even though the Editor can generate these LODs automatically, it may not be feasible for you to open every Static Mesh Asset in your project one-by-one in order to set them all up. You could bulk edit the Assets, but this doesn't help if you want to apply different settings to different Static Mesh Assets based on their characteristics — for example, to apply different reduction settings based on the number of existing triangles in the mesh, or based on an Asset naming convention. It also doesn't help if you want to create your LODs as a sub-step within a larger custom Asset pipeline that you've scripted. For these kinds of cases, you can use Blueprints or Python to script the automatic LOD creation system.

You'll need to install the Editor Scripting Utilities plugin, if you haven't already. For details, see Scripting and Automating the EditorNEW! .

Choose your implementation method:

Blueprints

Python

You'll find the nodes you'll need to manage LODs under the Editor Scripting > Static Mesh category.

To use these nodes, your Blueprint class must be derived from an Editor-only class, such as the PlacedEditorUtilityBase class. For details, see Scripting the Editor using BlueprintsNEW! .

  • The key node is Set Lods, which automatically creates levels of detail for the Static Mesh Asset you pass in. To use this node, you'll need to provide it with a set of reduction settings that define the screen size threshold and relative triangle percentage for each level of detail you want to create. See the example below.

    The first EditorScriptingMeshReductionSettings item that you pass to the Reduction Settings input of the EditorScriptingMeshReductionOptions node has no effect, as LOD 0 is always considered to show the mesh at its most detailed level, with all of its triangles in place.

  • You can use Get Lod Count and Get Lod Screen Sizes to get information about the Levels of Detail that are currently set up for a Static Mesh.

  • You can also use Remove Lods to remove all existing LODs (except LOD 0, which is always the fully detailed mesh).

  • Setting up LODs modifies the Static Mesh Asset. Assuming you want to keep the changes you make, you'll also need to use a node like Save Asset or Save Loaded Asset afterward.

The following example loads each Static Mesh Asset in an input path in turn. Whenever it finds one that has more vertices than a minimum threshold, it sets up three additional LODs for the Static Mesh, and saves it afterward.

Click image for full size.

You'll find the LOD management functions in the unreal.EditorStaticMeshLibrary class.

  • The key function is unreal.EditorStaticMeshLibrary.set_lods(), which automatically creates levels of detail for the Static Mesh Asset you pass in. To use this function, you'll need to pass in an EditorScriptingMeshReductionOptions object, which contains a set of EditorScriptingMeshReductionSettings that define the screen size threshold and relative triangle percentage for each level of detail you want to create. See the example below.

    The first EditorScriptingMeshReductionSettings item that you set in the EditorScriptingMeshReductionOptions.reduction_settings array has no effect, as LOD 0 is always considered to show the mesh at its most detailed level, with all of its triangles in place.

  • You can use unreal.EditorStaticMeshLibrary.get_lod_count() and unreal.EditorStaticMeshLibrary.get_lod_screen_sizes to get information about the Levels of Detail that are currently set up for a Static Mesh.

  • You can also use unreal.EditorStaticMeshLibrary.remove_lods() to remove all existing LODs (except LOD 0, which is always the fully detailed mesh).

  • Setting up LODs modifies the Static Mesh Asset. Assuming you want to keep the changes you make, you'll also need to use a function like unreal.EditorAssetLibrary.save_asset() or  unreal.EditorAssetLibrary.save_loaded_asset() afterward.

The following example loads each Static Mesh Asset in an input path in turn. Whenever it finds one that has more vertices than a minimum threshold, it sets up three additional LODs for the Static Mesh, and saves it afterward.

import unrealasset_path = "/Game/studio"
# we define a function that generates new LODs for a specified Static Mesh Asset.
def apply_lods(static_mesh):
# check if the mesh is complex enough.
number_of_vertices = unreal.EditorStaticMeshLibrary.get_number_verts(static_mesh, 0)
if number_of_vertices < 10:
    return
print("treating asset: " + static_mesh.get_name())
print("existing LOD count: " + str(unreal.EditorStaticMeshLibrary.get_lod_count(static_mesh)))
# set up options for auto-generating the levels of detail.
options = unreal.EditorScriptingMeshReductionOptions()
# we request three new levels of detail. Each has:
# - a screen space threshold at which this level of detail appears.
# - the percentage of the triangles in LOD 0 that should be retained at this level/
options.reduction_settings = [ unreal.EditorScriptingMeshReductionSettings(1.0, 1.0),
    unreal.EditorScriptingMeshReductionSettings(0.8, 0.75),
    unreal.EditorScriptingMeshReductionSettings(0.6, 0.5),
    unreal.EditorScriptingMeshReductionSettings(0.4, 0.25)
]
# use the screen space thresholds set above, rather than auto-computing them.
options.auto_compute_lod_screen_size = False
# set the options on the Static Mesh Asset.
unreal.EditorStaticMeshLibrary.set_lods(static_mesh, options)
# save the changes.
unreal.EditorAssetLibrary.save_loaded_asset(static_mesh)
print("new LOD count: " + str(unreal.EditorStaticMeshLibrary.get_lod_count(static_mesh)))
# get a list of all Assets in the path.
all_assets = unreal.EditorAssetLibrary.list_assets(asset_path)
# load them all into memory.
all_assets_loaded = [unreal.EditorAssetLibrary.load_asset(a) for a in all_assets]
# filter the list to include only Static Meshes.
static_mesh_assets = unreal.EditorFilterLibrary.by_class(all_assets_loaded, unreal.StaticMesh)
# run the function above on each Static Mesh in the list.
map(apply_lods, static_mesh_assets)

An alternative approach is to set the LOD Group option for each Static Mesh Asset. This option makes the mesh use one of the pre-set LOD reduction settings that are defined in the [StaticMeshLODSettings] section of your project's BaseEngine.ini file, such as LevelArchitecture, SmallProp, LargeProp, or HighDetail.

For example:

import unreal
asset_path = "/Game/studio/"
def set_high_detail(static_mesh):
# Set the LOD group.
static_mesh.set_editor_property("lod_group", "HighDetail")
# Save the Asset.
unreal.EditorAssetLibrary.save_loaded_asset(static_mesh)
# get a list of all Assets in the path.
all_assets = unreal.EditorAssetLibrary.list_assets(asset_path)
# load them all into memory.
all_assets_loaded = [unreal.EditorAssetLibrary.load_asset(a) for a in all_assets]
# filter the list to include only Static Meshes.
static_mesh_assets = unreal.EditorFilterLibrary.by_class(all_assets_loaded, unreal.StaticMesh)
# run the function above on each Static Mesh in the list.
map(set_high_detail, static_mesh_assets)

For more information about how this system works and how to use it in the Editor, see Automatic LOD Generation .