-
Concept: Environment Map (IBL)
-
What Is an Environment Map?
- A texture that represents the radiance arriving from all directions in the scene
- Typically an HDR (high dynamic range) image — captures real-world lighting
- Used as the “sky” and distant lighting in a path tracer
- When a ray misses all geometry: sample the environment map
-
- Equirectangular (lat-long)
- Maps the sphere to a 2:1 rectangle
u = (atan2(dir.z, dir.x) / (2π)) + 0.5
v = acos(dir.y) / π
- Simple but has pole distortion (oversampled at poles)
- Cubemap
- 6 square faces (±X, ±Y, ±Z)
- No pole distortion, hardware-accelerated sampling
- Harder to importance sample
- Octahedral
- Maps sphere to a square via octahedral projection
- No distortion, easy to importance sample
- Used in some modern engines
-
Sampling the Environment Map
- Naive: sample random direction, look up environment map
- PDF:
p(ω) = 1 / (4π) (uniform sphere)
- High variance — most directions contribute little
- Importance sampling: sample proportional to luminance
- Build a 2D CDF from the luminance of each texel
- Sample row (θ) then column (φ) using inverse CDF
- PDF:
p(ω) = L(ω) / ∫L(ω)dω — proportional to luminance
- Dramatically reduces variance for scenes with bright sun/sky
- Building the 2D CDF
-
IBL (Image-Based Lighting) in PBR
- Split-sum approximation (Karis 2013, used in Unreal Engine)
- Precompute two terms separately:
L_IBL = ∫ f_r(ω_i, ω_o) L_i(ω_i) cos(θ_i) dω_i
≈ (∫ L_i(ω_i) D(ω_i, roughness) dω_i) * (∫ f_r(ω_i, ω_o) cos(θ_i) dω_i)
- Term 1: pre-filtered environment map (one mip per roughness level)
- Term 2: BRDF integration LUT (precomputed 2D texture)
- Pre-filtered environment map
- Convolve environment map with GGX NDF at each roughness level
- Store in mip chain: mip 0 = sharp (roughness=0), mip N = blurry (roughness=1)
- Sample:
textureLod(envMap, reflect(-V, N), roughness * MAX_MIP)
- BRDF integration LUT
- 2D texture indexed by
(NdotV, roughness)
- Stores
(scale, bias) for Schlick Fresnel: F_approx = F0 * scale + bias
- Precomputed once, reused for all materials
- This is an approximation — path tracing with environment map sampling is exact
-
In a Path Tracer
- Miss shader: sample environment map at ray direction
- NEE with environment map: sample a direction from the env map CDF
- Compute PDF in solid angle:
p(ω) = luminance(L(ω)) / total_luminance * (W*H) / (2π²*sin(θ))
- Trace shadow ray in that direction
- Apply MIS weight:
w = p_env² / (p_env² + p_brdf²)
-
.hdr (Radiance RGBE format) — most common, 8-bit mantissa + 8-bit exponent
.exr (OpenEXR) — 16-bit or 32-bit float, lossless, industry standard
.dds with BC6H compression — GPU-compressed HDR, used in games
- Loading in C++:
stb_image.h for .hdr, tinyexr for .exr