Ilya Seletsky - Real Time Occlusion Culling



Powered by illEngine
(As of 3/21/2013, good luck compiling it...)

Occlusion Culling, figuring out what not to draw...

This map was made by putting together modular set peices and arranging them to form this structure. In other words, it's a mesh soup. Each peice of the map is some mesh with its own transform, and is organized in a 3D uniform grid. (My only regret is I didn't have time to texture all the objects, all the color comes from the lighting)

Occlusion Queries On Occlusion Queries Off

This shows the scene from two points of view. The bottom portion shows which objects are being rendered in the top view. It's a bit hard to tell what's going on from still images, and the video shows it better. View frustum culling is used in both situations, but the left image shows occlusion queries being used as well to filter out even more objects. With occlusion culling off, you are effectively drawing the entire level at certain camera angles, reducing performance dramatically.

The following is another point of view showing the camera looking down a shaft joining two floors. Notice how things on the floor below are occluded as well.

Occlusion Queries On Occlusion Queries Off
Occlusion Queries On Occlusion Queries Off

To make this work, I'm traversing the uniform grid front to back with the view frustum. For each cell I issue a hardware occlusion query whose results will be used next frame. If the cell was visible last frame, I add objects inside it to the render queue. Objects can pop in a frame late, which shouldn't be noticeable when the frame rate is high. I myself can't see objects popping in a frame late when I turn around quickly. I only see things popping in if I'm clipping through walls, which you shouldn't let the player do in a game anyway since they'll see a lot of really ugly stuff.

This approach allows for dynamic environments. This means everything is fully destructible, editable, moveable, modifiable, etc... in real time. This can be used not only for games, but for CAD programs and map editors where designers will be constantly moving objects around. Games of the past precomputed visibility statically using complex algorithms. This approach is not only useful in modern games, but accessible to most indie game developers who don't feel like writing BSP tree computation tools. (Not that you'd want to if you're trying to make a destructible environment)

Modern games like Crysis and Battlefield 3 do their visibility similarly to my approach only they have super smart engineers who wrote extremely optimized software rasterizers to perform their occlusion queries. They do this to help get around the CPU latency that happens when waiting for the GPU to send occlusion query results back to the CPU. Using the query results next frame like in my approach helps with that at the cost of objects popping in a frame late, which again, is unnoticeable.

References

Fast and Simple Occlusion Culling using Hardware-Based Depth Queries
Dynamic Scene Occlusion Culling using a Regular Grid
Doom Engine Review
GPU Gems Chapter 29. Efficient Occlusion Culling
Battlefield 3: Culling The Battlefield
Cry Engine Technical Docs: Culling Explained
Unreal Engine 3 Docs: Visibility Culling