Quick answer: OcclusionPortal needs baked PVS data to do its job. Mark surrounding walls as Occluder Static, mark hidden objects as Occludee Static, then bake occlusion. Toggle OcclusionPortal.open to control visibility through the portal. Without a bake step, the portal does nothing.

Here is how to fix Unity OcclusionPortal components that do not actually cull anything when closed. You add a portal at a doorway, code that sets portal.open = false when the door shuts, but the room beyond keeps rendering at full cost. Frame Debugger shows every object inside the closed room still being drawn. The fix is almost always missing baked occlusion data — OcclusionPortal does not work standalone.

The Symptom

An OcclusionPortal component is on a door GameObject. portal.open toggles correctly in the inspector. But objects on the other side still render even when closed. stat batches shows no reduction. The Occlusion Culling window shows the scene as “Not Baked” or with stale data.

What Causes This

No baked occlusion data. OcclusionPortal works only as part of Unity’s baked occlusion culling system. Without baking, the portal has nothing to cull through.

Static flags missing. Surrounding walls must be Occluder Static; objects to be hidden must be Occludee Static. Dynamic objects can be culled by portals only if a static occluder defines the volume.

Portal positioned incorrectly. The portal’s box must completely span the gap (doorway). Gaps around the edges leak visibility.

Stale bake after scene changes. Adding or moving static geometry invalidates the bake. Without re-bake, runtime culling uses old data that may not match the current scene.

The Fix

Step 1: Mark walls Occluder Static. Select all walls around the door. In the inspector, click Static dropdown and enable Occluder Static. Walls block visibility for the bake.

Step 2: Mark hidden room contents Occludee Static. Select the renderers inside the room you want to hide. Set their Static flag to Occludee Static (and not Occluder unless they should also block). Dynamic objects (NPCs, the player) can still be culled at runtime if the static topology is sound.

Step 3: Add the OcclusionPortal at the door. On the door GameObject, add the OcclusionPortal component. Resize its Center/Size box to span the doorway exactly. Sketch it slightly larger than the visual frame; gaps cause leaks.

Step 4: Bake occlusion. Open Window → Rendering → Occlusion Culling → Bake. Click Bake. Wait for completion. Confirm the scene’s baked data updates by viewing Visualization while moving the camera; objects on the wrong side of the closed portal should disappear.

Step 5: Toggle from script.

using UnityEngine;

[RequireComponent(typeof(OcclusionPortal))]
public class DoorOcclusion : MonoBehaviour
{
    private OcclusionPortal portal;

    void Awake() { portal = GetComponent<OcclusionPortal>(); }

    public void SetDoor(bool isOpen)
    {
        portal.open = isOpen;
        // Also toggle the visual mesh, animations, audio, etc.
    }
}

open = true means visibility passes through (door open). open = false means the portal blocks (door closed).

Common Mistakes

Adding OcclusionPortal but forgetting Static flags — the most common cause. Without static markers, the bake has nothing to occlude. Result: portal toggle does nothing.

Marking the door itself as Occluder Static. The door is a moving object; it cannot participate as a static occluder. Use OcclusionPortal instead.

Forgetting to rebake after moving walls. The bake snapshots geometry; subsequent moves are not reflected.

When To Use Other Approaches

OcclusionPortal works well for static buildings with discrete doors. For procedurally generated levels or open worlds, baked PVS is impractical. Consider:

“OcclusionPortal is a runtime toggle on top of baked PVS. Without the bake, there is nothing to toggle.”

Related Issues

For occlusion not working at all, see Occlusion Culling Not Working. For LOD issues, see LOD Group Not Switching.

Static flags. Bake. Then portal.open works.