File size: 2,065 Bytes
e937288
e5b87f1
 
e937288
 
 
4cf835c
 
f4b5e4a
4cf835c
e937288
 
 
4cf835c
 
e937288
4cf835c
e5b87f1
e937288
f4b5e4a
e5b87f1
f4b5e4a
e5b87f1
 
 
 
 
 
 
 
 
 
 
 
 
f4b5e4a
e5b87f1
 
 
 
e937288
e5b87f1
4cf835c
 
e937288
 
4cf835c
e937288
4cf835c
 
e937288
f4b5e4a
 
 
 
 
4cf835c
 
e937288
4cf835c
e937288
 
4cf835c
 
 
 
e937288
4cf835c
e937288
 
 
f4b5e4a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""
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()