keywords: UE4, Occlusion Culling, 遮挡剔除, 场景优化, Scene Optimization, Distance Culling, View frustum, Precomputed Visibility, Dynamic Occlusion

Working principle of Occlusion Culling

Original: How does object occlusion and culling work in UE4?
https://answers.unrealengine.com/questions/312646/how-does-object-occlusion-and-culling-work-in-ue4.html

Unreal Engine 4 uses an automatic process for culling that uses Scene Depth and the bounds of an object.
When using the Wireframe viewmode, this is not a good method for testing if an object is occluded in UE4. You can use the (Editor only) console command r.visualizeOccludedPrimitives 1 to view the occluded objects. This will render a green bounds box for any objects that are occluded. Adjusting the bounds scale will increase the green bounding box and can cause the mesh to be rendered even when it’s not in view.
In the project settings you can disable Occlusion Culling completely if you need, but in most cases this is not needed.
There is an alternative method of occlusion in the engine that is not on by default. It’s less strict than the currently default method. You can enable this by using the console command r.HZBOcclusion 1
This uses an approximation with occlusion culling. It will occlude the mesh dependent more on size and bounds scale than strictly on bounds scale. This can be useful in some instances, but problematic in others where it would cause meshes to be rendered that you wouldn’t necessarily wan to be when hidden. This is largely why it’s not on by default at the moment.
Using the first console command above is the best solution right now for debugging what’s being occluded and what’s not for the time being.

Origin: Performance boost on UE4 games for Radeon users - guru3d
HZB Occlusion is a technique supposed to increase performance is a method of rasterizing certain portions of a scene into a depth buffer and then performing image-space occlusion queries on a hierarchical structure constructed from the depth buffer.
In any realistic 3D scene, there are things you can see and things that you can’t see. It sounds simple, but the application of this knowledge can have very beneficial effects on the performance of an application billed with rendering the 3D scene in real time.
Generally, we want to lower the computational cost of objects that do not contribute to the scene - those objects that are outside our field of view or are obscured by other objects. The Z-buffer is the last stage in the rendering pipeline where an object can be identified as “invisible”; in this case, the object in question is a fragment, and it can only be identified as invisible when the fragment’s depth value is “deeper” than something that has already been rendered at the same raster position.
The Z-buffer test is invoked for each and every fragment of a higher-level object being rendered - the polygonal representation of a “thing” in the scene, such as a person, a wall, a car, etc - and thus imposes a rather high computational cost of visibility determination, even with recent optimizations made to hardware z-buffer mechanisms.

Occlusion Culling switch

Global Switch(In Editor):
Project Settings -> Engine -> Rendering -> Culling -> Occlusion Culling. It’s checked by default.

Local Switch(for single Primitive):
Details Panel of Mesh -> Rendering -> LOD -> Never Distance Cull, false by default.
This property in C++ is UPrimitiveComponent::bNeverDistanceCull.

Mask material only in early Z-pass

Whether force early Z to be turned on for the mask material?

In order to reduce the computing of depth pass (belonging to PrePass in UE), UE4 will decide whether to turn on the Early Z pass of the mask material based on the hardware characteristics. This causes some machines (especially Android devices) to automatically turn off the Early Z pass of the mask material, but this The overdraw of pixel pass (belonging to BasePass in UE) will be greatly increased.

It’s necessary to test whether Early Z has a net gain on performance in the different scenario, the console command for testing (needs to be restarted, runtime switching is not supported):

[/Script/Engine.RendererSettings]
; default is 3
r.EarlyZPass=2
; default is false
r.EarlyZPassOnlyMaterialMasking=True

The switches in settings:Project Settings -> Rendering -> Optimizations:

  • Early Z-pass
  • Mask material only in early Z-pass

You can also check if occlusion culling works using console:

r.visualizeOccludedPrimitives 1

For more details, see:Effects and mechanism of Mask Material only in Early Z-pass

Documents

Visibility and Occlusion Culling
https://docs.unrealengine.com/en-US/Engine/Rendering/VisibilityCulling/index.html

Understanding Culling Methods | Live Training | Inside Unreal
https://www.youtube.com/watch?v=6WtE3CoFMXU

Culling in UE4/UE5 (Precomputed Visibility Volumes, and Cull Distance Volumes) (Recommended)
https://www.chrismccole.com/blog/culling-in-ue4ue5

Software Occlusion Queries for Mobile - UnrealEngine Official Docs

Occlusion Culling in UE5

CPU based Occlusion Culling

UE5 discarded software occlusion culling (CPU-side) and use HZBO (GPU-side) by default.
Port and extend the UE4 Occlusion Culling system to UE5 - LinkedIn
Software Occlusion Culling for UE5 - github

Issues

Occlusion Culling doesn’t work

Origin: Occlusion Culling doesn’t work
https://answers.unrealengine.com/questions/458450/occlusion-culling-doesnt-work.html

Dynamic occlusion is on by default and does a pretty good job when given the opportunity. Unless all your static meshes are all one single mesh then occlusion is working.

You can test this by using the console command r.visualizeoccludedprimitives 1. This will create a green bounding box around the actors that are occluded. This will work only while working in the editor and not while in PIE/standalone game modes. Alternatively, you can use the console command freezerendering to toggle the current rendering state. Move the camera to outside of the are where it’s suppose to occlude the actors behind it. Use the console command and then you’ll see Rendering Frozen in the top left of the screen. You can now freely move the camera around the scene and it will have frozen/paused the actors at their current rendering state. So if they were occluded and not being rendered they will not be visible when you move the camera behind you walls that were occluding them.

This is a good method to start troubleshooting your occlusion issues. You can also use the console command Stat Initviews while in PIE/Standalone game and look at the counters at the bottom. Follow the stat for Visibile Satic Mesh Elements. This number should rise and lower depending on the number of Static Meshes that are visible in the viewing area.

Lastly, for Precomputed Visibility Volumes, this is a static, offline, way of handling occlusion. There are some caveats to using it, but overall it can be used. Before investigating adding it to your game I would instead troubleshoot and narrow down the issues regarding your issue with dynamic occlusion before moving to something else.

There is some documentation that is being worked on for Visibility Culling, Precomputed Visibility Volumes, and Cull Distance Volumes that will be available hopefully in the not too distant future.

If your still having issues or something I said doesn’t make sense feel free to post back here.


六盘山上高峰,红旗漫卷西风。今日长缨在手,何时缚住苍龙? ----毛泽东《清平乐· 六盘山》