---
title: Horizon-Based Ambient Occlusion (HBAO)
url: https://www.emergentmind.com/topics/horizon-based-ambient-occlusion-hbao
type: topic
---

# Horizon-Based Ambient Occlusion (HBAO)

Horizon-Based Ambient Occlusion (HBAO) is a screen-space technique for approximating ambient occlusion (AO), essential for visually plausible global illumination in real-time rendering. HBAO analytically integrates local geometric occlusion by evaluating visibility across a hemisphere over the surface normal, traditionally reducing the AO integral to a series of horizon-angle slices. Recent advancements extend this framework with the introduction of a visibility bitmask, offering robust handling of thin geometry and multi-directional light probes with minimal performance overhead [2301.11376].

## 1. Classical HBAO Formulation

Let $V(p,\omega)\in\{0,1\}$ denote the binary visibility at point $p$ along direction $\omega$ on the hemisphere $\Omega^+$ above $p$. The ambient occlusion at $p$ is given by:
$$
A(p) = \int_{\Omega^+} V(p,\omega)\, (n_p\cdot\omega)\, d\omega
$$
Expressed in spherical coordinates $(\theta,\phi)$ about $n_p$:
$$
A(p) = \int_{0}^{2\pi} \int_{0}^{\pi/2} V(p,\theta,\phi)\,\cos\theta\,\sin\theta\,d\theta\,d\phi
$$
HBAO approximates this by dividing the integral into $M$ azimuthal slices $\phi_i$. For each slice, depth samples are taken outward to locate occlusion “horizons,” i.e., maximum and minimum elevation angles $(\theta_{min,i}, \theta_{max,i})$. The inner $\theta$ integral is then analytically computed over the non-occluded regions, yielding per-slice contributions:
$$
AO_2(\phi_i) = \frac{1}{2}(1 - \cos^2\theta_{min,i}) + \frac{1}{2}\cos^2\theta_{max,i}
$$
The AO is then assembled as
$$
AO(p) = 1 - \frac{1}{M\pi} \sum_{i=1}^{M} AO_2(\phi_i)\, 2\pi
$$
This reduction achieves $O(M\cdot N_s)$ complexity ($N_s$ = samples per slice), with each slice requiring storage of two angles.

## 2. Extension to Visibility Bitmask Representation

The core innovation of the “visibility bitmask” is to encode occlusion not as two horizon angles per slice but as an $N$-bitmask $B$ per slice, with each bit representing the occlusion state (occluded/un-occluded) of a sector. The hemisphere elevation $\theta \in [0, \pi/2]$ is uniformly partitioned into $N$ sectors, each mapped to bit indices $i=0\ldots N-1$. During the depth-marching, at each sample, both “front” ($s_f$) and “back” ($s_b = s_f - t\cdot v$, with $t$ a fixed thickness) points are projected. Their elevation angles $(\theta_f, \theta_b)$ define an occlusion interval $[\theta_{min}, \theta_{max}]$, which is mapped to sector indices $(a,b)$:
$$
a = \lfloor \theta_{min} / \Delta\theta \rfloor, \quad
b = \lceil \theta_{max} / \Delta\theta \rceil
$$
The corresponding bit pattern is formed by
$$
M_{sample} = ((1 \ll (b-a+1)) - 1) \ll a
$$
and OR’ed into $B$. After processing, $B$ reflects which sectors in the slice are occluded by any “slab” of thickness $t$. This discretized encoding naturally supports multiple non-contiguous occluded intervals, in contrast to the original two-angle model [2301.11376].

## 3. Ambient Occlusion Integral with Bitmask

Occlusion integration with the bitmask replaces analytic intervals by summing over sector midpoints:
$$
AO_2^{mask}(\phi) \approx \frac{1}{N}\sum_{i=0}^{N-1} b_i
$$
with $b_i = 0$ if occluded, $1$ if not. Full AO is assembled across slices:
$$
AO^{mask}(p) = 1 - \frac{1}{MN} \sum_{k=1}^M \sum_{i=0}^{N-1} b_i^{(k)}
$$
If the original $\cos\theta$ weighting is desired, precomputed per-sector weights $w_i$ may be used:
$$
w_i = \frac{1}{2}\left[ \cos^2\theta \right]_{i\Delta\theta}^{(i+1)\Delta\theta}
$$
$$
AO_2^{mask}(\phi) \approx \sum_{i=0}^{N-1} b_i w_i
$$
In most practical cases, uniform weighting suffices and incurs less computational overhead [2301.11376].

