A screenshot of Impaler's faux ambient

Faking Ambient Occlusion

Impaler is a small game I created with the goal of making it run on integrated graphics cards while still looking visually appealing. I had to find creative ways to fake expensive graphics techniques to achieve this. Anything that relied on sampling or multiple render passes would be too heavy for low-end GPUs. This meant I had to find a new approach to implement ambient occlusion.


Background on Ambient Occlusion

Ambient occlusion, often abbreviated AO, is a graphics technique for self-shadowing. It estimates how much ambient light is blocked by nearby geometry and adds a soft shadow to those areas. It has a large impact on the visual quality of a scene.

Screenshot of Crysis Crysis (2007) was one of the first games to incorporate AO. It still looks good today!


Common AO Implementations

Screen space ambient occlusion (SSAO) and horizon-based ambient occlusion (HBAO) are commonly found in games today. These approaches perform calculations in screen space and do not slow with complex scenes. They work well for just about any game and produce convincing results. However, each fragment samples the depth buffer multiple times. This can be too expensive for low-end hardware with integrated graphics cards. A different approach would be required for Impaler.

In the future, screen space AO may be less common as games adopt ray tracing and global illumination models. These are the best-looking solutions. Screen space effects can suffer from under-sampling and artifacts at the edges of the screen.

Screenshot of Quake 2 RTX Quake 2 RTX (2019) Features real-time ray tracing and global illumination. Indirect lighting and shadow are calculated via ray tracing.


Why Did Impaler Need AO?

The game takes place in a dark cathedral-like arena. Without proper light and shadow, it simply does not create the illusion you are there. It is ugly and has a “flat” look remiscient of early 3D games.

Screenshot of Impaler with ambient occlusion forced off Impaler (2022) without AO. Note how the scene is overly bright and the corners are hard to identify.

The environment is simple - a large rectangle with 6 columns and game objects scattered throughout. Only a few areas in the world need self-shadowing.

  • corners of the arena
  • edges between walls and the floor
  • bases of the stone columns

How It’s Done

Since ray tracing and screen space effects are too expensive, I needed an alternative approach. The solution was to perform calculations in world space and share the scene’s geometry with the shader. Instead of sampling the depth buffer, a numeric approximation would estimate occlusion based on promixity to occluders (e.g. corners). It’s not something that would work for most games, but a good fit for Impaler given the simple environment.

Pseudocode

  • pass the fragment shader a list of occluders and their geometry
    • line segments for boundaries between wall and floor
    • positions of the corners
    • axis-aligned cylinders representing the stone columns
  • for each fragment, evaluate the contribution from each occluder in world space
  • keep track of the largest occlusion value encountered - max() not sum()
  • modulate the ambient light intensity based on the largest occlusion value
  • shade the fragment using an occlusion-modulated ambient light term


GLSL


Impact on Visual Quality

The occluder-based approach works well - the scene brightness is reduced and the map features are easier to distinguish. It also has no visual artifacts related to undersampling. It does a good job representing the simple geometry of the environment. However, it would not work for more complex scenes. Nor is it physically correct.

Screenshot of Impaler with ambient occlusion enabled Animation of AO being toggled on and off

Animation comparing AO on and off


Closing

Real-time computer graphics is a balance between performance and visual quality. Finding a creative way to approximate this lighting effect was a good learning experience.

If you enjoy these posts and want to support my work, please consider buying my game on Steam.