Game Development Reference
pixels), this generation step is surprisingly fast. Figure 7.1 shows a screenshot
in which the voxel grid representation of the Sponza scene is visualized. To
create this image for each visible pixel of the rendered scene, the word-space
position is reconstructed. With the help of the reconstructed position, we can
determine the location of the corresponding voxel inside the grid. Finally, each
visible pixel will be colored with the diffuse albedo information that is stored
inside the corresponding voxel. In order to cover the entire scene, two nested
voxel grids have been used: a fine-resolution grid for the area near to the viewer
and a coarse-resolution grid for the distant area.
Since all operations are performed using a very small render-target (64
Create VPLs in Voxel Space
In this step we create VPLs entirely from the previously generated voxel grid.
For each light source that is located inside the boundaries of the grid, we render
a small quad of 32
32 pixels. By using hardware instancing, for each quad we
are able to render 32 instances with a single draw call. After passing the vertices
through the vertex shader, the geometry shader will choose the corresponding
render-target slice in the currently bound 2D texture arrays. The pixel shader
will then illuminate all voxels that contain geometry information according to
the type of the current light source. Finally, the illuminated voxels are converted
into a second-order spherical harmonic representation of VPLs. By using additive
hardware blending, the results of all light sources are automatically combined.
Listing 7.2 generically shows how this is done for DirectX 11 in HLSL.
// vertex shader
VS_OUTPUT main(VS_INPUT input,uint instanceID: SV_InstanceID)
output.position = float4(input.position,1.0f);
output.instanceID = instanceID;
// geometry shader
float4 position: SV_POSITION;
uint rtIndex: SV_RenderTargetArrayIndex;
void main(line VS_OUTPUT input,inout TriangleStream <GS_OUTPUT>
// Generate a quad from two corner vertices.