Previous topic

NVIDIA VXGI

Next topic

Release Notes

NVIDIA VXGI 0.9.

Overview

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).

_images/vxgi.png

Package

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

Getting Started

To start using VXGI with your rendering engine, you should:

  1. Add a reference to GFSDK_VXGI_x64.lib or GFSDK_VXGI_x86.lib.
  2. Put GFSDK_VXGI_x64.dll or GFSDK_VXGI_x86.dll into the output directory of the project.
  3. Copy or include the files GI_InterfaceD3D11.cpp and GI_InterfaceD3D11.h into the project to get a reference implementation of the rendering backend (Direct3D proxy).
  4. Use the latest available version of NVAPI library – it’s required for certain features in the backend implementation, specifically SLI support and extended rasterizer state.
  5. Include GI_Interface.h to get all VXGI interface declarations.
  6. Implement VXGI::IErrorCallback to receive error messages from VXGI.

To get an indirect illumination channel from the VXGI library, the following actions have to be taken by the application:

  1. Create a GI object (instance of VXGI::IGlobalIllumination) by calling VFX_VXGI_CreateGIObject(…), providing it with the rendering system interface (a proxy for Direct3D 11 and eventually OpenGL) and parameters that define the quality of the voxel representation.
  2. Create a GI tracer (instance of VXGI::IViewTracer) by calling VXGI::IGlobalIllumination::createNewTracer(…).
  3. Create voxelization geometry and pixel shaders, at least one of each.
    1. The voxelization geometry shader can be easily created from the shader in the previous stage (that is, vertex shader or domain shader) by calling VXGI::IGlobalIllumination::createVoxelizationGeometryShaderFromVS(…) or VXGI::IGlobalIllumination::createVoxelizationGeometryShaderFromDS(…).
    2. A simple voxelization pixel shader can be created by calling VXGI::IGlobalIllumination::createVoxelizationDefaultPixelShader(…). This pixel shader is only good for voxelizing solid geometry for opacity, i.e. it doesn’t support alpha testing or emissive materials. Note that this shader also doesn’t expect any custom attributes to be passed through the geometry shader, so if there are some, there will be D3D runtime warnings.
    3. A more advanced voxelization pixel shader can be created by calling VXGI::IGlobalIllumination::createVoxelizationPixelShader(…), which compiles custom HLSL source code written by the application developer. The rules that have to be followed by this code are covered in the comments to the declaration of that function.
    4. All kinds of voxelization shaders and custom cone tracing shaders as well can be compiled once and then reused. To do that, first compile the shader using one of the create… functions; then call VXGI::IUserDefinedShaderSet::getBinary(…) and store the binary somewhere; later call VXGI::IGlobalIlluminaion::loadUserDefinedShaderSet(…) to restore the shaders from the binary representation.
  4. Voxelize the scene using this sequence of calls:
    1. VXGI::IGlobalIllumination::prepareForOpacityVoxelization(…). This method collects information about which regions of the scene need to be updated on the current frame, and returns performOpacityVoxelization and performEmittanceVoxelization predicates that tell the application whether it should do opacity and emittance voxelization, respectively, on this frame. It also collects references to reflective shadow maps (RSMs) for scene lights, if they are provided in the array of LightDesc structures.
    2. If performOpacityVoxelization is true, voxelize scene geometry as described in the corresponding section of this document.
    3. Call VXGI::IGlobalIllumination::prepareForEmittanceVoxelization().
    4. If performEmittanceVoxelization is true, voxelize emissive or directly lit objects in the same way that is used for opacity voxelization, possibly using different voxelization shaders.
    5. After voxelization, call VXGI::IGlobalIllumination::finalizeVoxelization() to prepare for cone tracing.
  5. Pass the G-buffer surfaces and camera information to the tracer by calling VXGI::IViewTracer::setInputBuffers(…).
  6. Call VXGI::IViewTracer::computeDiffuseChannel(…) and/or computeSpecularChannel(…).
  7. Combine the diffuse and specular channels with direct lighting. It is advised to use tone mapping to make the rendering look more natural.

Voxelizing scene geometry

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:

  1. Fill a VXGI::MaterialInfo structure and call VXGI::IGlobalIllumination::getVoxelizationState(materialInfo, out drawCallState) when materialInfo changes. You can call this method for every mesh, but that is inefficient.
  2. Apply the state returned by getVoxelizationState by calling VXGI::Util::IRendererInterfaceD3D11::applyState(…); add the state that your parts of the pipeline need.
  3. Draw your geometry using any number of draw calls.

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.

Voxelizing light

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.

Browse Documentation