## 4. Real-Time Implementation and Pseudocode

Each pixel maintains $M\,\times\,32$-bit temporaries (for $N=32$), typically consuming 4–8 uint32 registers or shared-memory space. The GPU implementation per slice consists of:

1. Sampling $N_s$ points along the slice from the depth buffer.
2. For each, computing front/back angles, mapping to sector interval $[a,b]$, constructing the respective bitmask, and OR’ing into $B$.
3. After all samples, computing $\text{popcount}(B)$, a native single-GPU instruction, to count occluded sectors.
4. Calculating AO as $1 - \text{popcount}(B)/N$.

For indirect-diffuse GI, each sample’s contribution is tested against the already-occluded mask with $(M_{sample}\ \&\ \sim B) \neq 0$ before accumulation, ensuring unique lighting per visible sector. Pseudocode in the source paper outlines this per-pixel, per-slice workflow, covering both AO and single-bounce GI [2301.11376].

## 5. Quantitative Performance and Quality Metrics

Empirical results for a 1920×1080 RTX 2080 configuration are summarized in the tables below.

| Radius | Samples/half-slice | GTAO AO (ms) | Bitmask AO (ms) |
|--------|--------------------|--------------|-----------------|
| 0.8    | 8                  | 0.49         | 0.51            |
| 1.0    | 12                 | 0.75         | 0.77            |
| 1.0    | 16                 | 0.95         | 0.97            |
| 2.0    | 16                 | 1.12         | 1.13            |
| 3.0    | 16                 | 1.12         | 1.13            |

The bitmask overhead at $N=32$ is approximately 0.01–0.02 ms (∼2%), rising to 5–10% for $N=128$.

Indirect-diffuse GI performance:

| Config | Rays (slices×steps) | Resolution | Sampling (ms) | Denoise (ms) | Total (ms) |
|--------|--------------------|------------|---------------|--------------|------------|
| (a)    | 4×(8 const)        | full       | 0.90          | 0.33         | 1.23       |
| (b)    | 4×(8 const, r=4)   | full       | 1.70          | 0.33         | 2.03       |
| (c)    | 4×(16 const, r=4)  | full       | 2.30          | 0.33         | 2.63       |
| (f)    | 4×(16 exp, r=4)    | half       | 0.97          | 0.10         | 1.07       |

Comparative studies demonstrate reduced noise against SSR tracing at equal sample budgets (because each sample yields occlusion), fewer over-darkening “halos” around thin geometry, and AO visually close to ray-traced references—capable of capturing small-scale detail even at low sample counts. Multi-cone ambient occlusion improves the smoothness and directionality of shading over bent-normal approaches [2301.11376].

## 6. Thin Geometry Handling and Multi-Cone Ambient Lighting

Traditional HBAO construes the depth buffer as a height field, failing on light passing behind thin, disconnected features. The bitmask mechanism models each sample as a ground “slab” of finite thickness $t$, permitting light leakage through gaps if any sector remains unoccluded after all sample slabs are OR’ed. This multi-interval encoding is efficient, enables the capture of complex visibilities, and mitigates overdarkening near thin surfaces without resorting to deep G-buffer or stochastic approaches [2301.11376].

Moreover, the bitmask allows efficient sampling of ambient lighting in $K$ cones per slice. The $2\pi$ azimuth is divided into $K$ segments; per subrange, the unoccluded bit fraction weights the ambient probe in that direction. This generalizes bent normal lighting ($K=1$) to multi-directional probes, enabling robust, directionally-aware ambient shading with negligible added cost, as per-popcount operations suffice [2301.11376].

## 7. Summary and Significance

HBAO with visibility bitmask advances the state-of-the-art in real-time screen-space ambient occlusion and indirect illumination by discretizing the occlusion horizon into multiple sectors per view direction. It preserves $O(MN_s)$ sampling costs while supporting accurate modeling of thin geometry and multi-directional occlusions. The method’s generality extends to indirect diffuse and multi-cone ambient illumination, achieving visual results comparable to ray-tracing or multi-layer techniques but with the storage and performance footprint of classical HBAO [2301.11376].

Source: https://www.emergentmind.com/topics/horizon-based-ambient-occlusion-hbao