The author mentions simplicity in their Readme. I would be very interested to read their journey and some of the decisions they made where they preferred simplicity. More of this please !
I've been thinking of doing a series of blogs on the journey but .. it's been a journey, which is a lot to write about in full. In short, a few places where I've been able to prefer simplicity:
1. Allocators are all pretty much as simple as you can get. Most memory in the program is bump/arena allocated. There is a buddy-style heap allocator for things that are annoying to arena allocate (strings that can be edited, for example). I make heavy use of temp memory and freelists.
2. Containers are all very straight-forward, and it's definitely a feature. The example I always give here is std::map from C++. On paper, it looks great; it has very good looking properties. In practice, the implementation is a nightmare; it's slow, and has a comically large rebalancing-shaped performance cliff. My containers strive to be simple, with reasonable average and worst-case performance.
3. I wrote my own metaprogramming language instead of using C++ template metaprogramming. Writing an entire programming language sounds like the antithesis of simplicity, but in reality, having a good metaprogramming layer makes your life immeasurably easier in the long run. With strong metaprogramming capabilities, stuff like realtime debug UI and state serialization becomes nearly trivial. Once you start doing versioned data serialization in C++, you quickly realize you need a better compiler (see: protobuf, cap'n proto)
It's actually more efficient to do a hybrid approach, especially at high view distances. Rasterizing triangles is extremely fast, and is basically a perfect primary-ray intersection. Ethan Gore recently did some experiments with raytracing and said that for large scene volumes (his engine comfortably renders the entire 32-bit range, or 4B^3) it turns out to be faster to do raster for primary rays and raytrace shadows/GI.
I've always wondered why voxel engines tend to produce output that looks so blocky. I didn't realize it was a performance issue.
Still, games like "C&C: Red Alert" used voxels, but with a normal mapping that resulted in a much less blocky appearance. Are normal maps also a performance bottleneck?
I originally chose to go with axis-aligned blocks and hard axis-aligned normals because I liked the aesthetic. I've since slightly course-corrected; each voxel has bent normals which follow the surface. How much the normals are bent is artist configurable. This has the effect of smoothing out the look of the surface when viewing from a distance, but still gives the distinct blocky look when up close.
In terms of performance, there is a cost to having fully 3D normals per voxel, but it's certainly manageable. There's a lot of other, more expensive, stuff going on.
Before Minecraft, basically all voxel engines used some form of non-axis-aligned normals to hide the sharp blocks. Those engines did this either through explicit normal mapping, or at the very least, by deriving intermediate angles from the Marching Cubes algorithm. Nowadays, the blocky look has become stylish, and I don't think it really even occurs to people that they could try to make the voxels smooth.
Can you add more details? This seems to directly contradict GP. GP said ray tracing can do higher voxel counts = ray tracing is more performant (than rasterization).
I did a decent amount of work in MagicaVoxel in the past.
I like that Voxel Max works on iPad. It also allows 3D meshes to be imported and voxelized.
Voxel Max has a good amount of polish these days. It’s my top option with MagicaVoxel a close second.
I’ve also used Qubicle and Goxel. Qubicle is okay for specific things. I really like its masking planes feature. I really don’t like Goxel. It’s UI just feels clunky.
The author mentions simplicity in their Readme. I would be very interested to read their journey and some of the decisions they made where they preferred simplicity. More of this please !
Hello, author here :)
I've been thinking of doing a series of blogs on the journey but .. it's been a journey, which is a lot to write about in full. In short, a few places where I've been able to prefer simplicity:
1. Allocators are all pretty much as simple as you can get. Most memory in the program is bump/arena allocated. There is a buddy-style heap allocator for things that are annoying to arena allocate (strings that can be edited, for example). I make heavy use of temp memory and freelists.
2. Containers are all very straight-forward, and it's definitely a feature. The example I always give here is std::map from C++. On paper, it looks great; it has very good looking properties. In practice, the implementation is a nightmare; it's slow, and has a comically large rebalancing-shaped performance cliff. My containers strive to be simple, with reasonable average and worst-case performance.
3. I wrote my own metaprogramming language instead of using C++ template metaprogramming. Writing an entire programming language sounds like the antithesis of simplicity, but in reality, having a good metaprogramming layer makes your life immeasurably easier in the long run. With strong metaprogramming capabilities, stuff like realtime debug UI and state serialization becomes nearly trivial. Once you start doing versioned data serialization in C++, you quickly realize you need a better compiler (see: protobuf, cap'n proto)
It's really not that hard to ray trace the voxels instead of using rasterization and allows for way higher voxel counts.
https://dubiousconst282.github.io/2024/10/03/voxel-ray-traci...
Hello, author here.
It's actually more efficient to do a hybrid approach, especially at high view distances. Rasterizing triangles is extremely fast, and is basically a perfect primary-ray intersection. Ethan Gore recently did some experiments with raytracing and said that for large scene volumes (his engine comfortably renders the entire 32-bit range, or 4B^3) it turns out to be faster to do raster for primary rays and raytrace shadows/GI.
I've always wondered why voxel engines tend to produce output that looks so blocky. I didn't realize it was a performance issue.
Still, games like "C&C: Red Alert" used voxels, but with a normal mapping that resulted in a much less blocky appearance. Are normal maps also a performance bottleneck?
Hello, author here :)
I originally chose to go with axis-aligned blocks and hard axis-aligned normals because I liked the aesthetic. I've since slightly course-corrected; each voxel has bent normals which follow the surface. How much the normals are bent is artist configurable. This has the effect of smoothing out the look of the surface when viewing from a distance, but still gives the distinct blocky look when up close.
In terms of performance, there is a cost to having fully 3D normals per voxel, but it's certainly manageable. There's a lot of other, more expensive, stuff going on.
Before Minecraft, basically all voxel engines used some form of non-axis-aligned normals to hide the sharp blocks. Those engines did this either through explicit normal mapping, or at the very least, by deriving intermediate angles from the Marching Cubes algorithm. Nowadays, the blocky look has become stylish, and I don't think it really even occurs to people that they could try to make the voxels smooth.
5 replies →
It's way more performant though and looks fine so I see the reasoning why you would do rasterization instead
Can you add more details? This seems to directly contradict GP. GP said ray tracing can do higher voxel counts = ray tracing is more performant (than rasterization).
I’ve been using Voxel Max for the last couple weeks to draw voxel art for a game and it’s incredible.
I’ll have to try some of my assets out in this engine.
I'm curious, did you specifically choose Voxel Max over MagicaVoxel for any reason?
> I’ll have to try some of my assets out in this engine.
The asset loading is currently broken in Bonsai after a big rewrite, but it's the next thing on my list to fix! Would love to see your art :)
I did a decent amount of work in MagicaVoxel in the past.
I like that Voxel Max works on iPad. It also allows 3D meshes to be imported and voxelized.
Voxel Max has a good amount of polish these days. It’s my top option with MagicaVoxel a close second.
I’ve also used Qubicle and Goxel. Qubicle is okay for specific things. I really like its masking planes feature. I really don’t like Goxel. It’s UI just feels clunky.
1 reply →
didn't find any video so: https://www.youtube.com/watch?v=sRL_RU7-jfc
btw the license is nuts
WTFPL (Do What The F*k You Want To Public License) https://en.wikipedia.org/wiki/WTFPL
This seems like a bad idea. Surely the warranty and liability disclaimer found in licenses like MIT exists for a reason.
8 replies →
Author here.. that was kind of the point.
To be fair, most are.
Better than LGPL which prevents you from static linking even if you give attribution.
Nice project, this tutorial was also helpful for a hobby volumetric data display routine. Cheers =3
"I Optimised My Game Engine Up To 12000 FPS" ( https://www.youtube.com/watch?v=40JzyaOYJeY )
https://github.com/vercidium-patreon/meshing
very cool