rishitdagli commited on
Commit
f09f438
·
0 Parent(s):

Made-with: Cursor

.gitattributes ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.ply filter=lfs diff=lfs merge=lfs -text
37
+ *.whl filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ venv/
2
+ weights/
README.md ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: VoMP
3
+ emoji: 🚀
4
+ colorFrom: green
5
+ colorTo: green
6
+ sdk: gradio
7
+ python_version: 3.12
8
+ sdk_version: 6.2.0
9
+ app_file: app.py
10
+ pinned: true
11
+ license: apache-2.0
12
+ short_description: Volumetric physics materials for interactive worlds
13
+ suggested_hardware: a100-large
14
+ suggested_storage: medium
15
+ ---
app.py ADDED
@@ -0,0 +1,575 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import glob
2
+ import os
3
+ import shutil
4
+ import tempfile
5
+ from typing import Dict, List, Optional, Tuple
6
+
7
+ import gradio as gr
8
+ import matplotlib
9
+
10
+ matplotlib.use("Agg")
11
+ import matplotlib.pyplot as plt
12
+ import matplotlib.colors as mcolors
13
+ from matplotlib.colorbar import ColorbarBase
14
+ import numpy as np
15
+ import spaces
16
+ import torch
17
+ from huggingface_hub import snapshot_download
18
+
19
+ from vomp.inference import Vomp
20
+ from vomp.inference.utils import LazyLoadDino, save_materials
21
+
22
+ NUM_VIEWS = 150
23
+ PROPERTY_NAMES = ["youngs_modulus", "poissons_ratio", "density"]
24
+ PROPERTY_DISPLAY_NAMES = {
25
+ "youngs_modulus": "Young's Modulus",
26
+ "poissons_ratio": "Poisson's Ratio",
27
+ "density": "Density",
28
+ }
29
+
30
+ BLENDER_LINK = (
31
+ "https://download.blender.org/release/Blender3.0/blender-3.0.1-linux-x64.tar.xz"
32
+ )
33
+ BLENDER_INSTALLATION_PATH = "/tmp"
34
+ BLENDER_PATH = f"{BLENDER_INSTALLATION_PATH}/blender-3.0.1-linux-x64/blender"
35
+
36
+ EXAMPLES_DIR = "examples"
37
+
38
+ model_id = "nvidia/PhysicalAI-Simulation-VoMP-Model"
39
+ base_path = snapshot_download(repo_id=model_id, local_dir="weights")
40
+ print(os.listdir(base_path))
41
+
42
+ def _preload_dino(model: Vomp) -> None:
43
+ print("Preloading DINO model...")
44
+ dino = LazyLoadDino(
45
+ model_name="dinov2_vitl14_reg",
46
+ device=model.device,
47
+ use_trt=getattr(model, "use_trt", False),
48
+ )
49
+ _ = dino.get_model()
50
+ _ = dino.get_transform()
51
+
52
+ def _install_blender():
53
+ if not os.path.exists(BLENDER_PATH):
54
+ print("Installing Blender...")
55
+ os.system("sudo apt-get update")
56
+ os.system(
57
+ "sudo apt-get install -y libxrender1 libxi6 libxkbcommon-x11-0 libsm6"
58
+ )
59
+ os.system(f"wget {BLENDER_LINK} -P {BLENDER_INSTALLATION_PATH}")
60
+ os.system(
61
+ f"tar -xvf {BLENDER_INSTALLATION_PATH}/blender-3.0.1-linux-x64.tar.xz -C {BLENDER_INSTALLATION_PATH}"
62
+ )
63
+ print("Blender installed successfully!")
64
+
65
+
66
+ def _is_gaussian_splat(file_path: str) -> bool:
67
+ if not file_path.lower().endswith(".ply"):
68
+ return False
69
+
70
+ try:
71
+ with open(file_path, "rb") as f:
72
+ header = b""
73
+ while True:
74
+ line = f.readline()
75
+ header += line
76
+ if b"end_header" in line:
77
+ break
78
+ if len(header) > 10000:
79
+ break
80
+
81
+ header_str = header.decode("utf-8", errors="ignore").lower()
82
+ gaussian_indicators = ["f_dc", "opacity", "scale_0", "rot_0"]
83
+ return any(indicator in header_str for indicator in gaussian_indicators)
84
+ except Exception:
85
+ return False
86
+
87
+
88
+ def _setup_examples():
89
+ """Ensure examples directory exists."""
90
+ os.makedirs(EXAMPLES_DIR, exist_ok=True)
91
+
92
+
93
+ _setup_examples()
94
+
95
+
96
+ print("Loading VoMP model...")
97
+ model = Vomp.from_checkpoint(
98
+ config_path="weights/inference.json",
99
+ geometry_checkpoint_dir="weights/geometry_transformer.pt",
100
+ matvae_checkpoint_dir="weights/matvae.safetensors",
101
+ normalization_params_path="weights/normalization_params.json",
102
+ )
103
+ print("VoMP model loaded successfully!")
104
+ _preload_dino(model)
105
+
106
+
107
+ def _get_render_images(output_dir: str) -> List[str]:
108
+ renders_dir = os.path.join(output_dir, "renders")
109
+ if not os.path.exists(renders_dir):
110
+ return []
111
+ image_paths = sorted(glob.glob(os.path.join(renders_dir, "*.png")))
112
+ return image_paths
113
+
114
+
115
+ def _create_colorbar(
116
+ data: np.ndarray, property_name: str, output_path: str, colormap: str = "viridis"
117
+ ) -> str:
118
+ fig, ax = plt.subplots(figsize=(6, 0.8))
119
+ fig.subplots_adjust(bottom=0.5)
120
+ ax.remove()
121
+
122
+ cmap = plt.cm.get_cmap(colormap)
123
+ norm = mcolors.Normalize(vmin=np.min(data), vmax=np.max(data))
124
+
125
+ cbar_ax = fig.add_axes([0.1, 0.4, 0.8, 0.35])
126
+ cb = ColorbarBase(cbar_ax, cmap=cmap, norm=norm, orientation="horizontal")
127
+ cb.ax.set_xlabel(
128
+ f"{PROPERTY_DISPLAY_NAMES.get(property_name, property_name)}", fontsize=10
129
+ )
130
+
131
+ plt.savefig(
132
+ output_path, dpi=150, bbox_inches="tight", facecolor="white", transparent=False
133
+ )
134
+ plt.close()
135
+ return output_path
136
+
137
+
138
+ def _render_point_cloud_views(
139
+ coords: np.ndarray,
140
+ values: np.ndarray,
141
+ output_dir: str,
142
+ property_name: str,
143
+ colormap: str = "viridis",
144
+ ) -> List[str]:
145
+ vmin, vmax = np.min(values), np.max(values)
146
+ if vmax - vmin > 1e-10:
147
+ normalized = (values - vmin) / (vmax - vmin)
148
+ else:
149
+ normalized = np.zeros_like(values)
150
+
151
+ cmap = plt.cm.get_cmap(colormap)
152
+ colors = cmap(normalized)
153
+
154
+ views = [
155
+ (30, 45, "view1"),
156
+ (30, 135, "view2"),
157
+ (80, 45, "view3"),
158
+ ]
159
+
160
+ image_paths = []
161
+
162
+ for elev, azim, view_name in views:
163
+ fig = plt.figure(figsize=(6, 6), facecolor="#1a1a1a")
164
+ ax = fig.add_subplot(111, projection="3d", facecolor="#1a1a1a")
165
+
166
+ ax.scatter(
167
+ coords[:, 0],
168
+ coords[:, 1],
169
+ coords[:, 2],
170
+ c=colors,
171
+ s=15,
172
+ alpha=0.9,
173
+ )
174
+
175
+ ax.view_init(elev=elev, azim=azim)
176
+ ax.set_xlim([-0.6, 0.6])
177
+ ax.set_ylim([-0.6, 0.6])
178
+ ax.set_zlim([-0.6, 0.6])
179
+ ax.set_axis_off()
180
+ ax.set_box_aspect([1, 1, 1])
181
+
182
+ output_path = os.path.join(output_dir, f"{property_name}_{view_name}.png")
183
+ plt.savefig(
184
+ output_path,
185
+ dpi=150,
186
+ bbox_inches="tight",
187
+ facecolor="#1a1a1a",
188
+ edgecolor="none",
189
+ )
190
+ plt.close()
191
+
192
+ image_paths.append(output_path)
193
+
194
+ return image_paths
195
+
196
+
197
+ def _create_material_visualizations(
198
+ material_file: str, output_dir: str
199
+ ) -> Dict[str, Tuple[List[str], str]]:
200
+ result = {}
201
+ data = np.load(material_file, allow_pickle=True)
202
+
203
+ if "voxel_data" in data:
204
+ voxel_data = data["voxel_data"]
205
+ coords = np.column_stack([voxel_data["x"], voxel_data["y"], voxel_data["z"]])
206
+ properties = {
207
+ "youngs_modulus": voxel_data["youngs_modulus"],
208
+ "poissons_ratio": voxel_data["poissons_ratio"],
209
+ "density": voxel_data["density"],
210
+ }
211
+ else:
212
+ if "voxel_coords_world" in data:
213
+ coords = data["voxel_coords_world"]
214
+ elif "query_coords_world" in data:
215
+ coords = data["query_coords_world"]
216
+ elif "coords" in data:
217
+ coords = data["coords"]
218
+ else:
219
+ print(f"Warning: No coordinate data found in {material_file}")
220
+ return result
221
+
222
+ properties = {}
223
+ property_mapping = {
224
+ "youngs_modulus": ["youngs_modulus", "young_modulus"],
225
+ "poissons_ratio": ["poissons_ratio", "poisson_ratio"],
226
+ "density": ["density"],
227
+ }
228
+ for prop_name, possible_names in property_mapping.items():
229
+ for name in possible_names:
230
+ if name in data:
231
+ properties[prop_name] = data[name]
232
+ break
233
+
234
+ center = (np.min(coords, axis=0) + np.max(coords, axis=0)) / 2
235
+ max_range = np.max(np.max(coords, axis=0) - np.min(coords, axis=0))
236
+ if max_range > 1e-10:
237
+ coords_normalized = (coords - center) / max_range
238
+ else:
239
+ coords_normalized = coords - center
240
+
241
+ for prop_name, prop_data in properties.items():
242
+ if prop_data is not None:
243
+ view_paths = _render_point_cloud_views(
244
+ coords_normalized, prop_data, output_dir, prop_name
245
+ )
246
+ colorbar_path = os.path.join(output_dir, f"{prop_name}_colorbar.png")
247
+ _create_colorbar(prop_data, prop_name, colorbar_path)
248
+ result[prop_name] = (view_paths, colorbar_path)
249
+ print(f"Created visualization for {prop_name}: {len(view_paths)} views")
250
+
251
+ return result
252
+
253
+
254
+ @spaces.GPU(duration=60)
255
+ @torch.no_grad()
256
+ def process_3d_model(input_file):
257
+ empty_result = (
258
+ None,
259
+ [],
260
+ None,
261
+ [],
262
+ None,
263
+ None,
264
+ [],
265
+ None,
266
+ None,
267
+ [],
268
+ None,
269
+ None,
270
+ )
271
+
272
+ if input_file is None:
273
+ return empty_result
274
+
275
+ output_dir = tempfile.mkdtemp(prefix="vomp_")
276
+ material_file = os.path.join(output_dir, "materials.npz")
277
+
278
+ try:
279
+ if _is_gaussian_splat(input_file):
280
+ print(f"Processing as Gaussian splat: {input_file}")
281
+ results = model.get_splat_materials(
282
+ input_file,
283
+ voxel_method="kaolin",
284
+ query_points="voxel_centers",
285
+ output_dir=output_dir,
286
+ )
287
+ else:
288
+ print(f"Processing as mesh: {input_file}")
289
+ _install_blender()
290
+ results = model.get_mesh_materials(
291
+ input_file,
292
+ blender_path=BLENDER_PATH,
293
+ query_points="voxel_centers",
294
+ output_dir=output_dir,
295
+ return_original_scale=True,
296
+ )
297
+
298
+ save_materials(results, material_file)
299
+ print(f"Materials saved to: {material_file}")
300
+
301
+ all_images = _get_render_images(output_dir)
302
+ first_image = all_images[0] if all_images else None
303
+
304
+ visualizations = _create_material_visualizations(material_file, output_dir)
305
+
306
+ youngs_views = visualizations.get("youngs_modulus", ([], None))[0]
307
+ youngs_colorbar = visualizations.get("youngs_modulus", ([], None))[1]
308
+ youngs_first = youngs_views[0] if youngs_views else None
309
+
310
+ poissons_views = visualizations.get("poissons_ratio", ([], None))[0]
311
+ poissons_colorbar = visualizations.get("poissons_ratio", ([], None))[1]
312
+ poissons_first = poissons_views[0] if poissons_views else None
313
+
314
+ density_views = visualizations.get("density", ([], None))[0]
315
+ density_colorbar = visualizations.get("density", ([], None))[1]
316
+ density_first = density_views[0] if density_views else None
317
+
318
+ return (
319
+ first_image,
320
+ all_images,
321
+ youngs_first,
322
+ youngs_views,
323
+ youngs_colorbar,
324
+ poissons_first,
325
+ poissons_views,
326
+ poissons_colorbar,
327
+ density_first,
328
+ density_views,
329
+ density_colorbar,
330
+ material_file,
331
+ )
332
+
333
+ except Exception as e:
334
+ print(f"Error processing 3D model: {e}")
335
+ raise gr.Error(f"Failed to process 3D model: {str(e)}")
336
+
337
+
338
+ def update_slider_image(slider_value: int, all_images: List[str]) -> Optional[str]:
339
+ if not all_images or slider_value < 0 or slider_value >= len(all_images):
340
+ return None
341
+ return all_images[slider_value]
342
+
343
+
344
+ def update_property_view(slider_value: int, views: List[str]) -> Optional[str]:
345
+ if not views or slider_value < 0 or slider_value >= len(views):
346
+ return None
347
+ return views[slider_value]
348
+
349
+
350
+ css = """
351
+ .gradio-container {
352
+ font-family: 'IBM Plex Sans', sans-serif;
353
+ }
354
+
355
+ .title-container {
356
+ text-align: center;
357
+ padding: 20px 0;
358
+ }
359
+
360
+ .badge-container {
361
+ display: flex;
362
+ justify-content: center;
363
+ gap: 8px;
364
+ flex-wrap: wrap;
365
+ margin-bottom: 20px;
366
+ }
367
+
368
+ .badge-container a img {
369
+ height: 22px;
370
+ }
371
+
372
+ h1 {
373
+ text-align: center;
374
+ font-size: 2.5rem;
375
+ margin-bottom: 0.5rem;
376
+ }
377
+
378
+ .subtitle {
379
+ text-align: center;
380
+ color: #666;
381
+ font-size: 1.1rem;
382
+ margin-bottom: 1.5rem;
383
+ }
384
+
385
+ .input-column, .output-column {
386
+ min-height: 400px;
387
+ }
388
+
389
+ .output-column .row {
390
+ display: flex !important;
391
+ flex-wrap: nowrap !important;
392
+ gap: 16px;
393
+ }
394
+
395
+ .output-column .row > .column {
396
+ flex: 1 1 50% !important;
397
+ min-width: 0 !important;
398
+ }
399
+ """
400
+
401
+ title_md = """
402
+ <div class="title-container">
403
+ <h1>VoMP: Predicting Volumetric Mechanical Properties</h1>
404
+ <p class="subtitle">Feed-forward, fine-grained, physically based volumetric material properties from Splats, Meshes, NeRFs, and more.</p>
405
+ <div class="badge-container">
406
+ <a href="https://arxiv.org/abs/2510.22975"><img src='https://img.shields.io/badge/arXiv-VoMP-red' alt='Paper PDF'></a>
407
+ <a href='https://research.nvidia.com/labs/sil/projects/vomp/'><img src='https://img.shields.io/badge/Project_Page-VoMP-green' alt='Project Page'></a>
408
+ <a href='https://huggingface.co/nvidia/PhysicalAI-Simulation-VoMP-Model'><img src='https://img.shields.io/badge/%F0%9F%A4%97%20-Models-yellow'></a>
409
+ <a href='https://huggingface.co/datasets/nvidia/PhysicalAI-Robotics-PhysicalAssets-VoMP'><img src='https://img.shields.io/badge/%F0%9F%A4%97%20-GVM%20Dataset-yellow'></a>
410
+ </div>
411
+ </div>
412
+ """
413
+
414
+ description_md = """
415
+ Upload a Gaussian Splat (.ply) or Mesh (.obj, .glb, .stl, .gltf) to predict volumetric mechanical properties (Young's modulus, Poisson's ratio, density) for realistic physics simulation.
416
+ """
417
+
418
+ with gr.Blocks(css=css, title="VoMP") as demo:
419
+ all_images_state = gr.State([])
420
+ youngs_views_state = gr.State([])
421
+ poissons_views_state = gr.State([])
422
+ density_views_state = gr.State([])
423
+
424
+ gr.HTML(title_md)
425
+ gr.Markdown(description_md)
426
+
427
+ with gr.Row():
428
+ # Input Column (50%)
429
+ with gr.Column(scale=1, elem_classes="input-column"):
430
+ gr.Markdown("### 📤 Input")
431
+ input_model = gr.Model3D(
432
+ label="Upload 3D Model",
433
+ clear_color=[0.1, 0.1, 0.1, 1.0],
434
+ )
435
+
436
+ submit_btn = gr.Button(
437
+ "🚀 Generate Materials", variant="primary", size="lg"
438
+ )
439
+
440
+ gr.Markdown("#### 🎬 Rendered Views")
441
+ rendered_image = gr.Image(label="Rendered View", height=250)
442
+
443
+ view_slider = gr.Slider(
444
+ minimum=0,
445
+ maximum=NUM_VIEWS - 1,
446
+ step=1,
447
+ value=0,
448
+ label="Browse All Views",
449
+ info=f"Slide to view all {NUM_VIEWS} rendered views",
450
+ )
451
+
452
+ # Output Column (50%)
453
+ with gr.Column(scale=1, elem_classes="output-column"):
454
+ gr.Markdown("### 📥 Output - Material Properties")
455
+
456
+ # Row 1: Young's Modulus and Poisson's Ratio
457
+ with gr.Row():
458
+ with gr.Column(scale=1, min_width=200):
459
+ youngs_image = gr.Image(label="Young's Modulus", height=200)
460
+ youngs_slider = gr.Slider(
461
+ minimum=0,
462
+ maximum=2,
463
+ step=1,
464
+ value=0,
465
+ label="View",
466
+ info="Switch between 3 views",
467
+ )
468
+ youngs_colorbar = gr.Image(height=50, show_label=False)
469
+
470
+ with gr.Column(scale=1, min_width=200):
471
+ poissons_image = gr.Image(label="Poisson's Ratio", height=200)
472
+ poissons_slider = gr.Slider(
473
+ minimum=0,
474
+ maximum=2,
475
+ step=1,
476
+ value=0,
477
+ label="View",
478
+ info="Switch between 3 views",
479
+ )
480
+ poissons_colorbar = gr.Image(height=50, show_label=False)
481
+
482
+ # Row 2: Density and Download
483
+ with gr.Row():
484
+ with gr.Column(scale=1, min_width=200):
485
+ density_image = gr.Image(label="Density", height=200)
486
+ density_slider = gr.Slider(
487
+ minimum=0,
488
+ maximum=2,
489
+ step=1,
490
+ value=0,
491
+ label="View",
492
+ info="Switch between 3 views",
493
+ )
494
+ density_colorbar = gr.Image(height=50, show_label=False)
495
+
496
+ with gr.Column(scale=1, min_width=200):
497
+ gr.Markdown("#### 💾 Download")
498
+ output_file = gr.File(
499
+ label="Download Materials (.npz)",
500
+ file_count="single",
501
+ )
502
+
503
+ gr.Markdown("### 🎯 Examples")
504
+ gr.Examples(
505
+ examples=[
506
+ [os.path.join(EXAMPLES_DIR, "plant.ply")],
507
+ [os.path.join(EXAMPLES_DIR, "dog.ply")],
508
+ [os.path.join(EXAMPLES_DIR, "dozer.ply")],
509
+ [os.path.join(EXAMPLES_DIR, "fiscus.ply")],
510
+ ],
511
+ inputs=[input_model],
512
+ outputs=[
513
+ rendered_image,
514
+ all_images_state,
515
+ youngs_image,
516
+ youngs_views_state,
517
+ youngs_colorbar,
518
+ poissons_image,
519
+ poissons_views_state,
520
+ poissons_colorbar,
521
+ density_image,
522
+ density_views_state,
523
+ density_colorbar,
524
+ output_file,
525
+ ],
526
+ fn=process_3d_model,
527
+ cache_examples=False,
528
+ )
529
+
530
+ # Event handlers
531
+ submit_btn.click(
532
+ fn=process_3d_model,
533
+ inputs=[input_model],
534
+ outputs=[
535
+ rendered_image,
536
+ all_images_state,
537
+ youngs_image,
538
+ youngs_views_state,
539
+ youngs_colorbar,
540
+ poissons_image,
541
+ poissons_views_state,
542
+ poissons_colorbar,
543
+ density_image,
544
+ density_views_state,
545
+ density_colorbar,
546
+ output_file,
547
+ ],
548
+ )
549
+
550
+ view_slider.change(
551
+ fn=update_slider_image,
552
+ inputs=[view_slider, all_images_state],
553
+ outputs=[rendered_image],
554
+ )
555
+
556
+ youngs_slider.change(
557
+ fn=update_property_view,
558
+ inputs=[youngs_slider, youngs_views_state],
559
+ outputs=[youngs_image],
560
+ )
561
+
562
+ poissons_slider.change(
563
+ fn=update_property_view,
564
+ inputs=[poissons_slider, poissons_views_state],
565
+ outputs=[poissons_image],
566
+ )
567
+
568
+ density_slider.change(
569
+ fn=update_property_view,
570
+ inputs=[density_slider, density_views_state],
571
+ outputs=[density_image],
572
+ )
573
+
574
+ if __name__ == "__main__":
575
+ demo.launch()
examples/dog.ply ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1808d618588f67a083bca52848070297be63d24ba3ddf1e9dae7edd75d87c69e
3
+ size 2477313
examples/dozer.ply ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b44ab835c41c4b4e2ad4b55456de1173f38e8bcef005de4d5d9d2c27f7b3749e
3
+ size 84598795
examples/fiscus.ply ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7516d90f1ec0764ce653819057b1b69197a56bc31683b4a7fd4fdff247437f7e
3
+ size 74925059
examples/plant.ply ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3a659f85e78556a90cddb2f37fcf77e9bd452fda15de6f69f6db8c5803bf9fd5
3
+ size 12734620
requirements.txt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ polyscope==2.5.0
3
+ trimesh==4.8.1
4
+ Pillow==11.0.0
5
+ safetensors==0.6.2
6
+ easydict==1.13
7
+ scipy==1.14.1
8
+ pyparsing==3.2.3
9
+ opencv-python-headless==4.10.0.84
10
+ numpy==1.26.4
11
+ matplotlib==3.7.5
12
+ torch==2.4.0
13
+ torchvision==0.19.0
14
+ xformers==0.0.27.post2
15
+ spconv-cu121
16
+ https://nvidia-kaolin.s3.us-east-2.amazonaws.com/torch-2.4.0_cu121/kaolin-0.18.0-cp312-cp312-linux_x86_64.whl
17
+ https://huggingface.co/spaces/nvidia/PhysicalAI-Robotics-VoMP-Demo/resolve/main/wheels/utils3d-0.0.2-py3-none-any.whl
18
+ https://huggingface.co/spaces/nvidia/PhysicalAI-Robotics-VoMP-Demo/resolve/main/wheels/diff_gaussian_rasterization-0.0.0-cp312-cp312-linux_x86_64.whl
19
+ git+https://github.com/nv-tlabs/vomp.git#egg=vomp
20
+ https://github.com/Dao-AILab/flash-attention/releases/download/v2.7.0.post2/flash_attn-2.7.0.post2+cu12torch2.4cxx11abiFALSE-cp312-cp312-linux_x86_64.whl
wheels/diff_gaussian_rasterization-0.0.0-cp312-cp312-linux_x86_64.whl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3b7166024db90f7878df26a50a5ec554a3a5efa421d2bc924a0fa1a99fb59b6c
3
+ size 459917
wheels/utils3d-0.0.2-py3-none-any.whl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4caaf6a3e6ddca59d824d1436f6a6139d7410d61a5d33af5c5e57e041d1d21c2
3
+ size 88958