Daily Archives: December 2, 2014

Journal Entry 61 – Rotating Voxel Chunks

Tonight will be a pretty quick write up, but I’d like to share some of what I’ve been working on these past few days. Over the weekend I was thinking about procedural generation, and decided to start working on a procedural farm. One of the first items I tackled was a fence around the property, which was difficult to do. I would have to create fence assets that ran in both north to south and east to west directions, as well as any corner pieces, etc that I would require. It would be nice if I could somehow create an asset once, and then include information in the chunk ID to rotate the chunk by an arbitrary amount.

The final result was simply adding a new voxel type. As I’ve mentioned before, each of my voxels is a 16 bit ushort. This 16 bit value has many different uses. It can represent a color with 5 bits for each of the R, G and B components. It can also be a transparent color, or contain an ID which references another voxel chunk, it can be a plant, or water, or anything else that I would like to dream up (as long as it fits in the 16 bit space). I’ve created a new voxel type that includes a 10 bit ID and a 2 bit rotation, allowing for the item to be rotated 0, 90, 180 or 270 degrees.

Here we use the same model, but rotate it 0, 90, 180 and 270 degrees to get a more detailed scene.
Here we use the same model, but rotate it 0, 90, 180 and 270 degrees to get a more detailed scene.

This was actually very simple to do, and only required a small modification to the code that deals with processing what I’ve called ‘detailed voxel chunks’. Detailed voxel chunks are voxels that exist in a world chunk that reference another voxel chunk. A simple example would be a plant, which is itself a voxel chunk that is placed within a parent voxel chunk. These chunks can be embedded indefinitely, and I needed to make a small modification to this bit of a code to allow for rotation.

// if this is a chunk that can be rotated then we need to do a bit more work
if ((t & 0xF000) == 0x9000)
{
    // swap the x and z sizes since we've rotated this chunk either 90 or 270 degrees
    if ((t & 0x0C00) == 0x0C00 || (t & 0x0C00) == 0x0400)
    {
        position = BoundingBox.Min + new Vector3(x - center.z * scale + 0.5, y, z - center.x * scale + 0.5) + new Vector3(chunk.minz, chunk.miny, chunk.minx) * scale;
        box = new AxisAlignedBoundingBox(position, position + new Vector3(chunk.maxz - chunk.minz, chunk.maxy - chunk.miny, chunk.maxx - chunk.minx) * scale);
    }
    else box = new AxisAlignedBoundingBox(position, position + new Vector3(chunk.maxx - chunk.minx, chunk.maxy - chunk.miny, chunk.maxz - chunk.minz) * scale);
 
    // calculate the rotation angle of the detailed voxel chunk
    float angle = (float)((t & 0x0C00) >> 10) * (float)Math.PI * 0.5f;
 
    // first we must translate the chunk to the origin, then rotate it, then translate it to the desired position
    modelMatrix = Matrix4.CreateTranslation(new Vector3(-center.x, 0, -center.z)) * 
                  Matrix4.CreateRotationY(angle) * 
                  Utilities.FastMatrix4(new Vector3(x + 0.5, y, z + 0.5), new Vector3(scale, scale, scale));
}

The code will first check to see if the voxel is a rotated voxel chunk. If so, it will then calculate the correct bounding box for the chunk. The bounding box is used for picking, and depends on the rotation (we need to swap the x and z when the chunk is rotated either 90 or 270 degrees). Then we compute the rotation, which is determined via 2 bits in the 16 bit voxel identifier. Finally, we create a model matrix for this voxel chunk. The model matrix is a bit of a pain, because rotations must happen around the origin. To accommodate this we first translate the voxel chunk into the origin, then we perform the rotation, and then we translate it back out to the designated position.

Finally, we can build the fence that we set out to build! This uses the same fence voxel chunk for the entire fence, but it is rotated in code. This makes it easier on the asset creators (you only need one model and can re-use several times) and on the procedural generation. I’m hoping to be able to make all sort of cool new effects with the help of this voxel type.

This fence can be easily built procedurally with the ability to rotate voxel chunks.
This fence can be easily built procedurally with the ability to rotate voxel chunks.

Tomorrow I’m going to start tackling the creation of a full water mill! I’d like to be able to demo the crafting system and be able to turn wheat into flour. Stay tuned,

Giawa