Spaces:
Sleeping
Sleeping
| """ | |
| Gradio app: robust .vox → .glb conversion + built-in Model3D viewer. | |
| Handles small and large voxel files, centers and colors mesh to avoid 'paper icon'. | |
| """ | |
| import gradio as gr | |
| import tempfile | |
| import trimesh | |
| import numpy as np | |
| from pathlib import Path | |
| from pyvox.parser import VoxParser | |
| def vox_to_glb(file_path): | |
| vox = VoxParser(file_path).parse() | |
| model = vox.models[0] | |
| voxels = model.voxels | |
| size_x, size_y, size_z = model.size.x, model.size.y, model.size.z | |
| if not voxels: | |
| raise ValueError("No voxels found") | |
| # Small grid: cube per voxel, Large grid: marching cubes | |
| if max(size_x, size_y, size_z) <= 16: | |
| cubes = [] | |
| for v in voxels: | |
| cube = trimesh.creation.box(extents=(1,1,1)) | |
| cube.apply_translation([v.x, v.y, v.z]) | |
| cubes.append(cube) | |
| mesh = trimesh.util.concatenate(cubes) | |
| else: | |
| grid = np.zeros((size_x, size_y, size_z), dtype=bool) | |
| for v in voxels: | |
| grid[v.x, v.y, v.z] = True | |
| mesh = trimesh.voxel.ops.matrix_to_marching_cubes(grid) | |
| # Center mesh, scale, add color | |
| mesh.apply_translation(-mesh.centroid) | |
| mesh.apply_scale(1.0) | |
| mesh.visual.vertex_colors = [200, 100, 50, 255] | |
| tmp = tempfile.NamedTemporaryFile(suffix=".glb", delete=False) | |
| mesh.export(tmp.name) | |
| return tmp.name | |
| def handle_upload(file): | |
| if file is None: | |
| return None | |
| ext = Path(file.name).suffix.lower() | |
| if ext == '.vox': | |
| try: | |
| return vox_to_glb(file.name) | |
| except Exception as e: | |
| print(f"Failed to convert vox: {e}") | |
| return None | |
| elif ext in ['.glb', '.gltf']: | |
| return file.name | |
| else: | |
| return None | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# VOX / GLB Viewer\nUpload a `.vox` or `.glb/.gltf` file to preview.") | |
| upload = gr.File(file_types=['.vox','.glb','.gltf'], label="Upload File") | |
| viewer = gr.Model3D(label="Preview") | |
| upload.change(handle_upload, upload, viewer) | |
| if __name__ == '__main__': | |
| demo.launch() |