A demonstration of volume-intersect ambient occlusion

Volume-intersect Ambient Occlusion

While creating a new environment for Impaler, I devised a new way to approximate ambient occlusion. The result is computationally cheap, pleasing to the eye, and builds off ideas from my last post. It works by comparing the volume of a cube with the volume shared between the cube and environment (intersection of the cube and environment). The ratio between the two volumes is then used as an occlusion factor.

Quick refresher: Ambient occlusion is a technique for applying self-shadowing to environments and objects.


How It Works

Volume-intersect AO calculates how much unobstructed volume exists in front of a given point. Points with a lot of nearby “stuff” will have a small obstruction-free volume and be considered more occluded.

Pseudocode:

  • place an AABB (axis-aligned bounding box) at the world position of the current fragment
  • offset the AABB in the direction of the surface normal by 1/2 its size
  • sum the volume of intersections between the AABB and nearby world geometry
  • calculate the ratio between the total intersect volume and the sample AABB volume
  • repeat N times - each with a smaller sample AABB
  • [OPTIMIZATION] early return, when the intersect volume is zero (subsequent samples will also be 0)
  • sum & weight results (high values are more heavily occluded)
  • shade pixel

Sampling Visualized:

Visualization of the variable-sized sample volume The yellow cubes are the “sample volume” at various sizes. Notice how the big samples have significant intersections with the environment (and therefore contribute more to occlusion).


Limitations

Similar to the approach in my last post, this technique requires sharing environment data with the fragment shader. This will limit its use to simple environments like those in Impaler. Adapting the approach to work with other geometries (spheres?) may be possible. However, calculating intersections may be too expensive. Being limited to AABBs is arguably the biggest issue with this technique.


Computation / Performance

  • requires no texture reads
  • looks good with as few as 5 samples
  • AABB <> AABB intersection calculations are cheap
  • the early return optimization makes un-occluded fragments almost free

Overall, the performance is very good for simple scenes with few occluders.


Live Example

The code for the example above can be found here on Shadertoy.


Using It In a Game?

The next Impaler update will include an implementation of Volume-intersect AO. Check it out below.