Table of Contents

    What Is Occlusion Culling and Why Does It Improve FPS?

    Imagine standing in front of a massive castle wall in an open-world RPG. You only see the stone wall. However, behind it sits a bustling marketplace full of stalls, props, and characters. Without optimization, the engine still processes and sends all that hidden geometry to the GPU. This wasted effort creates rendering overhead, leading to low frame rates on both mobile devices and PCs.

    This is where Occlusion Culling comes in. It is a rendering optimization technique that identifies which objects are completely hidden behind closer, opaque structures (like walls, hills, or buildings) and prevents the engine from drawing them. By skipping these hidden meshes, you reduce the workload on both the CPU and the GPU, yielding significant FPS improvements.


    1. Understanding the Rendering Pipeline: Frustum vs. Occlusion Culling

    Camera rendering relies on two visibility tests. The camera sees through a pyramid-like field of view called the camera frustum. Frustum Culling checks if an object is inside this shape; if it is behind the camera or off-screen, the engine discards it. This check is automatic and extremely cheap on the CPU.

    However, frustum culling does not check if objects block each other. If you stand in a dense forest, frustum culling attempts to render every tree in your line of sight, even if they are stacked deep behind the first row. Occlusion Culling solves this by analyzing depth to discard meshes hidden behind closer objects.

    Optimization Metric Frustum Culling Occlusion Culling
    Scope of Check Is the object inside the camera's viewing field? Is the object blocked from view by closer geometry?
    Engine Setup Automatic (no developer setup) Manual configuration (requires baking or setting volumes)
    CPU Cost Extremely low (fast bounding box checks) Moderate (evaluates depth buffers or grid cells)
    GPU Savings High (stops drawing off-screen models) Extreme (stops drawing overlapping geometry)
    Ideal Environment All scenes (open worlds, space) Dense scenes (corridors, cities, forests, interiors)

    2. How Occlusion Culling Works

    Occlusion culling categorizes objects into two roles:

    • Occluders: Solid, opaque blocking structures (terrain, walls, buildings).
    • Occludees: Props that can be hidden behind occluders (furniture, debris, loot chests). Some large objects can act as both.
    The Cardboard Screen Analogy
    Think of rendering as drawing a landscape. If you place a cardboard screen (occluder) in front of an apple (occludee), you cannot see the apple.

    Frustum culling checks if both are in front of you. If they are, it tells the engine to draw the apple and then paint the cardboard over it. Occlusion culling checks depth first, realizes the apple is blocked, and discards it before drawing begins.

    3. Types of Occlusion Culling

    Engines use three primary strategies to evaluate visibility:

    Hardware Occlusion Queries

    The CPU queries the GPU: "If I render this bounding box, will any pixels pass the depth test?" If zero pixels pass, the object is occluded.
    Pros: Dynamic and highly accurate; no pre-computation needed.
    Cons: Waiting for the GPU to return results causes latency (CPU-GPU sync stalls), which can hurt frame rates on older hardware.

    Software Occlusion Culling

    To avoid GPU sync stalls, the CPU rasterizes a low-resolution depth buffer containing only the largest occluders, and checks bounding boxes against it.
    Pros: Bypasses GPU query overhead; ideal for mobile platforms where GPU queries are slow.
    Cons: Uses CPU threads that could otherwise handle physics or AI.

    Precomputed / Baked Occlusion Culling

    The engine divides the level into 3D cells and pre-calculates visibility data offline. At runtime, the engine checks which cell the camera is in and loads its visibility list.
    Pros: Extremely cheap runtime CPU check (simple array lookup).
    Cons: Only works for static objects; increases game build sizes and memory footprint.


    4. Why It Improves FPS: The Math of Rendering Savings

    Pairing occlusion culling with standard rendering reduces bottlenecks across the entire pipeline:

    • Draw Calls (CPU): If a scene has 1,200 props and a wall blocks 1,000 of them, the CPU only prepares 200 draw calls instead of 1,200, saving valuable frame time.
    • Vertex Processing (GPU): Drawing only visible props cuts the vertex shader workload from millions of polygons to a fraction, saving GPU memory bandwidth.
    • Overdraw (GPU): Skipping hidden objects avoids rendering overlapping layers of pixels, reducing fill-rate limitations, particularly on mobile chipsets.
    Pipeline Phase Without Culling With Culling Performance Gain Type
    CPU Main Thread Processes visibility for all 1,200 meshes Processes visibility for 200 meshes Saves CPU time for game logic and scripts
    Graphics API Submits 1,200 draw calls to driver Submits 200 draw calls to driver Saves driver translation time (prevents stalls)
    GPU Vertex Stage Computes math for 2.4M polygons Computes math for 400K polygons Saves vertex shading and pipeline capacity
    GPU Pixel Stage High overdraw and depth sorting waste Low overdraw (renders visible surfaces) Reduces VRAM bandwidth and thermals

    5. Setting Up Occlusion Culling in Unity

    Unity uses Umbra for baked occlusion culling. To configure it:

    1. Select static blocking meshes in the hierarchy. In the Inspector static dropdown, check **Occluder Static** and **Occludee Static**. For smaller props, check **Occludee Static** only.
    2. Open the panel: Window > Rendering > Occlusion Culling.
    3. In the **Bake** tab, adjust parameters:
      • Smallest Occluder: Min size of an object that can block others. Smaller values increase bake file size.
      • Smallest Hole: Min gap the camera can see through.
    4. Click **Bake**.
    5. Switch the Scene View dropdown to **Occlusion Culling** and select your Main Camera to visualize objects disappearing as they are blocked.

    6. Setting Up Occlusion Culling in Unreal Engine

    Unreal Engine uses dynamic hardware occlusion queries by default. To optimize visibility checks:

    Precomputed Visibility Volume

    For mobile and low-spec hardware, bake visibility cells:

    • Place a **Precomputed Visibility Volume** covering the player's movement area.
    • Ensure **Precomputed Visibility** is checked in World Settings.
    • Click **Build Lighting** to bake cells.

    Verification Console Commands

    Open the in-editor console (tilde key `~`) to profile culling:

    • r.VisualiseOccludedPrimitives 1: Outlines occluded meshes in green.
    • stat InitViews: Displays counters, including **Occluded Primitives**, showing how many actors are successfully culled.


    7. Common Pitfalls and Performance Costs

    Be aware of these potential performance bottlenecks and setup issues:

    • CPU Baking Overload: Setting "Smallest Occluder" too low generates excessive cells, making visibility lookups cost more CPU time than drawing the meshes.
    • Baking Size Bloat: Large worlds baked with detailed culling parameters can add hundreds of megabytes of data to your build size.
    • Pop-in Artifacts: Hardware occlusion delays can cause hidden meshes to visibly snap into view when you turn corners quickly. Use larger occluders to mask transitions.
    • Dynamic Environments: Baked occlusion is static. An open door marked "Occluder Static" will continue to cull the room behind it, creating empty rendering voids.

    8. Best Practices for Game Developers

    Follow these rules to maximize rendering optimization:

    1. Design Winding Paths: Create levels with corners, curves, or large walls to maximize occlusion opportunities. Long, straight corridors offer no culling benefits.
    2. Mark Sparingly: Only mark large, structural meshes (walls, hills, houses) as occluders. Small objects (cups, rocks) should be occludees only.
    3. Pair with LODs: Occlusion culling hides close objects behind walls, while LODs optimize visible objects in the distance. Use both together.

    Frequently Asked Questions

    1. Does occlusion culling reduce polygon count?
    It does not change mesh details, but it reduces the total count of rendered polygons on screen by disabling hidden meshes.
    2. Can dynamic objects act as occluders?
    In baked systems (like Unity's), only static objects can act as occluders. Dynamic systems (like Unreal's) allow it, but doing so increases GPU query costs.
    3. Why do meshes pop in when turning corners quickly?
    This is culling latency. The GPU takes a frame to return visibility query results, causing delayed rendering when turning. Use larger occluders to mask corners.
    4. What is the difference between Occlusion Culling and Overdraw?
    Overdraw is drawing overlapping layers of pixels. Occlusion culling is the check performed beforehand to discard hidden meshes and prevent overdraw.
    5. Should I mark small props as occluders?
    No. Small props do not block enough geometry to justify the visibility check CPU cycles. Mark them as occludees only.
    6. Does occlusion culling work with transparent shaders?
    No. Transparent objects do not write depth information, so they cannot act as occluders, though they can be culled behind opaque walls.
    7. Does occlusion culling affect CPU or GPU performance more?
    Both. The CPU prepares fewer draw calls, while the GPU processes fewer vertices and pixels. However, visibility checks add minor CPU calculations.
    8. What happens if I set "Smallest Occluder" too low in Unity?
    It creates too many visibility cells, bloating the build size and increasing runtime CPU lookup overhead, which can degrade performance.
    9. Does Unreal Engine's Nanite support occlusion culling?
    Yes. Nanite performs culling at the cluster level directly on the GPU using compute shaders, bypassing the standard CPU culling checks.
    10. Can I use occlusion culling in 2D games?
    Typically, no. 2D engines do not use a 3D depth buffer. Instead, visibility is managed via viewport culling or custom code layers.

    Comments