Voxel and Voxel Data Encoding โ
This page describes how voxels and voxel grid data are encoded in Foxel.
Voxel Encoding โ
In Foxel, a voxel is stored as a 32-bit unsigned integer.
The individual bits store shape, rotation, color, material, and selection state.
| Bits | Property | Valid values | Description |
|---|---|---|---|
| ๐จ | Selection bit | [0..1] | Indicates whether the voxel is selected. |
| ๐ฅ | Material ID | [0..127] | Index of the material in the material map. |
| ๐ซ | โ | โ | Currently unused and reserved. |
| ๐ฉ | Color ID | [0..255] | Index of the color in the Color Palette. |
| ๐ฆ | Shape ID | [0..5] | Identifies the voxel shape. |
| ๐ช | Rotation ID | [1..24] | Identifies the voxel rotation using one of the 24 box rotations. |
INFO
Rotation ID starts at 1 and cannot be 0. This ensures that solid voxels are always non-zero.
Shape ID cannot be 7, because that value is reserved for run-length encoding.
Voxel Data Encoding โ
A voxel grid is stored internally as a one-dimensional array of unsigned integers.
To preserve voxel positions, voxels are written in a fixed order. To reduce memory usage, Foxel stores voxel data as run-length encoded columns.
Run-length encoding uses a special flag value to indicate that the next voxel value is repeated multiple times:
uint rleflag = (runlength << 8u) | 250u;Sample Code โ
The following examples show the basic principles of decoding voxels and encoding or decoding voxel grid data.
Decoding Voxels โ
uint voxel;
vec4 materials[128];
vec3 colors[256];
// ...
// initialize voxel, materials, and colors
// ...
bool isSolid = (voxel != 0u);
bool isAir = (voxel == 0u);
uint rotationID = voxel & 31u;
uint shapeID = (voxel >> 5u) & 7u;
uint colorID = (voxel >> 8u) & 255u;
uint materialID = (voxel >> 24u) & 127u;
bool selected = ((voxel & 2147483648u) != 0u);
bool isValid = (voxel != 0u && rotationID > 0u && rotationID < 25u && shapeID < 7u);
vec3 color = colors[colorID];
vec4 material = materials[materialID];
float metallic = material.x;
float roughness = material.y;
float emissive = material.z;
float alpha = material.w;
bool isRLE = ((voxel & 250u) == 250u);
uint runlength = (voxel >> 8u) & 16777215u;Encoding Voxel Data โ
The following example encodes a 3D voxel grid into a one-dimensional data array.
uint grid[][][];
// ...
// initialize grid
// ...
uint data[];
uint voxel;
uint rleflag;
int sizex = sizeof(grid);
int sizey = sizeof(grid[0]);
int sizez = sizeof(grid[0][0]);
int index = 0;
int runlength;
for (int x = 0; x < sizex; x++)
{
for (int z = 0; z < sizez; z++)
{
runlength = 1;
for (int y = 0; y < sizey; y++)
{
voxel = grid[x][y][z];
if (y < sizey - 1 && voxel == grid[x][y + 1][z])
{
runlength++;
}
else
{
if (runlength == 1)
{
data[index] = voxel;
index++;
}
else
{
rleflag = (runlength << 8u) | 250u;
data[index] = rleflag;
data[index + 1] = voxel;
index += 2;
runlength = 1;
}
}
}
}
}Decoding Voxel Data โ
The following example decodes a one-dimensional voxel data array back into a 3D voxel grid.
uint sizex;
uint sizey;
uint sizez;
uint data[];
// ...
// initialize sizex, sizey, sizez, and data
// ...
uint datasize = sizeof(data);
uint grid[][][];
int index = 0;
int runlength;
uint value;
int x = 0;
int y = 0;
int z = 0;
while (index < datasize)
{
value = data[index];
if ((value & 250u) == 250u)
{
runlength = (value >> 8u) & 16777215u;
value = data[index + 1];
for (int i = 0; i < runlength; i++)
{
grid[x][y + i][z] = value;
}
index += 2;
y += runlength;
}
else
{
grid[x][y][z] = value;
index++;
y++;
}
if (y == sizey)
{
y = 0;
z++;
if (z == sizez)
{
z = 0;
x++;
}
}
}