Hello, guys. Please forgive me for the shameless self promotion, I'd just like to share and discuss the results I got with my Voxel Cone Tracing implementation. So, in my last post I presented an early version of my own implementation of global illumination using voxel cone tracing, since then I've done a lot of improvements and ended up creating a demo that you can find here to show it. Very soon I'll be writing a set of articles explaining the implementation in more detail but for now I'll outline the most important aspects:
My implementation uses two 128x128x128 3D textures to store the voxelized scene, a small texture and a larger one, where the small one covers a 30x30x30m volume of the scene while the larger one covers a 120x120x120m volume. Together they provide a voxelized representation of the scene with enough quality and range for the GI processing. The volumes are fixed at the world origin, they do not follow the camera because that makes the lighting unstable, I know this is impractical for a video game but it's enough to cover the smalll scene of my demo.
No Sparse Voxel Octree is used, this is because I concluded from my early experiments that traversing the tree takes a huge toll on performance probably because the divergent code paths and incoherent memory accesses are not very GPU friendly. So, In general volume textures seem to provide much better performance that octrees at the expense of huge memory waste (because of empty voxels). I haven't profiled one method against the other, my choice was based simply on experiments so please feel free to argue against these arguments and provide your own insight on the subject.
The scene is voxelized in real-time using a similar version of the technique described by Cyrril Crassin in the free OpenGL Insights chapter that is available here. The voxelization is quite fast and can be performed in real-time without a great impact on performance which allows to make the lighting dynamic, if any object or light source moves you'll see the lighting change accordingly.
Once the voxel volume is ready it is possible to simulate a second bounce of GI by revoxelizing the scene to a second volume while using the first volume to perform cone tracing for each fragment that is inserted into the volume. Note however that this is very expensive and doesn't compensate the reduced improvement in visual quality so it's disabled by default in the demo.
The diffuse lighting is calculated in groups of 3x3 pixels to improve the performance and a edge refinement is done later to fix the difficult cases. For each group of 3x3 pixels 16 cones are traced in all directions with 32 samples per cone. The tracing of each cone is done pretty much like Crassin describes in his paper, for each sample inside the cone we read the corresponding mipmap level of the volume texture and accumulate both the color and the opacity of the voxel information that was read.
The specular lighting is calculated by tracing a cone along the reflection vector. Voxel cone tracing gives the flexibility to generate sharp and glossy reflections which is really neat. In general both look good but the lack of resolution of the voxel volume prevents the accurate rendering of glass and mirror materials. Sharp reflections are problematic also because they require an insane amount of samples per cone (200 in the demo) to avoid missing scene features like thin walls. The tracing is optimized to skip large portions of empty space by sampling a lower resolution mipmap level of the voxel volume and checking its opacity (similar to sphere tracing), if the opacity is zero then there are no objects nearby and we can skip that space altogether. This is essentially an GPU friendly approximation of what is done with a Sparse Voxel Octree.
So this concludes the overview of the implementation. Please feel free to leave your comments.
Don't forget to try the demo (I recommend running it on a Nvidia GTX 680 or similar, it's untested for AMD hardware so I have now idea how it runs on it).
Here is some eye candy :