July 2025
Last months focus was on managing voxels and after a few mishaps I got it to a stage where I’m happy (for now). This month has been mostly focusing on graphics instead, which have actually really highlighted both the pros and cons of my approach to voxels.
Now when modifying the world is a lot easier I immediately identified the next big problem, due to the limited lighting it looks like crap. No cozy caves without shadows.
So first think I set of to do is to actually add some drop shadows. Thanks to last months work on the voxel data structure it was actually really straighforward, I just trace the light in the lighting pass.
Adding soft shadows wasn’t that difficult to implement either, simulate that the sun is a disk and not a point light by using some noise. Noise have definitely been my best friend and worst enemy this month. Did some research on noise and these were two very valuable resources: blog.voxagon.se and extremelearning.com.au.
As I said, worst enemy. Noise is great but needs filtering…
Some of the noise gets cleaned (or smudged) by the TAA but I also did some initial work on a temporal denoising pass for my lighting pass. Denosing is tricky though, it has a very visible cost as the camera moves, so I’m aiming to revisit this at some later time.
A cool thing I realized is that now with my voxels I can actually do world space ambient occlusion. So I replaced my previous ugly SSAO implementation by just casting rays in world space instead. This has a hefty price tag tho.
Now I have lighting sufficient to actually make caves dark!
Cool loking bug from that process. Caused by me trying to optimize the ambient occlusion by traversing at a lower voxel resolution. Dennis Gustafsson had a similar problem and solved it by combining both screen and voxel tracing which might be cool to try out.
To reduce the cost of the ambient lighting I had the idea to do some kind of texel based lighting instead of doing it per screen pixel. This would have the extra benefit of making it a bit more stylistic.
I also added some more stats to my panel on the right. As I spent a lot of time working on my macbook it was valuable to see get immediate feedback on the runtime. Don’t mind the slow lighting pass as I was just prototyping here.
It got horrible to denoise compared to screen space tho so I scratched it. Later, I found Douglas had the same idea but solved it more neatly, so I might revisit this again.
No cozy caves without point lights so I added those as well.
Here I got a bit tired of dealing with noise so I went on to work on another much needed feature; foliage. Here you see the first “grass straw”.
I’ve opted for a fully GPU-driven approach to deal with foliage and my first problem to tackle was how to generate the grass straws. I had the idea to just use my voxel structure to just cast a ray down on the chunk to see if I hit grass, and if so, spawn a grass straw. This works, but also means occluded grass voxels won’t get populated.
First I thought it would be cool to render volumetric grass, just as Gabe Rundlett, but I didn’t get further than the image above before deciding to try out billboards.
I’m a bit on the fence still. I can probably get the volumetric grass to look a bit better by fixing the lighting and adding some animation, but there is something very nostalgic about billboards that I can’t shake.
I continued working a bit on the logistics of the grass so now it actually gets loaded/unloaded as chunks gets streamed in and out. I also replaced the ray casting approach for generating grass with a shader just doing a tree traversal, going through all voxels in the chunk to find grass. It solves the occlusion issue but it has some other issues so we’ll see.
Next up is to see if I can get the foliage system to interact a bit better with modifications to the voxels. For now I just regenerate the whole chunk, which is horrible for performance.