[UE5] Cut What You Draw with LOD, Culling, and Occlusion

Created: 2025-12-12Last updated: 2026-07-20

The full picture of "not drawing things" when Draw is your bottleneck. Simplify distant meshes with LOD, drop what the camera can't see with frustum and occlusion culling, and cut by distance with Cull Distance Volume. Includes a hands-on where you see the results with Freeze Rendering.

One tree in your level ran fine. Three thousand trees, and the frame rate tanks. You run stat unit and Draw is the biggest number. That means the CPU is writing 3,000 draw commands every single frame.

The fix is to reduce how much you draw in the first place. Draw distant objects coarsely, and don't draw things that are offscreen or hidden behind walls at all. This article covers four techniques (LOD, frustum culling, occlusion culling, and distance culling) and explains which stat unit number each one actually moves.

Distant trees rendered as simplified shapes while offscreen and occluded trees are greyed out

What You'll Learn

  • The idea all four techniques share: cut corners on anything far away or invisible
  • How to set up LOD and tune the switching distance
  • Frustum culling and occlusion culling (both automatic)
  • Cutting by distance with Cull Distance Volume
  • Using Freeze Rendering (Ctrl + Shift + O) to see culling with your own eyes
  • Hands-on: cutting Draw in a scene with 3,000 trees

Sponsored

The Shared Idea: Don't Draw Everything Faithfully

In the previous article, Finding Performance Bottlenecks with stat unit, we established that Draw is the time the CPU spends assembling draw commands. That number scales almost directly with how many things you're drawing.

So there are only two ways to bring it down: draw fewer things, or make each thing cheaper.

Classification diagram splitting the four techniques into "reduce the count" (frustum, occlusion, distance) and "make each one cheaper" (LOD)
TechniqueWhat it doesNumber it movesAutomatic?
LODSwaps distant objects for simpler meshesGPU (fewer triangles)Needs setup
Frustum cullingExcludes anything outside the camera viewDrawAutomatic
Occlusion cullingExcludes anything hidden behind geometryDrawAutomatic (PC/console)
Distance cullingExcludes anything past a set distanceDrawNeeds setup

In practice, the only two you configure yourself are LOD and distance culling. The engine handles the other two for you, so your job there is to confirm they're actually working.


LOD: Draw Distant Objects Coarsely

LOD (Level of Detail) swaps in simpler meshes based on distance from the camera. A tree in the distance doesn't need 10,000 triangles. If it only covers 20 pixels on screen, 500 triangles looks identical.

The same tree stepping down from LOD0 to LOD3 with distance, while its on-screen appearance barely changes

Generating LODs

Open the Static Mesh Editor and use LOD Settings in the details panel on the right.

  1. Enter the number of levels in Number of LODs (3 to 4 is a good target for background assets)
  2. Press Apply Changes and the engine generates the simplified versions from the source mesh

An even easier option is LOD Group. Just pick a preset like SmallProp or LargeProp and you get level counts and distances appropriate for that category in one shot. Try this before hand-tuning anything.

Tuning the Switching Distance

Each LOD has a Screen Size value. This isn't a distance. It's the fraction of the screen that mesh occupies. A Screen Size of 0.25 means the switch to the next LOD happens once the mesh shrinks to roughly a quarter of the screen's width and height.

Using screen coverage instead of raw distance means the setup doesn't fall apart when the field of view or resolution changes.

Asset typeApproach
Things the player examines up close (weapons, hero gear)Keep LOD0 longer (set the next Screen Size lower)
Background assets placed in bulk (rocks, trees, rubble)Switch early (set Screen Size higher)

Checking Your Work

You can see which LOD level is currently displayed. In the viewport's View Mode dropdown (default Lit), pick Level of Detail ColorationMesh LOD Coloration to color-code each LOD level. Move the camera back and forth to confirm the switching distances are what you intended.

Sponsored

Culling: Don't Draw It At All

If LOD is "draw it coarsely," culling is "don't spend a single millisecond on it." The impact is bigger, and most of it happens automatically.

Top-down diagram showing trees outside the camera frustum and trees behind a wall both excluded from rendering

Frustum Culling

This skips anything outside the camera's view volume (the frustum). UE does it constantly and automatically.

There's almost nothing to configure, but one fact is worth knowing. The test uses the actor's bounds (its bounding box), not the mesh itself. An actor with unnaturally large bounds won't be culled even when it leaves the screen. This tends to happen when you manually expand bounds for a material that uses World Position Offset.

Occlusion Culling

This skips anything fully hidden behind something closer to the camera. Behind walls, inside buildings, over the far side of terrain. Objects there cost nothing to render.

On PC and console, UE5 enables GPU-based hardware occlusion (Hierarchical Z-Buffer) by default. No special setup required. Just confirm that Occlusion Culling is checked under Project Settings → Engine → Rendering → Culling.

It does have two quirks worth knowing.

  • It's one frame behind: the test uses depth information from the previous frame, so swinging the camera quickly can briefly draw things that should be hidden
  • The test itself costs something: with tens of thousands of objects, the occlusion test starts showing up in Draw. At that point, combine it with distance culling and instancing

