Occlusion Culling
The frustum answers is it in front of the camera. Inside a building, a town or a
canyon, most of what survives that question is still invisible: a wall is in the
way. Occluder lets you say which boxes sight does not pass through, and the
renderer then stops collecting anything standing behind one.
world.insert(wall, Occluder, { halfExtents: { x: 400, y: 300, z: 20 } });That is the whole component. It changes what a frame costs and never what it shows — the picture with occluders and the picture without them are the same pixels.
The box is authored, and it belongs inside the wall
Section titled “The box is authored, and it belongs inside the wall”An occluder is not taken from the geometry beside it, and the reason is worth knowing: a mesh’s bounds contain the mesh. A bounding box around a pillar, an archway or a rock claims the empty air at its corners, and anything standing in that air would stop being drawn while the player can plainly see it.
So the rule is the opposite one:
Placing it:
halfExtentsis in world units, measured from the entity’s position, and the entity’s rotation turns it. Scale is not read, the same as every other extent in the engine.- The editor draws the box in the viewport, so you can size it against the wall it is inside of.
- It can sit on the wall’s own entity, or on an empty entity of its own — a building made of many meshes usually wants one big box rather than one per mesh.
What it culls, and what it leaves alone
Section titled “What it culls, and what it leaves alone”Only draws a depth test would have hidden anyway. An object that ignores depth paints over the wall in front of it, and culling it would remove something the frame really does show — so sprites, UI, text and any surface whose material turns the depth test off are never refused by an occluder.
It is also a camera’s answer, not the scene’s:
- Two cameras in one frame each ask their own occluders.
- Shadows are not culled by it. What the player cannot see still casts; a caster dropped because the camera cannot see it would take its shadow off the ground with it.
- An occluder the camera stands inside is ignored, rather than declaring the whole view blocked.
Reading what it did
Section titled “Reading what it did”Three counters in the Profiler, and each answers a different question:
| counter | says |
|---|---|
render.cull.occluders |
how many boxes this view took |
render.cull.occluded |
how many renderables an occluder refused |
render.culled |
every cull, the frustum’s included |
A scene whose occluders stopped working shows it in the first two: zero boxes means they were never taken (turned past the near plane, or authored to nothing), while boxes taken and nothing occluded means they are not in front of anything.
How much it can claim
Section titled “How much it can claim”The test runs on a small grid — about a sixty-fourth of the view across — and a box only claims a cell of it that it covers whole. Two consequences worth designing around:
- An occluder smaller than roughly 2% of the screen hides nothing. Big shapes are what pay: walls, floors between storeys, buildings, cliffs.
- An object that is hidden by the combination of two walls with a gap between them is still drawn. Each box answers for itself.
What this is not
Section titled “What this is not”Occluder is about what is in the way. It does not unload anything — see
streaming for that — and it does not simplify what is drawn,
which is LODGroup. The three compose: streaming
decides what exists, occlusion decides what is collected, LOD decides how much
geometry the survivors cost.