Data Structures
Note: This section generally covers runtime storage, not serialization.
The simplest way to store voxels is to define a three-dimensional array of elements (be it struct
s or integer
s), where each element represents a single voxel:
int width = ...;
int height = ...;
int depth = ...;
var voxels = new VOXEL[width][height][depth];
// Set a voxel:
voxels[x][y][z] = voxel;
// Get a voxel:
var voxel = voxels[x][y][z];
However, because storing arrays within arrays often means having pointers pointing at pointers (which ain't good for various reasons we won't get into here), it is generally recommended to use a one-dimensional array with a clearly defined spatial indexing scheme.
Here's an example:
--snip--
// Spatial Indexing Scheme is: Y-height, Z-depth, X-width
// The arrays size is just all axes multiplied together:
var voxels = new VOXEL[height * depth * width];
// Our Indexing Formula is the indexing scheme in reverse,
// with the components being multiplied subsequently:
// x + z*width + y*width*depth
// So let's define a function (here a lambda) for it:
var idx = (int x, int y, int z) => (x + z*width + y*width*depth);
// ^ NOTE: You may want to throw an error right here
// if the coordinate components are out of bounds.
// Set a voxel:
voxels[idx(x,y,z)] = voxel;
// Get a voxel:
var voxel = voxels[idx(x,y,z)];
Now, storing voxels in a plain array like this is perfectly fine for small scenes...
However, for larger scenes, we'll have to use a data-structure that allows both loading and purging parts of our volume (called Chunks) from memory, nearly in realtime, without slowing down accessing our voxel data.
Note: These techniques can often be combined.