Smooth Voxels and Texture Blending

Some work has recently gone into the smooth voxel renderer; drawing blocks as smooth connected surfaces rather than cubes. This is done on a per-material level, and these smooth blocks also store a kind of density value – the amount of material in the block – allowing for rougher, more organic surfaces.

Since smooth blocks can extend into adjacent blocks’ volumes, there needs to be some kind of blending between the textures. Rather than straight alpha blending, we’re looking into using the bump map from the textures to blend the two as though they were simply sloped into each other naturally. This feature probably won’t be done in time for the first release, but it’s a neat idea, and I can’t wait to see it in-engine. Here’s an test example of the results of this algorithm blending two materials together:

Art Asset Overview

Currently I am in charge of all the art assets going into the game. Daunting as this is, I’ve already started on some of the more immediately important things, such as a debug character model. Here is a render of a really rushed Ice Elemental kind of character/creature (this will be replaced by an actual character model later):

I literally threw this together in an hour and stole some ice texture from the internet somewhere...

And what he looks like ingame:

The shader Alex threw together looks tons better, you can see the sky reflecting in his head there.

Some Monster concepts, although most of these have already been rejected and recycled into another project:

I only fully rendered the Meat and the Mushroom, the others I'm saving for another time

Finally, I’ve also begun, and nearly finished in the past week the background for the menusystem of the game – which also doubles as some concept art for the landscapes. Here’s a Concept Video I rendered in Blender demonstrating how the images should scroll in the menu.

My next project before the Teaser Release is to paint the textures for the first 12 block types. This will not be pixel art, and it will not be flat. We want to approach a level of visual quality somewhere between Braid and Skyrim. I want to see some obviously painted textures for landscape and general scenery, but more refined rendering for important things like trees, objects, characters and creatures.

Update, and Memory Management

I’ve been spending a lot of time recently cleaning up the engine from a memory standpoint. We hit our ‘teaser release’ feature mark a while ago, and now it’s polish time. And it’s a good thing we’re working on this now, to be honest, because the more we write the harder it will be to tighten up later. Unfortunately there’s not much glamour in this part of my job, but the topic has been on my mind, and if you do any development yourself you might be interested anyway. If not, tune in for the next post, where I promise we’ll have some new screenshots :)

The engine is all C++, so memory management is a big concern. We’re really pushing for performance and scale in the engine, so having freedom of memory is useful (which you don’t get so much in managed languages). For instance, the vertex and index arrays that are allocated when chunk meshes are being built are massive – there could be 6000 triangles on an average chunk, each requiring maybe 52 bytes of storage. We have to temporarily allocate this every time a chunk is drawn: that’s 343 times (107MB, with these estimates) without even moving from the spawnpoint! We get around this problem by having a large circular buffer that the chunk generator instances can share. It’s a single block of memory that can be reused, rather than allocating and freeing from the heap hundreds of times (which leads to fragmentation).

This freedom comes with a cost, though, as anyone who’s taken a C programming class can attest. Every block of memory allocated must be freed. This is often harder than it looks; certain objects have very complex lifetimes, and it’s difficult to say for sure who should be responsible for freeing them, and when. There are a few ways to deal with this.

The first way is to actually have a defined lifetime for objects, and make sure you stick to them. This takes some discipline to implement well. If you miss something, it can be hard to catch without tools. Visual C++ has a built-in debug allocator that tracks allocated blocks. You can read about it here, if you’re interested. In order to track down what you’ve missed, it will print out the filename and line number of any allocations that were never freed. It can only do this, however, if calls to new are replaced with calls to new(_NORMAL_BLOCK,__FILE__,__LINE__). Unfortunately, there is no way (that I’ve found) to pass in these parameters with the placement syntax.

A tip like that could save your life one day.

