NVIDIA VXGI is an implementation of a global illumination algorithm known as Voxel Cone Tracing. Global illumination computes all lighting in the scene, including secondary reflections of light of diffuse and specular surfaces. Adding GI to the scene greatly improves the realism of the rendered images. Modern real-time rendering engines simulate indirect illumination using different approaches, which include precomputed light maps (offline GI), local light sources placed by artists, and simple ambient light.
The VXGI library calculates one-bounce diffuse indirect illumination effects using the voxel cone tracing method [1]. This means that light can be reflected by one diffuse surface prior to illuminating the surface visible to the observer; caustics (specular or refracted indirect illumination) are not supported, but specular reflections on the observed surfaces are simulated. The library can also simulate illumination from a uniform sky color or from an environment cubemap. Using the library makes it unnecessary to use an additional ambient occlusion pass (using SSAO or similar algorithms).
VXGI headers, libraries and DLLs
/samples/nvidia/vxgi/*.h | VXGI header files |
/samples/nvidia/vxgi/*.lib | VXGI library files (compiled with VX 2013) |
/samples/nvidia/vxgi/examplecode/... | Exemplar implementation of the rendering backend (a layer between VXGI and D3D11) |
/samples/bin/{x86,x64}/GFSDK_VXGI*.dll | VXGI DLLs (one per platform) |
Docs
/doc/... | Documentation files |
Sample files
/samples/GFSDK_VXGI_Samples_2013.sln | The solution file that contains the sample projects |
/samples/AmbientOcclusion/... | The Ambient Occlusion sample source code |
/samples/GlobalIllumination/... | The Global Illumination sample source code |
/samples/media/... | Scene files used in the samples |
/samples/nvidia/utils/... | Helper code for window, D3D device and camera manipulation |
To start using VXGI with your rendering engine, you should:
To get an indirect illumination channel from the VXGI library, the following actions have to be taken by the application:
Note: to test the rendering interface proxy and the basic use of VXGI library without actually voxelizing your geometry by combining pipelines and writing voxelization shaders, which is error-prone, you can call VXGI::IGlobalIllumination::voxelizeTestScene(…) after prepareForOpacityVoxelization(…) and prepareForEmittanceVoxelization(). This call produces a voxel representation of an opaque cube that emits white light. You should be able to observe this cube in the debug visualizations rendered by VXGI::IGlobalIllumination::renderDebug(…), and the cube should illuminate other scene geometry in the results of cone tracing.
Voxelization is performed by the application using a graphics pipeline state that is combined from state required by VXGI (which includes geometry and pixel shaders and some resources) and state required by the application (vertex shader, possibly tessellation shaders, and resources needed for them and for the user part of the voxelization pixel shader).
To set the voxel space parameters and regions to update on the current frame, and to begin voxelization, call VXGI::IGlobalIllumination::prepareForOpacityVoxelization(…). Later, to move from opacity voxelization to emittance voxelization, call prepareForEmittanceVoxelization().
After that and before voxelization, you need to get the view matrix that should be applied to your objects to transform them from world space to voxelization coordinate space. Call VXGI::IGlobalIllumination::getVoxelizationViewMatrix(…) for that.
Also you can get the list of regions that are used by VXGI to clip voxelized geometry – use these regions to cull the meshes in order to improve performance. The regions are returned by function VXGI::IGlobalIllumination::getInvalidatedRegions(…).
If the predicate corresponding to voxelization type (performOpacity/EmittanceVoxelization) is true, iterate over scene meshes doing the following for every mesh eligible for voxelization:
When done drawing, don’t forget to call VXGI::Util::IRendererInterfaceD3D11::clearState() in order to remove the state bits used for voxelization and avoid various issues.
Computing a voxel representation of surfaces that reflect light can be done in two fundamentally different ways.
The first method is RSM-based scatter light injection. It means that the application has to render a reflective shadow map (RSM) for every light. That RSM contains three channels: depth; world-space normal; reflected radiance or color. Every RSM texel is treated as a small Lambertian surface. This method requires that the application passes an array of VXGI::LightDesc descriptors to VXGI::IGlobalIllumination::prepareForOpacityVoxelization(…), where each descriptor contains valid handles to RSM textures.
The second method is direct light voxelization. It means that every mesh in the scene is treated as emissive, and its emissive color is computed as reflected diffuse radiance. To use this method, omit the LightDesc array and revoxelize the whole scene on every frame by invalidating it, or fill the array and set all texture handles in the LightDesc structure to zeroes, so that VXGI will track changes in lights and invalidate only parts of the emittance representation. Then render potentially lit objects during emittance voxelization. In the voxelization pixel shader, calculate the reflected radiance using any material shaders, light parameters and shadowing techniques. You can render geometry once and iterate over the lights inside the shader, or you can render geometry multiple times and test one light every time.
Direct light voxelization normally produces higher quality results than RSM-based injection, and it is sometimes faster – that depends on geometric complexity and voxelization parameters, such as adaptive supersampling. This technique is used in the GlobalIllumination sample provided with the VXGI library.