Spaces:
Running
Running
File size: 7,585 Bytes
7ce9c01 620dc90 7ce9c01 620dc90 7ce9c01 bd5dee7 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 1c6444b 7ce9c01 cdc95ff 7ce9c01 1c6444b |
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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
import gradio as gr
import numpy as np
import plotly.graph_objects as go
from pyvox.models import Vox
from pyvox.writer import VoxWriter
from pyvox.custom_parser import CustomVoxParser
def load_vox_model(file_path):
"""Load and parse a .vox file"""
try:
print(f"Attempting to parse vox file: {file_path}")
model = CustomVoxParser(file_path).parse()
print(f"Model parsed successfully")
voxels = model.to_dense()
print(f"Voxel array shape: {voxels.shape}")
print(f"Number of non-zero voxels: {np.count_nonzero(voxels)}")
print(f"Palette size: {len(model.palette)}")
if np.count_nonzero(voxels) == 0:
print("Warning: No voxels found in the model")
return None, None
return voxels, model.palette
except Exception as e:
print(f"Error in load_vox_model: {str(e)}")
return None, None
def create_3d_scatter(voxels, palette):
"""Create a 3D scatter plot from voxel data"""
# Get coordinates and color indices of non-zero voxels
x, y, z = np.nonzero(voxels)
color_indices = voxels[x, y, z] - 1 # Subtract 1 since palette indices in .vox start at 1
# Apply rotations: first 90 degrees in X, then 180 degrees in Z
# Convert to radians
theta_x = np.pi / 2 # 90 degrees
theta_z = np.pi # 180 degrees
# First rotation around X axis
y_rot = y * np.cos(theta_x) - z * np.sin(theta_x)
z_rot = y * np.sin(theta_x) + z * np.cos(theta_x)
y, z = y_rot, z_rot
# Then rotation around Z axis
x_rot = x * np.cos(theta_z) - y * np.sin(theta_z)
y_rot = x * np.sin(theta_z) + y * np.cos(theta_z)
x, y = x_rot, y_rot
# Convert palette indices to RGB colors using direct palette indexing
rgb_colors = [f'rgb({int(palette[c][0])}, {int(palette[c][1])}, {int(palette[c][2])})'
if c < len(palette) else 'rgb(255, 255, 255)' for c in color_indices]
# Create 3D scatter plot with improved voxel representation
fig = go.Figure(data=[go.Scatter3d(
x=x, y=y, z=z,
mode='markers',
marker=dict(
size=6,
color=rgb_colors,
opacity=1.0,
symbol='square', # Using square symbol (supported by Plotly)
line=dict(width=0), # Remove border lines completely
sizemode='diameter',
sizeref=1.0 # Reference scale for consistent size
)
)])
# Calculate center and range for better camera positioning
center_x = (x.max() + x.min()) / 2
center_y = (y.max() + y.min()) / 2
center_z = (z.max() + z.min()) / 2
max_range = max(x.max() - x.min(), y.max() - y.min(), z.max() - z.min())
# better visualization
fig.update_layout(
scene=dict(
aspectmode='cube', # Force cubic aspect ratio
camera=dict(
up=dict(x=0, y=1, z=0),
center=dict(x=0, y=0, z=0),
eye=dict(x=1.5, y=0.9, z=0.9)
),
xaxis=dict(range=[center_x - max_range/1.5, center_x + max_range/1.5], showgrid=True, gridwidth=1, gridcolor='rgba(128, 128, 128, 0.2)'),
yaxis=dict(range=[center_y - max_range/1.5, center_y + max_range/1.5], showgrid=True, gridwidth=1, gridcolor='rgba(128, 128, 128, 0.2)'),
zaxis=dict(range=[center_z - max_range/1.5, center_z + max_range/1.5], showgrid=True, gridwidth=1, gridcolor='rgba(128, 128, 128, 0.2)')
),
margin=dict(l=0, r=0, t=0, b=0),
showlegend=False,
template='plotly_dark', # Dark theme for better contrast
paper_bgcolor='rgba(0,0,0,1)', # Pure black background
plot_bgcolor='rgba(0,0,0,1)'
)
return fig
def display_vox_model(vox_file):
"""Main function to display the voxel model"""
try:
# Load the vox model
if not vox_file:
fig = go.Figure()
fig.add_annotation(
text="Please upload a .vox file",
xref="paper", yref="paper",
x=0.5, y=0.5,
showarrow=False,
font=dict(size=16, color="white")
)
fig.update_layout(
paper_bgcolor='rgba(0,0,0,1)',
plot_bgcolor='rgba(0,0,0,1)'
)
return fig
if not vox_file.name.endswith('.vox'):
fig = go.Figure()
fig.add_annotation(
text="Please upload a valid .vox file",
xref="paper", yref="paper",
x=0.5, y=0.5,
showarrow=False,
font=dict(size=16, color="white")
)
fig.update_layout(
paper_bgcolor='rgba(0,0,0,1)',
plot_bgcolor='rgba(0,0,0,1)'
)
return fig
print(f"Loading vox file: {vox_file.name}")
voxels, palette = load_vox_model(vox_file.temp_path if hasattr(vox_file, 'temp_path') else vox_file.name)
if voxels is None or palette is None:
fig = go.Figure()
error_message = "Error: Could not load voxel data from file\n"
error_message += "This might be due to version incompatibility.\n"
error_message += "The viewer currently supports .vox files up to version 200."
fig.add_annotation(
text=error_message,
xref="paper", yref="paper",
x=0.5, y=0.5,
showarrow=False,
font=dict(size=16, color="white")
)
fig.update_layout(
paper_bgcolor='rgba(0,0,0,1)',
plot_bgcolor='rgba(0,0,0,1)'
)
return fig
if voxels.size == 0:
fig = go.Figure()
fig.add_annotation(
text="Error: No voxels found in the model",
xref="paper", yref="paper",
x=0.5, y=0.5,
showarrow=False,
font=dict(size=16, color="white")
)
fig.update_layout(
paper_bgcolor='rgba(0,0,0,1)',
plot_bgcolor='rgba(0,0,0,1)'
)
return fig
print(f"Model loaded successfully. Shape: {voxels.shape}, Palette size: {len(palette)}")
# Create the 3D visualization
fig = create_3d_scatter(voxels, palette)
return fig
except Exception as e:
print(f"Error details: {str(e)}")
# Create an empty figure with error message
fig = go.Figure()
fig.add_annotation(
text=f"Error loading model: {str(e)}",
xref="paper", yref="paper",
x=0.5, y=0.5,
showarrow=False,
font=dict(size=16, color="white")
)
fig.update_layout(
paper_bgcolor='rgba(0,0,0,1)',
plot_bgcolor='rgba(0,0,0,1)'
)
return fig
# Create Gradio interface
interface = gr.Interface(
fn=display_vox_model,
inputs=gr.File(label="Upload .vox file"),
outputs=gr.Plot(label="3D Voxel Model"), # Remove the type parameter
title="Voxel Model Viewer",
description="Upload a .vox file to view the 3D voxelized model.",
examples=[
["examples/modelo_optimizado.vox"],
["examples/Poster.vox"],
["examples/Horse.vox"]
],
cache_examples=True # Enable caching to ensure examples work properly
)
if __name__ == "__main__":
interface.launch()
|