Hey all! It’s been a while. Sorry about the delay. I hit a few roadblocks along the way, but it’s finally here! Thanks for your patience
Have you ever wondered how some games like Teardown or Minecraft shader mods can generate such beautiful lighting?
We’ve previously talked about shadow mapping and volumetric lighting, which can help improve the lighting with just about any game, but they are limited by resolution which affects both quality and range. Other effects like Screen-Space-Ambient-Occlusion and Screen-Space-Reflections can add some realism, but they are limited to geometry visible on screen.
What if we could just ray cast from any point in space and in any direction we wanted? We could do take in reflections from outside the screen, cast pixel perfect shadows and maybe even do ambient occlusion in world space instead of only in screen space!
As it turns out, with 3D pixels, also known as “voxels”, raytracing is relatively easy and straightforward to learn.
Overview
Before jumping to any code, I want to give a quick summary of how the algorithm works. Here’s a 2D illustration I put together:
First, we divide the world into a grid of blocks. To start, we need a starting point (e.g. the camera’s position) and ray direction to look along. The goal is to check every block edge until we hit a block, so we loop through all the edges along the ray, checking the closest edges first. In order to find the closest edge, we need to be able to compute the depth for the edges.
We do this by finding the spacing between block edges in the given ray direction. In 2D, we two edges along the x and y axes. In 3D, we check the 3 faces along the x, y and z axes.
Here’s another 2D illustration to see what I mean:
The neat part is this spacing is the same for all blocks, so we can calculate this just once, outside the step loop. If we start on an X-axis edge and step the X spacing distance, we’re guaranteed to land on the next block edge. The same goes for the Y-axis or Z-axis (This can be mirrored, and the results are the same).
The actual voxel loop is just about finding which next edge or face axis is closest and stepping one voxel unit in that axis. We can store the depths to the next x/y/z edges in a vector, and when we hit one edge, we already know the next where the next will be using our spacing “x-spacing” distance! Just add it to our last x depth and then check which axis is closest again. If we hit something, then we stop the ray there.
When we repeat this process, we can test every single voxel cell that the ray intersects with until we hit a block! Now let’s look at some code so you can get a more solid understanding.
Code
As a way to say thank you to Paid subscribers, I’ve dedicated the rest of this tutorial to them. I’ll share the illustrations as well as the code examples below. If you choose to support my work, you can read the full tutorial by clicking below.
The next tutorial will be free for everyone. Thank you!
GM Shaders: Voxels
Hey all! It’s been a while. Sorry about the delay. I hit a few roadblocks along the way, but it’s finally here! Thanks for your patience Have you ever wondered how some games like Teardown or Minecraft shader mods can generate such beautiful lighting?
I’ve put together a little ShaderToy demo with some extra flare!
We don’t have to stick with just cubes. In fact, we can divide the voxels in any axes we like. How about triangular voxels or tetrahedral/octahedral voxels?
If there’s enough interest, I could write more about these in the next tutorial. Hopefully you’ve got enough here to get some ideas rolling and start experimenting!
Conclusion
I’ve written many different voxel shaders over the years (mostly with my own algorithms). It wasn’t until recently that I rediscovered how simple the loop part can actually be. Using the “DDA” algorithm, we only need to get the voxel spacing for each axis once for each ray direction. From there, we just loop through voxel faces, checking the closest face first and stepping one voxel unit at a time.
The best part, is that it’s so simple, it can be adapted for any number of axes, in any directions and any spacings (you can stretch each axis individually if you’d like).
Here’s an example of 2D triangle ray cast shadows
Extras
I found Chris Gyurgyik’s voxel tutorial to be quite solid. A good read if there’s anything you’re missing here.
Jacco Bikker wrote a solid voxel tutorial series which covers reflections, recursion, antialiasing, soft shadows, denoising and more!
I put together two ShaderToy demos for this tutorial:
GM Shaders: Voxels - A simple, but effective voxel raytracing demo
Triangle DDA - Using DDA to demonstration with 2D triangle grid and shadow casting
That’s all. Thanks for reading and have a great weekend!