Jump to content

Direct Lighting with Sparse Voxel Octrees


Josh

3,411 views

 Share

Previously I described how I was able to save the voxel data into a sparse octree and correctly lookup the right voxel in a shader. This shot shows that each triangle is being rasterized separately, i.e. the triangle bounding box is being correctly trimmed to avoid a lot of overlapping voxels:

vox.thumb.png.414a8a4812831567dfbd4c0428849824.png

Calculating direct lighting using the sparse octree was very difficult, and took me several days of debugging. I'm not 100% sure what the problem was, other than it seems GLSL code is not quite as flexible as C++. I actually had the same exact function working in GLSL and C++, and it worked perfectly in C++ but gave wrong results in GLSL! Of course I did not have a debugger for my GLSL code, so I ended up having to write a lot of if statements and outputting a pixel color base on the result. In the end I finally tracked the problem down to some data stored in an array, changed the way the routine worked, but what the exact issue was I'll never know.

With the sparse voxel octree, we only have about 400,000 pixels to draw when we process direct lighting. Rendering all voxels in a 256x256x256 volume texture would require 16 million pixels to be drawn. So the sparse approach requires us to draw only 2% the number of pixels we would have to otherwise. Using shadow maps, on a 1920x1080 screen we would have to calculate about 2,000,000 shadow intersections. Although we are not comparing the same exact things, this does make me optimistic for the final performance results. Basically, instead of calculating shadow visibility for each pixels, we can just calculate per voxel, and your voxels are always going to be quite a bit bigger than screen pixels. So the whole issue of balancing shadow map resolution with screen resolution goes away.

Ray traversal is very fast because it skips large chunks of empty space, instead of checking every single grid space for a voxel.

The voxel resolution below is not very high, I am only using one octree, and there's currently no blending / filtering, but that will all come in time.

Untitled.thumb.png.669fa5e8265b96b49c880b4f8895c570.png

Leadwerks 1 and 3D World Studio used lightmaps for lighting. Later versions of Leadwerks used deferred lighting and shadowmaps. Being able to roll out another cutting-edge lighting technology in Ultra Engine is icing on the cake for the new engine. I expect this will allow particle shadows and transparent glass with colored shadows, as well as real-time global illumination and reflections, all with great performance on most hardware.

  • Like 3
 Share

9 Comments


Recommended Comments

Here you can see the normal geometry with texture combined with shadow. There's no actual lighting, just full-bright or black:

Untitled.thumb.jpg.94179f63cd351a21b7ad48667b65ea62.jpg

  • Like 1
Link to comment

And here it is with the lighting taken into account. Shadows are blocky and low-res, but that's fine at this point. This is the equivalent to using a low-res shadow map with no filtering.

Untitled.thumb.jpg.5eed9b9f44dc2853bb0dccf169ac3f55.jpg

  • Like 3
Link to comment

Looks very nice.  I'd like to see it tested with a large outdoor environment.  Are there any limits in terms of shadow range?

Link to comment

I expect to have several octrees around the camera, each one twice the dimensions of the previous. So there will probably be a limited shadow range, but how that compares to CSM I don't know yet.

  • Like 1
Link to comment
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...