Voxel3D in Polyphase Engine
Overview
Voxel3D is a runtime-editable voxel mesh node that allows creation of block-based terrain and structures. It uses PolyVox for voxel storage and cubic mesh extraction, generating renderable geometry from a 3D grid of voxel values.
Key features: - Runtime voxel manipulation via C++ and Lua - Automatic mesh generation from voxel data - Scene persistence with RLE compression - Dirty-flag based rebuild system for efficiency
How It Works
Voxel Storage
Voxel3D uses PolyVox's RawVolume<uint8_t> for voxel storage:
- Voxel values: 0 = air (empty), 1-255 = solid material IDs
- Default dimensions: 32x32x32 voxels
- Coordinate system: Integer coordinates (x, y, z) starting from (0, 0, 0)
Mesh Extraction Pipeline
- When voxels are modified, the node is marked dirty
- On the next tick,
RebuildMeshInternal()is called - PolyVox's
extractCubicMesh()generates a blocky mesh from the volume - Vertices are converted to engine
VertexColorformat with per-face normals - Material IDs are mapped to colors (see Material ID to Color mapping below)
- The mesh is uploaded to the GPU
Material ID to Color Mapping
| ID | Color | Description |
|---|---|---|
| 0 | Transparent | Air (not rendered) |
| 1 | Light Gray | Stone/Default |
| 2 | Brown | Dirt |
| 3 | Green | Grass |
| 4 | Blue | Water |
| 5 | Red | - |
| 6 | Yellow | - |
| 7 | Dark Gray | - |
| 8+ | Auto-generated | HSV-based rainbow |
C++ API
Voxel Access
// Set a single voxel
void SetVoxel(int32_t x, int32_t y, int32_t z, VoxelType value);
// Get a voxel value (returns 0 if out of bounds)
VoxelType GetVoxel(int32_t x, int32_t y, int32_t z) const;
// Fill the entire volume
void Fill(VoxelType value);
// Fill a box region (coordinates are clamped to volume bounds)
void FillRegion(int32_t x0, int32_t y0, int32_t z0,
int32_t x1, int32_t y1, int32_t z1, VoxelType value);
Mesh Control
// Mark mesh for rebuild on next tick
void MarkDirty();
// Force immediate mesh rebuild
void RebuildMesh();
// Check if rebuild is pending
bool IsDirty() const;
Dimensions
// Get current dimensions
glm::ivec3 GetDimensions() const;
// Set dimensions (recreates volume, clears data)
void SetDimensions(glm::ivec3 dims);
Lua API
Example Usage
-- Create a voxel node
local voxel = world:SpawnNode("Voxel3D")
voxel:SetPosition(Vec(0, 0, 0))
-- Fill with stone
voxel:Fill(1)
-- Carve out a sphere of air
local cx, cy, cz = 16, 16, 16
local radius = 8
for x = cx - radius, cx + radius do
for y = cy - radius, cy + radius do
for z = cz - radius, cz + radius do
local dx, dy, dz = x - cx, y - cy, z - cz
if dx*dx + dy*dy + dz*dz < radius*radius then
voxel:SetVoxel(x, y, z, 0)
end
end
end
end
-- Force rebuild (optional - happens automatically on tick)
voxel:RebuildMesh()
Method Reference
| Method | Arguments | Returns | Description |
|---|---|---|---|
SetVoxel |
x, y, z, value |
- | Set voxel at position |
GetVoxel |
x, y, z |
int |
Get voxel value |
Fill |
value |
- | Fill entire volume |
FillRegion |
x0, y0, z0, x1, y1, z1, value |
- | Fill box region |
MarkDirty |
- | - | Mark for rebuild |
RebuildMesh |
- | - | Force immediate rebuild |
IsDirty |
- | bool |
Check if rebuild pending |
GetDimensions |
- | vec3 |
Get volume dimensions |
Platform-Specific Behavior
Vulkan (Windows / Linux / Android)
- Full support: Mesh data uploaded to GPU vertex/index buffers
- Uses
VertexColorvertex type for per-voxel coloring - Single draw call per
Voxel3Dnode
GameCube / Wii (GX) and 3DS (C3D)
- Stub implementations: Currently not rendering
- Future work: Implement display list generation for GX, vertex buffer for C3D
- Consider chunk-based rendering and reduced volume sizes for memory constraints
Serialization
Voxel data is embedded in scene files using RLE (Run-Length Encoding) compression:
Format:
- 3x int32: dimensions (x, y, z)
- uint32: compressed data size
- N bytes: RLE pairs [count, value, count, value, ...]
For a 32x32x32 volume: - Worst case (random data): ~65KB - Best case (uniform fill): ~2 bytes - Typical case: ~1-10KB depending on complexity
Collision
Current implementation uses a simple bounding box collision shape covering the entire volume dimensions. This provides basic physics interaction but does not conform to the voxel geometry.
Future enhancements (not in MVP): - Per-voxel box collision - Triangle mesh collision from extracted geometry - Chunk-based collision for larger volumes
Practical Guidance
When to Use Voxel3D
Good use cases: - Destructible terrain or structures - Runtime-editable building/crafting systems - Procedurally generated cave systems - Simple block-based levels
Consider alternatives when:
- Static geometry (use StaticMesh3D for better performance)
- Large open worlds (current implementation doesn't support chunking/streaming)
- High-detail organic shapes (voxels are inherently blocky)
Performance Considerations
- Volume size: Keep dimensions small for MVP (32x32x32 = 32K voxels)
- Rebuild frequency: Batch voxel changes before triggering rebuild
- Draw calls: Each
Voxel3Dnode is one draw call - Memory: Volume data + generated mesh vertices + GPU buffers
Best Practices
- Batch modifications: Set multiple voxels before the next tick to avoid multiple rebuilds
- Use FillRegion: More efficient than individual
SetVoxelcalls for large areas - Material override: Assign a custom material for texturing instead of vertex colors
- Smaller volumes: Multiple smaller volumes can be more efficient than one large volume
Configurable Properties
Properties exposed in the editor inspector:
| Property | Type | Default | Description |
|---|---|---|---|
| Dimension X | Integer | 32 | Volume width in voxels |
| Dimension Y | Integer | 32 | Volume height in voxels |
| Dimension Z | Integer | 32 | Volume depth in voxels |
| Material Override | Material | None | Custom material (inherited from Mesh3D) |
Future Roadmap
Features planned for future phases:
- Chunking: Split large volumes into smaller chunks for efficient updates
- Streaming: Load/unload chunks based on camera distance
- LOD: Simplified meshes for distant chunks
- Triangle collision: Accurate collision from mesh geometry
- Editor tools: Paint mode for sculpting voxels
- Console optimization: Platform-specific rendering for GX/C3D
- Marching cubes: Smooth surface extraction option