This article describes one of the big breakthroughs and realisations I had while making a voxel engine of mine. Here it is :

Using floating-point values to define simple cubes faces is a bad idea.

Well, obviously it's a bit overkill, but we're talking about a simple low-tech game, not Crysis 3, it doesn't even matter, does it ?

At first glance it may seem so, I used to think that Minecraft was easy on video memory ( spoiler : it's not. ), and that the few megabytes it would have used was mostly just for textures and framebuffers. So when I started working on Chunk Stories, my own voxel engine, I didn't consider the chunk geometry as very memory heavy thing, but just as a little overhead, negligible in regards to things like hd textures or big heightmaps for far terrain.

Then 2 days ago, after 3 weeks of being away from my PC, I loaded my latest build and found the game to be extremely laggy when it went over around 8-9 million vertices displayed, especially in the forests where the game renders every individual face of a leaves blocks ( that adds up, that's why "fast/fancy" modes on Minecraft do so much to the performance, in fast mode the leaves are opaque so it cuts the vertices dramatically ). It almost seemed like GTA V, running out of VRAM and freezing for a few frames every second. This was not tolerable, so I broke out my tools and GPU-Z's verdict was without appeal : the game used almost all of my Radeon HD 6870's 1Gb video memory. Outch.

It turns out, that in meshed voxels engine like most Minecraft-likes uses, the main video ram eater is actually chunk geometry. I looked at Minecraft's usage and it had a similar pattern, using hundreds of megs of VRAM, until running out and purging some, returning to about 600Mb used in total when standing still on far distance. So it definitely wasn't a particular design flaw of my engine, at least not compared to minecraft's, but in my engine, in my test cases, it was a game-breaker. My engine used even more VRAM than Minecraft did, probably because I stored the normals for the blocks inside the vertices, instead of computing them in a geometry shader or something. At this point it used 44 bytes per vertice, this had to go down.

idle_ff_.pngmcrunnng.png

Left : Idle with Firefox Open, Right : Minecraft 1.8.8 16 chunks distance

Fixing this issue meant compacting the vertex data into much more less bytes. I went on the OpenGL wiki and read about others ways to provide OpenGL vertex data than just regular SP floats. I could use half-floats, ints, shorts, bytes, and all sorts of exotics weird formats that packed bits in improbable structures. At first I went with GL_UNSIGNED_BYTE, but I discovered with horror that not only it didn't ran better, but it ran slower, much slower. After having spent a good hour refactoring my code, I almost went to bed, until I read about alignment. Basically GPUs don't like it when data don't come in packs of 4 bytes, and from what I read, my radeon was probably emulating that part of the graphics pipeline in software mode due to bad alignement ( 3 unsigned bytes without padding ). So I went for this weird format that packs 4 values into 2, 10, 10 and 10 bits-wide parts of a single 32-bit uint. It actually is supported almost everywhere, and requires either OpenGL 3.0, or a common extension ( Even an intel GMA from a netbook has it ). The data structure can be summarized as :

graphics.png

The normal part is still stupidly too expensive for what it codes for, but I haven't since bothered to optimise it further, I'm busy refactoring other parts of the engine.

When this optimization was done the engine had a massive boost, becoming able to render easily 15M faces at once, at stable frame rates, with hundreds of mbs of vram to spare. It will require me to have a separate vbo region with half-floats to put the non-blocky blocks shapes into, but it's already a big step forward, and now my engine can claim to be "more optimized" than Minecraft's ... well at least it is now for VRAM.

render.png

If you liked this post, found it useful, full of silly mistakes or terrible misconceptions about what I'm talking about, feel free to discuss it in the comments section below !