Jump to content

Voxel GI: Colors and Fast Downsampling


Josh

2,232 views

 Share

The polygon voxelization process for our voxel GI system now takes vertex, material, and base texture colors into account. The voxel algorithm does not yet support a second color channel for emission, but I am building the whole system with that in mind. When I visualize the results of the voxel building the images are pretty remarkable! Of course the goal is to use this data for fast global illumination calculations but maybe they could be used to make a whole new style of game graphics.

Untitled.thumb.jpg.e61c670a13fff655747ca7f576de656a.jpg

Direct lighting calculations on the CPU are fast enough that I am going to stick with this approach until I have to use the GPU. If several cascading voxel grids were created around the camera, and each updated asynchronously on its own thread, that might give us the speed we need to relieve the GPU from doing any extra work. The final volume textures could be compressed to DXT1 (12.5% their original size) and sent to the GPU.

After direct lighting has been calculated, the next step is to downsample the voxel grid. I found the fastest way to do this is to iterate through just the solid voxels. This is how my previous algorithm worked:

for (x=0; x < size / 2; ++x)
{
  for (y=0; y < size / 2; ++y)
  {
    for (z=0; z < size / 2; ++z)
    {
      //Downsample this 2x2 block
    }
  }
}

A new faster approach works by "downsampling" the set of solid voxels by dividing each value by two. There are some duplicated values but that's fine:

for (const iVec3& i : solidvoxels)
{
  downsampledgrid->solidvoxels.insert(iVec3(i.x/2,i.y/2,i.z/2))
}
for (const iVec3& i : downsampledgrid->solidvoxels)
{
  //Downsample this 2x2 block
}

We can then iterate through just the solid voxels when performing the downsampling. A single call to memset will set all the voxel data to black / empty before the downsampling begins. This turns out to be much much faster than iterating through every voxel on all three axes.

Here are the results of the downsampling process. What you don't see here is the alpha value of each voxel. The goblin in the center ends up bleeding out to fill very large voxels, because the rest of the volume around him is empty space, but the alpha value of those voxels will be adjusted to give them less influence in the GI calculation.

1.thumb.jpg.55dc07854388947cf69b3421f8aabe7c.jpg

2.thumb.jpg.ad4b748a187734adce31ae726d91f5f2.jpg

3.thumb.jpg.83f2bf220c3f596c6eb861657c9fec14.jpg

4.thumb.jpg.fa6be5bbc126702e46f55aa2749a7780.jpg

For a 128x128x128 voxel grid, with voxel size of 0.125 meters, my numbers are now:

  • Voxelization: 607 milliseconds
  • Direct lighting (all six directions): 109
  • First downsample (to 64x64): 39
  • Second downsample (to 32x32): 7
  • Third downsample (to 16x16): 1
  • Total: 763

Note that voxelization, by far the slowest step here, does not have to be performed completely on all geometry each update. The direct lighting time elapsed is within a tolerable range, so we are in the running to make GI calculations entirely on the CPU, relieving the GPU of extra work and compressing our data before it is sent over the PCI bridge.

Also note that a smaller voxel grids could be used, with more voxel grids spread across more CPU cores. If that were the case I would expect our processing time for each one to go down to 191 milliseconds total (39 milliseconds without the voxelization step), and the distance your GI covers would then be determined by your number of CPU cores.

In fact there is a variety of ways this task could be divided between several CPU cores.

 Share

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...