Editing millions of voxels in a single CPU thread (C++/Vulkan)

The dynamic ellipses you see when I drag my mouse are just ray-marched ellipse SDFs that I render as voxels by clamping the ray to the nearest voxel position when it's getting close to the surface. So not a single voxel is stored in memory during this phase.

The storing happens when I release the click. The voxels end up actually committed to the world terrain when the dragging ends, which is still very fast due to the data structure I'm using : a sparse 64-tree , an octree with 64 children per node (so a tetrahexacontree I guess ?) and only non-empty nodes are represented in memory. Which implies:

- Voxels are stored in a single buffer of tree nodes

- I'm not actually storing millions of individual voxels, the inside of the ellipses is probably just few KB of tree leaves.

That buffer containing all the nodes is allocated via virtual memory, I first reserve something like 6 GB of virtual addresses via VirtualAlloc / mmap, and commit addresses progressively to physical memory with VirtualAlloc / mprotect only when I need it.

To achieve that real-time performance, the storing algorithm is quite straightforward :

Starting from the root node of the 64-tree, I evaluate a coverage test between the ellipse and the AABB of the node :
- If fully covered, the node becomes a voxel leaf
- If partially covered, recurse into children and repeat
- otherwise, do nothing and stop

Then I upload the whole thing to the GPU unapologetically (will change eventually).

Everything is rendered with a single real time path tracing compute shader written in Slang. Which means that sharing light data between the SDFs, the voxel world and any data structure is quite simple as long as the rendering of these structures is ray-based (ray-marching, ray-tracing, you get it).

GCC and -O3 are doing a lot of heavy lifting though, in debug mode these ellipses would generate a 0.5s lag spike when releasing the click.

Conversely the unique Slang shader is faster when compiled to spirv with -O0 rather than -O3 somehow lol.

u/Mioliths — 9 days ago

Voxel Game Engine & Real-time Editor (C++ / Vulkan)

I am working on a voxel game engine & editor with the purpose of fast iteration and hand-free voxel drawing for those, like me, not willing to do 3d modeling, and making it fast even on older GPUs. So here is a demo I wanted to show you.

There are now too many technical details to cover. I'll probably write a full article later, but in the meantime, here's a brief overview.

The terrain is an editable SVDAG (Sparse 64-tree with only de-duplication at the last layer of the tree). The voxel editing works a little like what is described in the HashDAG paper:

Starting from the root node of the 64-tree, I evaluate a coverage test between any input shape and the AABB of the node
- If fully covered, the node becomes a voxel leaf
- If partially covered, recurse into children and repeat
- otherwise, stop

and a regular hash table is used to prevent the duplication of 4x4x4 groups of voxels at the end of the tree.

The whole tree is uploaded to the GPU at once for each edit (bad idea but it has not become a liability yet).

Everything is raymarched and path traced in a single compute shader: First, the SVDAG terrain, then the entities, for which I first test the intersection with their AABB then apply the transform (scale,rotation,position) by simply multiplying the inverse transform matrix with the ray direction & origin when I raycast them.

Entities can be anything raycastable that comes with a transform matrix and a AABB, like an SDF, or a raw voxel grid with directional distance field stored in empty voxels.

The pinball physics are just hard coded for the purpose of testing the engine so nothing new or fancy.

u/Mioliths — 10 days ago

Placing gigantic voxel ellipses in real time

The trick is that the dynamic ellipses you see when I drag my mouse are just raymarched ellipse SDF that I render as voxels by clamping the ray to the nearest voxel position when it's getting close to the surface. So not a single voxel is stored in memory during this phase.

When I release the left click, the voxels end up actually stored into the world sparse 64-tree. At this moment there is a visible lag spike but not quite noticeable because it happens after I've finished the dragging.

Now, even the voxel placing is quite fast due to the nature of sparse trees, I'm not storing millions of individual voxels, the inside of the sphere is probably just few KB of tree leaves.

Everything is rendered with a single real time path tracing compute shader. So every different kind of voxel structure in my engine just share light data easily as long as the structures are rendered via ray traversal/marching/tracing etc

u/Mioliths — 3 months ago