For mobile, there's a separate CPU-based software occlusion path. If you use it, set LOD for Occluder Mesh on the meshes that act as occluders to specify a simplified mesh for the test.

Building large occluders is worth thinking about. A single large wall hides everything behind it far better than a row of thin pillars. Placing "big surfaces that block sightlines" during level design alone cuts your render count substantially.


Cull Distance Volume: Cut by Distance

When automatic culling isn't enough, you can explicitly declare "don't draw anything past this distance." There are two ways.

For individual actors, select the actor and set Desired Max Draw Distance in the Rendering section of the details panel, in Unreal Units (1uu = 1cm). Enter 10,000 and it disappears at 100 meters.

For bulk setup, drag a Cull Distance Volume into your level from the Place Actors panel. It applies size-based cull distances to every actor it encloses.

Cull Distance Volume size mapping table alongside a diagram of small objects vanishing up close while large objects persist into the distance

The volume's Cull Distances property in the details panel is an array of Size and Cull Distance pairs.

Size (object size)Cull Distance (vanishes at)
1003,000
50010,000
200030,000

The engine looks at each actor's bounds size and picks the closest matching row. One volume gives you small things disappearing up close and large things persisting into the distance. Nobody notices a pebble vanishing at 100 meters, but everyone notices a mountain vanishing. Cull Distance Volume is that intuition turned into a table.

Push the distances too tight and objects pop into existence in front of you as you walk (pop-in). Walk around, and if it bothers you, extend the distance. Iterating like that is the practical approach.

Sponsored

Freeze Rendering: See Culling in Action

The annoying thing about culling is that you can't tell from the screen whether it's working. Even when things are correctly excluded, they weren't visible anyway, so nothing looks different.

Freeze Rendering lets you peek inside. Press Ctrl + Shift + O during play and the list of things being rendered freezes at that instant. Typing FreezeRendering in the console does the same thing.

After Freeze Rendering, pulling the camera back reveals blank space where geometry outside the frozen view used to be

Pull the camera back while frozen and only what was being rendered at freeze time remains; everything else is blank. You should see objects behind walls simply missing. That's occlusion culling doing its job.

Press Ctrl + Shift + O again to unfreeze.

For the numeric view, use stat initviews. It shows how many primitives were processed in a frame and how many were excluded by frustum and occlusion tests. Look at Frustum Culled Primitives and Occluded primitives. If the excluded percentage is low, it's time to revisit your occluder placement or add distance culling.


How Nanite Fits In

In UE5, Nanite takes over part of this story. But it doesn't replace all of it, and misreading that gap leaves gaps in your setup.

ItemDoes Nanite handle it?
LOD for Static MeshesYes (no manual LOD authoring needed)
LOD for Skeletal MeshesSupport improved in 5.5, but traditional LODs are still the norm
Meshes with translucent materialsNo (not Nanite-compatible; needs LODs)
Frustum cullingYes (Nanite culls internally at cluster granularity)
Occlusion cullingYes (same)
Cull Distance Volume / draw distanceNo. You decide the display distance yourself

In other words, enabling Nanite doesn't take distance culling off your plate. And characters and foliage (translucent or masked) still need traditional LODs. Nanite's mechanics and limitations are covered in detail in Handling High-Poly Meshes with Nanite.


Hands-On: Cutting Draw in a 3,000-Tree Scene

An open-world forest, a large RTS map, a survival game base. Placing the same asset in bulk shows up in every genre. Here we'll build a heavy forest and actually bring Draw down.

Bar chart showing Draw dropping from 14.6ms to 5.1ms, next to the two fixes: adding LODs and placing a Cull Distance Volume

Setting Up the Repro

ItemSetting
LevelFile → New Level → Basic
Mesh to placeOne Static Mesh with roughly 8,000 triangles (start with no LODs and Nanite off)
Count3,000 instances
Placement areaRandomly within a circle of radius 20,000uu (200 meters)

The fastest way to place them is a Spawn Actor from Class loop running 3,000 times from BeginPlay in the Level Blueprint. Leave Nanite off deliberately (turning it on hides the effects this article demonstrates).

Step 1: Measure the Current State

Launch with Standalone Game, position yourself so the forest is in view, and run stat unit.

Frame:  15.10 ms
Game:    2.30 ms
Draw:   14.62 ms
GPU:     9.80 ms

Draw at 14.62ms is the largest. The CPU is writing 3,000 draw commands, which is exactly the symptom of too many things to draw.

Also run stat scenerendering and note the Mesh draw calls count. It should be around 3,000.

Step 2: Add LODs

Open that mesh in the Static Mesh Editor, set Number of LODs to 4 under LOD Settings, and press Apply Changes.

Measure again in Standalone Game.

Frame:  11.20 ms
Game:    2.28 ms
Draw:   14.10 ms
GPU:     4.90 ms