The next approach is to use memory management objects such as smart pointers. A lot of our objects are stored in Lua states as well as game structures. Lua’s garbage collector can tell us when Lua is done using the object, but we don’t know if something else in the engine is holding onto it. A good example of this is the player. When a player joins, an Actor object is created to handle the character’s behavior. This object must exist as long as the player is in the game, since it receives user commands, etc. But to the Lua scripts, it’s just another object that can be discarded freely. Smart pointers are a great way to make sure the object isn’t freed until everyone’s done using it. A smart pointer wraps a regular pointer and maintains a reference count. Many copies of this smart pointer can exist (and be destroyed), but they all share this reference count. The actual object is only destroyed when the reference count reaches zero – no one is using the pointer anymore. Smart pointers are a little slower and more expensive to create (an extra allocation for the reference count), and they aren’t a magic bullet – they don’t perform real garbage collection, and are susceptible to circular references – but there are some very efficient implementations, and they solve a lot of headaches you encounter in unmanaged languages like C++.

We use both of these approaches; some tasks are more suited to the dynamic behavior of smart pointers, and some simply require that we buckle down and work out the object lifetime by hand. The goal of all this effort, and of the ‘teaser release’ in general, is to minimize waste and squeeze every last bit of performance out of the engine before we get too involved in the features. It’s getting there.

 

Voxels Engine

Here’s a brief summary of the progress and scope of our voxel game engine.

Interest in putting together a game with voxel terrain motivated a number of prototypes in spring of 2011. These prototypes covered a few basic features we wanted to play with – unlimited distance in any direction with data streaming from a server, a full scripting interface, and some different approaches to rendering the voxels. In summer and fall, work began on the actual engine, and we’re nearing our first milestone.

Terrain generator output
One early prototype was a high-level algorithm for designing believable continents with biomes, rivers, lakes, and eventually fauna and civilization. The parameters for this generator could be designed in a node-editor based system for stringing together generation primitives.
Terrain generator node editor

For simplicity the engine currently only draws voxels as cubes, iconic for this genre. More advanced methods of hybrid cube and isosurface rendering are in development. One of the prototypes demonstrates this isosurface rendering of discrete terrain (in 2d) in a way that is compatible with certain materials rendering as cubes, and others rendering with varying density levels.
Smooth terrain

To better render a dynamic smoothed terrain, the terrain shader implements tri-planar texturing over multiple voxel faces. In the case where the voxels are rendered as cubes, this results in a high resolution texture being tiled across multiple faces, helping to break up repetition artifacts.
Triplanar texturing

One of the biggest problems in voxel engines to date has been view distance. We have some ideas in mind to help give the impression of a massive view distance without needing to load (or generate!) terabytes of voxel data. They borrow from the standard LOD techniques of contemporary games as well as taking advantage of the nature of the data we’re dealing with. It wasn’t so much a prototype for this effect as just a side project, but over the summer a simple space flight simulator was written. It uses the same unlimited-distance mechanism as the voxel volume to let the player travel light-years, seeing procedurally generated stars and planets. These stars and planets are rendered with some fairly complex level-of-detail systems to prevent z-buffer fighting, etc., that we plan on using in this new engine to allow players to see distant mountains and structures.
Space sim

This first milestone represents a stable version with limited features that we can use to set up a build system and stress test the most basic and crucial components of the engine: networking, player characters, and of course the voxel volume. Players should be able to run around and modify the terrain freely using a subset of the materials we plan on including in the game. The scripting interface is also going to be available for people interested in modding to start getting a feel for it. There may be future open testing releases as we implement more features and begin working on elements of gameplay.

Deep

At the moment, the networking is almost complete. The scripting interface is sufficiently finished to allow for development of multiplayer actors and simple non-voxel objects. The voxel renderer only supports block meshes, but it does so very efficiently. Once the final engine bits have been completed, we’re going to spend a little time making a presentable set of materials and textures, and a new worldgen algorithm that knows how to place them. And maybe, just maybe, by then we’ll have come up with a name.

The engine is written in C++, and builds as singleplayer, multiplayer client, and dedicated server. Our development focus is on Windows, but Mac and Linux support is soon to follow (especially for the server!) The client uses Ogre as the primary graphics library and irrKlang for audio.

Subscribe to this blog if you’d like to get updates about our progress, as well as be the first to hear about any releases. Thanks for the interest!