Module bevy::pbr::irradiance_volume
source · Expand description
Irradiance volumes, also known as voxel global illumination.
An irradiance volume is a cuboid voxel region consisting of regularly-spaced precomputed samples of diffuse indirect light. They’re ideal if you have a dynamic object such as a character that can move about static non-moving geometry such as a level in a game, and you want that dynamic object to be affected by the light bouncing off that static geometry.
To use irradiance volumes, you need to precompute, or bake, the indirect
light in your scene. Bevy doesn’t currently come with a way to do this.
Fortunately, Blender provides a baking tool as part of the Eevee
renderer, and its irradiance volumes are compatible with those used by Bevy.
The bevy-baked-gi
project provides a tool, export-blender-gi
, that can
extract the baked irradiance volumes from the Blender .blend
file and
package them up into a .ktx2
texture for use by the engine. See the
documentation in the bevy-baked-gi
project for more details on this
workflow.
Like all light probes in Bevy, irradiance volumes are 1×1×1 cubes that can
be arbitrarily scaled, rotated, and positioned in a scene with the
bevy_transform::components::Transform
component. The 3D voxel grid will
be stretched to fill the interior of the cube, and the illumination from the
irradiance volume will apply to all fragments within that bounding region.
Bevy’s irradiance volumes are based on Valve’s ambient cubes as used in Half-Life 2 (Mitchell 2006, slide 27). These encode a single color of light from the six 3D cardinal directions and blend the sides together according to the surface normal. For an explanation of why ambient cubes were chosen over spherical harmonics, see Why ambient cubes? below.
If you wish to use a tool other than export-blender-gi
to produce the
irradiance volumes, you’ll need to pack the irradiance volumes in the
following format. The irradiance volume of resolution (Rx, Ry, Rz) is
expected to be a 3D texture of dimensions (Rx, 2Ry, 3Rz). The unnormalized
texture coordinate (s, t, p) of the voxel at coordinate (x, y, z) with
side S ∈ {-X, +X, -Y, +Y, -Z, +Z} is as follows:
s = x
t = y + ⎰ 0 if S ∈ {-X, -Y, -Z}
⎱ Ry if S ∈ {+X, +Y, +Z}
⎧ 0 if S ∈ {-X, +X}
p = z + ⎨ Rz if S ∈ {-Y, +Y}
⎩ 2Rz if S ∈ {-Z, +Z}
Visually, in a left-handed coordinate system with Y up, viewed from the right, the 3D texture looks like a stacked series of voxel grids, one for each cube side, in this order:
+X | +Y | +Z |
---|---|---|
-X | -Y | -Z |
A terminology note: Other engines may refer to irradiance volumes as voxel global illumination, VXGI, or simply as light probes. Sometimes light probe refers to what Bevy calls a reflection probe. In Bevy, light probe is a generic term that encompasses all cuboid bounding regions that capture indirect illumination, whether based on voxels or not.
Note that, if binding arrays aren’t supported (e.g. on WebGPU or WebGL 2),
then only the closest irradiance volume to the view will be taken into
account during rendering. The required wgpu
features are
bevy_render::settings::WgpuFeatures::TEXTURE_BINDING_ARRAY
and
bevy_render::settings::WgpuFeatures::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
.
Why ambient cubes?
This section describes the motivation behind the decision to use ambient cubes in Bevy. It’s not needed to use the feature; feel free to skip it unless you’re interested in its internal design.
Bevy uses Half-Life 2-style ambient cubes (usually abbreviated as HL2) as the representation of irradiance for light probes instead of the more-popular spherical harmonics (SH). This might seem to be a surprising choice, but it turns out to work well for the specific case of voxel sampling on the GPU. Spherical harmonics have two problems that make them less ideal for this use case:
-
The level 1 spherical harmonic coefficients can be negative. That prevents the use of the efficient RGB9E5 texture format, which only encodes unsigned floating point numbers, and forces the use of the less-efficient RGBA16F format if hardware interpolation is desired.
-
As an alternative to RGBA16F, level 1 spherical harmonics can be normalized and scaled to the SH0 base color, as Frostbite does. This allows them to be packed in standard LDR RGBA8 textures. However, this prevents the use of hardware trilinear filtering, as the nonuniform scale factor means that hardware interpolation no longer produces correct results. The 8 texture fetches needed to interpolate between voxels can be upwards of twice as slow as the hardware interpolation.
The following chart summarizes the costs and benefits of ambient cubes, level 1 spherical harmonics, and level 2 spherical harmonics:
Technique | HW-interpolated samples | Texel fetches | Bytes per voxel | Quality |
---|---|---|---|---|
Ambient cubes | 3 | 0 | 24 | Medium |
Level 1 SH, compressed | 0 | 36 | 16 | Low |
Level 1 SH, uncompressed | 4 | 0 | 24 | Low |
Level 2 SH, compressed | 0 | 72 | 28 | High |
Level 2 SH, uncompressed | 9 | 0 | 54 | High |
(Note that the number of bytes per voxel can be reduced using various texture compression methods, but the overall ratios remain similar.)
From these data, we can see that ambient cubes balance fast lookups (from leveraging hardware interpolation) with relatively-small storage requirements and acceptable quality. Hence, they were chosen for irradiance volumes in Bevy.
Structs
- The component that defines an irradiance volume.