3D Voxel Terrain

I’ve hit a small milestone! I’ve gotten voxel (3d pixel) terrain working in my game engine! The height maps from last post are used generate some placeholder terrain, which are then saved to chunk files (where a chunk is 32x32xHEIGHT blocks). Moving around in the 3d space creates a “viewable” radius of the world around you – as shown the viewing distance is roughly equivalent to max view distance achievable in other voxel game engines (like minecraft). 60+ frames per second on unoptimized code feels really great! I expect I can get another 10x of performance with some tweaking, but for now I’m all about *prototyping*.

One interesting technical tidbit from my work is thinking about file compression. Voxels take up a lot of space (1 byte per voxel), and building large worlds can mean lots of storage (including RAM). For example, even a 1024x1024x1024 map takes up 1GB of disk storage, and that is a very small world! But, voxels are quite similar and we can try to compress the file and save RAM and disk space. So I decided to implement some techniques and record the results.

The above figure shows my results. Run-length encoding is a great technique for data that is simple and pretty similar. It basically tries to find adjacent data that are the same and combine them. For example, AAABBA = 3A2B1A. The thing is, you need to choose a direction to look for, and I tried both checking horiztonally (RLE_hor) and vertically (RLE_col) across stripes in each chunk. Then, taking those results I compressed using LZX compression as found in zip/7zip. The results are pretty amazing. It turns out that on real terrain (with a variety of block types), RLE in the vertical direction is best, giving close to 65x compression (1GB/1024MB to ~16MB in our example). Adding LZ compression pushes you to around 600x to 1200x compression (1GB/1024MB to <1MB in our example). The entire world now fits in less than a megabyte! One of the side effects of compression besides saving space is also improving load speeds. RLE encoding in particular is extremely fast, which means that chunks can be loaded quickly.

That’s my update! I’ve got a lot of things I’m currently working on and hope to share soon!

Leave a comment

Your email address will not be published. Required fields are marked *