How to Convert Textured Meshes to O-Voxel Format for TRELLIS.2 Training Data
To convert textured meshes to O-Voxel format for TRELLIS.2 training data, use the data_toolkit/dump_mesh.py script which loads your mesh, rasterizes it via CUDA-accelerated voxelization in o_voxel/rasterize.py, and serializes the result to a compact .o_voxel binary file.
TRELLIS.2 trains on a proprietary sparse-voxel representation called O‑Voxel that efficiently stores fully textured 3D assets with their PBR attributes. Before you can train the model, you must preprocess your source meshes—whether OBJ, GLTF, or PLY—into this format. The Microsoft TRELLIS.2 repository provides a complete conversion pipeline that runs without rendering and completes in under 10 seconds per mesh on a single CPU core.
Prerequisites: Install the O-Voxel Library
The conversion tools depend on compiled CUDA kernels. Initialize the submodule before your first conversion:
. ./setup.sh --o-voxel
This pulls and builds the o-voxel package located at o-voxel/o_voxel/ in the repository root.
Method 1: Command-Line Conversion (Recommended)
The fastest way to convert textured meshes to O-Voxel format is through data_toolkit/dump_mesh.py. This script orchestrates the full pipeline: loading, rasterization, serialization, and metadata generation.
python data_toolkit/dump_mesh.py \
--mesh_path /path/to/your_mesh.obj \
--output_path /path/to/output_dir/your_mesh.o_voxel \
--resolution 256
Key Arguments
| Argument | Description |
|---|---|
--mesh_path |
Path to source mesh with texture coordinates and PBR materials |
--output_path |
Destination .o_voxel file path |
--resolution |
Voxel grid resolution per axis (default: 256) |
--voxel_size |
Physical voxel size in world units (default: 1/resolution) |
--attributes |
PBR channels to retain: color,roughness,metallic,opacity |
The script automatically extracts vertex positions, face indices, and per-vertex texture attributes during loading. It then invokes the rasterizer and writes a JSON sidecar (metadata.json) recording the source name, resolution, and preprocessing flags.
Method 2: Python API for Batch Processing
For dataset-scale conversion, use the o_voxel module directly in Python. This approach gives you full control over batching, parallelization, and custom preprocessing.
import os
from trellis2.utils.vis_utils import load_mesh
import o_voxel
def mesh_to_ovoxel(mesh_path, out_path, resolution=256):
# Step 1: Load mesh with PBR attributes
mesh = load_mesh(mesh_path)
# Step 2: CUDA-accelerated rasterization
voxel_grid = o_voxel.rasterize(
vertices=mesh.vertices,
faces=mesh.faces,
attributes=mesh.attributes, # dict of PBR channels
resolution=resolution,
voxel_size=1.0 / resolution,
)
# Step 3: Serialize to O-Voxel binary format
o_voxel.serialize(
voxel_grid,
out_path,
aabb=[[-0.5, -0.5, -0.5], [0.5, 0.5, 0.5]],
attr_layout=mesh.attr_layout,
)
# Step 4: Write metadata JSON
metadata = {
"source_mesh": os.path.basename(mesh_path),
"resolution": resolution,
"voxel_size": 1.0 / resolution,
}
with open(out_path + ".json", "w") as f:
import json
json.dump(metadata, f, indent=2)
Parallel Batch Conversion
The rasterizer creates isolated CUDA contexts per process, making it thread-safe for parallel execution:
from concurrent.futures import ProcessPoolExecutor
mesh_files = [f for f in os.listdir("my_meshes") if f.endswith(".obj")]
with ProcessPoolExecutor(max_workers=8) as executor:
executor.map(
lambda f: mesh_to_ovoxel(
os.path.join("my_meshes", f),
os.path.join("ovoxels", f.replace(".obj", ".o_voxel")),
256
),
mesh_files
)
Verifying Your O-Voxel Output
Confirm successful conversion by deserializing and inspecting the voxel grid:
import o_voxel
voxel = o_voxel.deserialize("my_asset.o_voxel")
print("Voxel shape:", voxel.shape) # (256, 256, 256, 4)
print("Attribute layout:", voxel.layout) # e.g., ['color', 'roughness', 'metallic', 'opacity']
If the grid appears empty or distorted, verify that your source mesh contains UV coordinates in the [0, 1] range and valid PBR material channels. The rasterizer in o-voxel/o_voxel/rasterize.py requires properly unwrapped textures to interpolate attributes onto the voxel grid.
Core Pipeline Components
Understanding the underlying implementation helps debug conversion failures and optimize for your data.
Mesh Loading: data_toolkit/dump_mesh.py
The CLI entry point at data_toolkit/dump_mesh.py handles:
- Triangle mesh ingestion via
trimesh.loador internal loaders - Extraction of per-vertex PBR attributes (base color, roughness, metallic, opacity)
- Coordination with the rasterization and serialization modules
Voxel Rasterization: o-voxel/o_voxel/rasterize.py
The CUDA kernel implemented in o_voxel/rasterize.py projects mesh triangles onto a 3D grid. For each voxel intersecting a triangle, it barycentrically interpolates the four PBR channel values. This operation is render-free—it operates directly on geometry without GPU rendering pipelines.
Binary Serialization: o-voxel/o_voxel/serialize.py
The o_voxel.serialize() function in o-voxel/o_voxel/serialize.py compresses the dense voxel grid into the .o_voxel format. The binary structure stores:
- Voxel dimensions and axis-aligned bounding box
- Attribute layout descriptor
- Run-length encoded voxel data for sparse regions
Performance Characteristics
| Aspect | Specification |
|---|---|
| Runtime | < 10 seconds per mesh (256³ resolution, single CPU core) |
| Memory | Proportional to resolution³ × 4 channels × 4 bytes |
| Parallelism | Multi-process safe; each worker requires separate CUDA context |
| Input requirements | Watertight mesh preferred; requires UVs and PBR materials |
Connecting to Training
Once converted, reference your O-Voxel files in the training configuration. The train.py script accepts a --data_dir argument pointing to a JSON manifest that lists your .o_voxel paths. See data_toolkit/README.md for the expected directory layout and manifest format.
Summary
- Install dependencies: Run
. ./setup.sh --o-voxelto build CUDA kernels - Single conversion: Use
python data_toolkit/dump_mesh.pywith--mesh_pathand--output_path - Batch processing: Import
o_voxeldirectly and parallelize withProcessPoolExecutor - Verify output: Call
o_voxel.deserialize()to inspect grid shape and attribute layout - Troubleshoot: Ensure source meshes have valid UVs in
[0, 1]and complete PBR channels
Frequently Asked Questions
What mesh formats does the O-Voxel converter support?
The converter supports OBJ, GLTF, GLB, and PLY files through the trellis2.utils.vis_utils.load_mesh() utility. All formats must include texture coordinates and material definitions for the PBR channels you intend to rasterize. Untextured meshes will produce voxel grids with default attribute values.
Why is my output voxel grid empty?
Empty grids typically indicate missing or malformed UV coordinates. The rasterizer in o-voxel/o_voxel/rasterize.py requires texture coordinates to map PBR attributes onto voxel positions. Verify your mesh has UVs in the [0, 1] range and that faces reference valid UV indices. Non-manifold geometry or zero-area triangles can also cause rasterization failures.
Can I convert meshes without CUDA?
No—the voxel rasterization depends on CUDA kernels compiled during setup.sh --o-voxel. CPU-only rasterization is not implemented in the current TRELLIS.2 codebase. You need an NVIDIA GPU with CUDA toolkit installed to run the conversion pipeline.
How do I choose the right resolution value?
The --resolution parameter controls the voxel grid size per axis. Use 128 for rapid prototyping, 256 for standard training data (recommended default), or 512+ for high-fidelity assets. Each doubling of resolution increases memory usage 8× and runtime approximately 4×. Match your training configuration's expected input resolution.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →