How is visibility calculated?

How does the engine calculate which parts of the world are rendered and which parts are not?

I’m coming from the Source engine and understand VIS blocks and leaves. However browsing the docs & tutorials I wasn’t able to find an answer. Help/links towards an answer appreciated.

There are several types of culling. Two main ones are automatic and a third is probably similar to VIS blocks (although I am honestly not very familiar with those).

The most basic is obviously frustum culling, which culls any objects whose bounding box doesn’t intersect with the camera frustum. That isn’t always great since objects with large bounds tend to always intersect the camera when you have a small densely meshed level.

There is an additional kind of culling that works by doing a set of traces to each bounding box to determine culling based on occlusion. Ie, a mesh on the other side of the wall will be occluded by the wall, assuming the bounds were totally occluded.

There is also another kind of occlusion called “Precomputed Visibility Volumes” defined by placing a volume in the level. What those do is replace the traced occlusion culling with a sort of 3d grid where each grid point in 3d space stores a list of actors that were visible. So in that case you lighten much of the processing burden on the hardware since it is easier to just get a list of meshes and hide them than it is to trace to every object in the scene. But it takes more memory so it is a trade-off only worth making in some cases. You can dial in the size of the 3d grids to tweak the memory/performance ratio. Smaller grid sizes take more memory but can potentially occlude more accurately.