GPU dropped by half, from 9.80ms to 4.90ms. Distant trees were replaced with simplified meshes, so there are fewer triangles to shade.

Meanwhile Draw barely moved (14.62 → 14.10ms). LOD reduces triangles, but it doesn't reduce the number of draw commands. There are still 3,000 trees, and all of them are still being drawn. That's LOD's limit, and why you need the next fix.

Step 3: Place a Cull Distance Volume

In the Place Actors panel (Window → Place Actors), search for "Cull" and drag a Cull Distance Volume into the level.

Scale the volume so it encloses the whole forest (set X / Y / Z in Brush Settings to around 45,000 each) and add this single row to Cull Distances in the details panel.

SizeCull Distance
50012000

The trees have bounds of roughly 500uu, so this drops them from rendering at 120 meters.

Measure once more in Standalone Game.

Frame:   6.40 ms
Game:    2.25 ms
Draw:    5.14 ms
GPU:     3.60 ms

Draw fell from 14.62ms to 5.14ms. Mesh draw calls in stat scenerendering should have dropped from around 3,000 to around 1,000. Frame went from 15.10ms to 6.40ms, which is well past 60 FPS and closer to 150.

Step 4: See It With Your Own Eyes

Stand in the middle of the forest during play, press Ctrl + Shift + O, and pull the camera straight up. You'll see that the trees beyond 120 meters simply don't exist. That's what's saving you nine milliseconds of Draw right now.

Then walk the player around. If you see trees popping in ahead of you, raise Cull Distance to 15000, then 18000, until you find a distance you don't notice.

If it isn't working, here's how to narrow it down.

  • Draw didn't drop → the Cull Distance Volume isn't enclosing the trees. Check its size. Only actors inside the volume get culled
  • All the trees vanishedCull Distance is too small, or the Size row doesn't match the trees' bounds. Try a row with Size set to 0 (applies to everything) to isolate the issue
  • GPU didn't drop → LODs weren't generated. Check with Mesh LOD Coloration that the colors change
  • Freeze Rendering does nothing → make sure you're running in PIE or Standalone, not the editor viewport

Two things to take away.

  • LOD hits GPU, culling hits Draw: remember this mapping and your stat unit results tell you which fix to apply. High GPU means LODs and materials; high Draw means culling and instancing. In the hands-on above, neither fix alone would have saved nine milliseconds
  • Decide cull distances by walking around: on paper, shorter is always better, but pop-in wrecks immersion. After tuning the numbers, always walk the level to confirm

To push Draw further, the next step is Instanced Static Mesh or Hierarchical Instanced Static Mesh, which draw many copies of the same mesh in one command. And the completely different angle of "don't load it into the level at all" is covered in Level Streaming and World Partition.

Sponsored

Bonus: Good to Know for Later

Many copies of one mesh can be drawn together. When you're placing hundreds or thousands of the same mesh — trees, rocks — you can collapse the draw commands into one (→ Cutting Draw Calls with Instanced Static Meshes). It combines with culling.

Every material slot adds a draw command. A mesh with five material slots means five draw commands. Consolidating slots while modeling background assets pays off in Draw. Cut your 3,000 trees from two slots to one and you've removed 3,000 draw commands.

Shadows are drawn too. An object casting a shadow from a dynamic light gets drawn a second time for the shadow pass. Turning off Cast Shadow on distant objects, or tightening the light's Dynamic Shadow Distance, reduces cost with almost no visual change.

Auto-generated LODs are usually good enough. For background assets, the LODs produced by Apply Changes hold up in production. Hand-authoring LOD meshes is only worth it when a broken silhouette would be obvious, like on straight-edged architecture.

Hierarchical Level of Detail (HLOD) is the next tier up. It replaces multiple distant actors with a single merged mesh. On World Partition levels, it's part of the standard toolkit (see Level Streaming and World Partition).

Run r.VisualizeOccludedPrimitives 1 to display wireframes where occlusion-culled objects are. It's a quicker way than Freeze Rendering to check what's currently hidden.


Summary

TechniqueWhat it doesNumber it movesWhat to do
LODSwaps distant objects for simpler meshesGPUSet Number of LODs, or pick a LOD Group
Frustum cullingSkips what's outside the viewDrawAutomatic. Check that bounds aren't abnormally large
Occlusion cullingSkips what's behind geometryDrawAutomatic. Place large occluders in your level
Distance cullingSkips what's far awayDrawCull Distance Volume or Desired Max Draw Distance

The mapping is the thing to remember. LOD hits GPU, culling hits Draw. Check which is larger with stat unit, then decide which fix to apply.

Your verification tools are Ctrl + Shift + O (Freeze Rendering) and stat initviews. Culling leaves no visual trace when it works, so you have to confirm it separately.

So far this has all been about not drawing what's already in the level. Next we step up a level and look at not loading it into the level at all (see Level Streaming and World Partition).

Try pressing Ctrl + Shift + O in your own level and pulling the camera straight up. More may already be getting culled than you expected.

Further Reading