When rendering geometries in VTK, we can now achieve great results with the newly introduced PBR shading. We just have to configure properly lights, HDRI and materials. However, with complex surfaces like CAD models, something is clearly missing and the rendered image looks fake as illustrated in Figure 1.
Our depth perception is highly sensitive to ambient occlusion. Holes, creases, concave surfaces are occluded by the surrounding geometry. This has to be taken into account when computing illumination. In VTK 9.0, we have added a new render pass called Screen-Space Ambient Occlusion (SSAO). This technique, introduced in 2007 by Crytek, is an efficient alternative to raytracing to approximate ambient occlusion. While only an approximation, it produces very plausible result in real-time. The Figure 2 shows a complex geometry (~3M cells) rendered at 150fps on a RTX 2060 GPU.
In order to compute the ambient occlusion, the render pass modify the PolyDataMapper to save pixels positions and normals in new GPU textures. These textures are used by the SSAO algorithm in order to generate a new occlusion texture that can be combined to the color buffer. The algorithm is illustrated in Figure 3.
In order to enable SSAO in VTK, it is necessary to create a custom render pass pipeline. Several parameters can be used to configure this render pass:
- Radius: neighbor pixels considered when computing the occlusion
- Bias: tolerance factor used when comparing pixel depth
- KernelSize: number of samples used (controls the quality)
- Blur: controls if occlusion buffer should be blurred before combining it with the color buffer.
An example of a simple render pass pipeline can be found below.
vtkNew<vtkRenderStepsPass> basicPasses; double sceneSize; // e.g. the diagonal of the bounding box vtkNew<vtkSSAOPass> ssao; ssao->SetRadius(0.1 * sceneSize); // comparison radius ssao->SetBias(0.001 * sceneSize); // comparison bias ssao->SetKernelSize(128); // number of samples used ssao->BlurOff(); // do not blur occlusion ssao->SetDelegatePass(basicPasses); glRenderer->SetPass(ssao);