## Fun with voxels

by on May.15, 2012, under Gamedev

I’ve been working on a new game lately, with a nice pseudo-3D effect for the display. After a while, it dawned on me that what I was doing there essentially amounted to voxels. Which was strange, because while I had read about voxels before, my interest in the topic was academic at best. But now the connection was made, I decided to take a closer look, just to know what possibilities I might be overlooking.

But first, what exactly are voxels?

You know what pixels are, right? On the computer, an ordinary two-dimensional image is made of little dots arranged in a grid. Whenever you want to see what the image represents, you simply draw each dot on the screen, row after row, making sure the dots in each row line up vertically. Well, voxels are exactly the same thing, except in 3D.

Which brings up an obvious question: short of an actual volumetric display, how do you present a three-dimensional grid of dots to a viewer? Why, via 3D projection of course! And as I demonstrated in a previous article, that’s really easy to do for the basic case.

``````var TwoPointFive = {
Camera: function (x, y, z, f) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
this.f = f || 200;
},

project: function (x, y, z, camera) {
x -= camera.x;
y -= camera.y;
z -= camera.z;
var scale = camera.f / z;
var px = x * scale;
var py = y * scale;
return [px, py, scale];
}
}
``````

With that in place, all we have to do is go over each layer in turn and plot the coordinates of each voxel on screen.

``````for (var z = DEPTH - 1; z >=0; z++) {
for (var x = 0; x < WIDTH; x++) {
for (var y = 0; y < HEIGHT; y++) {
var p = TwoPointFive.project(x, y, z, camera);
// Determine the voxel's color somehow.
var color = getColor(x, y, z);
}
}
}
``````

Here, I make sure to start from the back and come towards the camera, a.k.a. painter’s algorithm. A more popular option nowadays is to generate a cube around each voxel and let OpenGL worry about the rendering; but then, that would take care of the 3D projection as well. As it is, I simply paint each voxel as a square, scaled according to distance from the camera (see source code).

Wait… isn’t it cheating to use a flat image in a discussion of volumetric pixels? That’s more like… a texture! No, really, it is. It’s also the same basic principle; with voxels, we simply have layer after layer of data, instead of just one. Which presents a problem.

Believe it or not, this coarse scene — full code here — contains as many voxels as the one before. (Though mostly obtained by mirroring.) The square-cube law ensures that the amount of data required increases fast with resolution. Luckily, there are ways to mitigate this problem.

This is an ordinary heightmap (see code), except rendered with voxels instead of polygons. The height of each data point is encoded in its shade of gray. It works because we’re only interested in the surface — and as a bonus, we can still use the same value to color the voxel. (Under realistic conditions, a color map would be in order.) Note how I’ve drawn the voxels taller than they are wide in order to hide the seams, and it’s still not perfect. I guess there’s a reason polygons are more popular.

What’s the point of using voxels, then? Nowadays, they are mostly used as a stylistic choice, as they give games a very distinctive appearance. They also naturally enable fully modifiable environments, something rather difficult to implement in a polygonal world. Otherwise, polygons are better studied and directly supported by the commodity GPUs built into almost any computer.

Back around 1997, however, before 3D acceleration was ubiquitous, voxels were enjoying considerable attention. Quite a few famous games used voxels for some or all of their graphics, Blade Runner being my favorite example. See, voxels are easy to understand, and require very simple calculations. But the comparative difficulty of animating voxel objects, together with the march of technology, relegated them to just another tool in the toolbox. Use wisely.

(Illustration: Voxel Fashion Party, by Raffi Asdourian; CC-BY. Tux icon courtesy of OpenClipart.org.)