Chunking
The first and possibly most important step when dealing with voxels, is to divide the voxel grid into chunks. Regardless of what kind of data-structure one ultimately ends up using, at the bottom of it there will likely be chunks containing voxels (when using a tree-like structure, chunks may be called bricks).
Motivation
TODO: Explain the reasoning behind chunking.
Code Example
Let's implement chunking, shall we?
class Chunk {
// How many voxels does the chunk contain on any given axis?
public const int EDGE_LEN = 32;
// Size of a single slice of the chunk.
public const int VOX_AREA = EDGE_LEN * EDGE_LEN;
// Position of the chunk within the scene.
public int chunk_x;
public int chunk_y;
public int chunk_z;
// Voxel Data.
public VOXEL[] voxels;
public Chunk(int x, int y, int z) {
chunk_x = x;
chunk_y = y;
chunk_z = z;
voxels = new VOXEL[EDGE_LEN*EDGE_LEN*EDGE_LEN];
}
public VOXEL get(int local_x, int local_y, int local_z) {
return voxels[local_x + local_y*EDGE_LEN + local_z*VOX_AREA];
}
public void set(int local_x, int local_y, int local_z, VOXEL voxel) {
voxels[local_x + local_y*EDGE_LEN + local_z*VOX_AREA] = voxel;
}
}
And then, to use it:
Chunk[][][] chunks = /* ? */;
var x = 1;
var y = 2;
var z = 3;
// Get the chunk...
var chunk = chunks[x / Chunk.EDGE_LEN][y / Chunk.EDGE_LEN][z / Chunk.EDGE_LEN];
// Set the voxel:
chunk.set(x % Chunk.EDGE_LEN, y % Chunk.EDGE_LEN, z % Chunk.EDGE_LEN, voxel);
// Get the voxel:
var voxel = chunk.get(x % Chunk.EDGE_LEN, y % Chunk.EDGE_LEN, z % Chunk.EDGE_LEN);
Having to write all these divisions time and time again might be a bit annoying, so let's give the chunk some extra methods:
class Chunk {
/* --- SNIP --- */
public VOXEL get_from_world(int x, int y, int z) {
return this.get(x - chunk_x*EDGE_LEN, y - chunk_y*EDGE_LEN, z - chunk_z*EDGE_LEN);
}
public void set_from_world(int x, int y, int z, VOXEL voxel) {
this.set(x - chunk_x*EDGE_LEN, y - chunk_y*EDGE_LEN, z - chunk_z*EDGE_LEN, voxel);
}
}
Which makes using the chunk much simpler:
/* --- SNIP --- */
// Set the voxel:
chunk.set_from_world(x, y, z, voxel);
// Get the voxel:
var voxel = chunk.get_from_world(x, y, z);
In all of the above code, you might have noticed that nearly all coordinate variables have prefixes: There is a good reason for that.