Spaces:
Running on Zero
Running on Zero
Add isolated pre-simplification geometry replay
Browse files- scripts/replay_geometry_export.py +40 -0
- studio/native.py +6 -0
- studio/worker.py +10 -0
scripts/replay_geometry_export.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Diagnostic replay of saved tensors; capture or substitute pre-simplification remesh."""
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
import json
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def replay(raw_path, layout_path, output, filtered_path=None):
|
| 8 |
+
import torch
|
| 9 |
+
import cumesh
|
| 10 |
+
import o_voxel
|
| 11 |
+
output = Path(output)
|
| 12 |
+
output.mkdir(parents=True, exist_ok=True)
|
| 13 |
+
with np.load(raw_path, allow_pickle=False) as data:
|
| 14 |
+
arrays = {key: data[key].copy() for key in data.files}
|
| 15 |
+
layout = {key: slice(*value) for key, value in json.loads(Path(layout_path).read_text()).items()}
|
| 16 |
+
original = cumesh.remeshing.remesh_narrow_band_dc
|
| 17 |
+
class Captured(Exception):
|
| 18 |
+
pass
|
| 19 |
+
def interception(*args, **kwargs):
|
| 20 |
+
if filtered_path:
|
| 21 |
+
with np.load(filtered_path, allow_pickle=False) as data:
|
| 22 |
+
return (torch.from_numpy(data['vertices'].astype(np.float32)).cuda(),
|
| 23 |
+
torch.from_numpy(data['faces'].astype(np.int32)).cuda())
|
| 24 |
+
vertices, faces = original(*args, **kwargs)
|
| 25 |
+
np.savez_compressed(output / 'pre-simplify.npz', vertices=vertices.cpu().numpy(), faces=faces.cpu().numpy())
|
| 26 |
+
raise Captured()
|
| 27 |
+
cumesh.remeshing.remesh_narrow_band_dc = interception
|
| 28 |
+
try:
|
| 29 |
+
result = o_voxel.postprocess.to_glb(
|
| 30 |
+
vertices=torch.from_numpy(arrays['vertices']).cuda(), faces=torch.from_numpy(arrays['faces']).cuda(),
|
| 31 |
+
attr_volume=torch.from_numpy(arrays['attrs']).cuda(), coords=torch.from_numpy(arrays['coords']).cuda(),
|
| 32 |
+
attr_layout=layout, grid_size=int(arrays['grid_size']) if arrays['grid_size'].ndim == 0
|
| 33 |
+
else arrays['grid_size'].tolist(), aabb=[[-.5, -.5, -.5], [.5, .5, .5]],
|
| 34 |
+
decimation_target=50000, texture_size=1024, remesh=True, remesh_band=1, remesh_project=0)
|
| 35 |
+
result.export(output / 'filtered-remesh.glb')
|
| 36 |
+
except Captured:
|
| 37 |
+
return str(output / 'pre-simplify.npz')
|
| 38 |
+
finally:
|
| 39 |
+
cumesh.remeshing.remesh_narrow_band_dc = original
|
| 40 |
+
return str(output / 'filtered-remesh.glb')
|
studio/native.py
CHANGED
|
@@ -132,3 +132,9 @@ def compare_geometry_gpu(image, seed, output):
|
|
| 132 |
capture(meshes[0], latents[2], pipeline.pbr_attr_layout, output)
|
| 133 |
compare(output)
|
| 134 |
return output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
capture(meshes[0], latents[2], pipeline.pbr_attr_layout, output)
|
| 133 |
compare(output)
|
| 134 |
return output
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
@spaces.GPU(duration=240)
|
| 138 |
+
def replay_geometry_gpu(raw, layout, output, filtered=None):
|
| 139 |
+
from scripts.replay_geometry_export import replay
|
| 140 |
+
return replay(raw, layout, output, filtered)
|
studio/worker.py
CHANGED
|
@@ -88,6 +88,10 @@ class WorkerEndpoints:
|
|
| 88 |
self.models.geometry(image, int(seed), output)
|
| 89 |
return str(output)
|
| 90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
def compare_geometry(self, image, seed):
|
| 92 |
from .native import compare_geometry_gpu
|
| 93 |
with Image.open(image) as source:
|
|
@@ -162,6 +166,12 @@ def build_worker(role, models, output_root="outputs/worker"):
|
|
| 162 |
gr.Button("Generate").click(getattr(endpoints, role), inputs, outputs, api_name=role,
|
| 163 |
concurrency_limit=1)
|
| 164 |
if role == "geometry":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
diagnostic = gr.File(label="Same-input export comparison")
|
| 166 |
gr.Button("Compare export modes").click(endpoints.compare_geometry, inputs, diagnostic,
|
| 167 |
api_name="compare_geometry", concurrency_limit=1, concurrency_id="geometry")
|
|
|
|
| 88 |
self.models.geometry(image, int(seed), output)
|
| 89 |
return str(output)
|
| 90 |
|
| 91 |
+
def replay_geometry(self, raw, layout, filtered):
|
| 92 |
+
from .native import replay_geometry_gpu
|
| 93 |
+
return replay_geometry_gpu(raw, layout, str(self.directory()), filtered)
|
| 94 |
+
|
| 95 |
def compare_geometry(self, image, seed):
|
| 96 |
from .native import compare_geometry_gpu
|
| 97 |
with Image.open(image) as source:
|
|
|
|
| 166 |
gr.Button("Generate").click(getattr(endpoints, role), inputs, outputs, api_name=role,
|
| 167 |
concurrency_limit=1)
|
| 168 |
if role == "geometry":
|
| 169 |
+
raw = gr.File(label="Raw tensor NPZ", type="filepath")
|
| 170 |
+
layout = gr.File(label="Attribute layout JSON", type="filepath")
|
| 171 |
+
filtered = gr.File(label="Filtered remesh NPZ (optional)", type="filepath")
|
| 172 |
+
replay_output = gr.File(label="Replay output")
|
| 173 |
+
gr.Button("Replay saved tensors").click(endpoints.replay_geometry, [raw, layout, filtered], replay_output,
|
| 174 |
+
api_name="replay_geometry", concurrency_limit=1, concurrency_id="geometry")
|
| 175 |
diagnostic = gr.File(label="Same-input export comparison")
|
| 176 |
gr.Button("Compare export modes").click(endpoints.compare_geometry, inputs, diagnostic,
|
| 177 |
api_name="compare_geometry", concurrency_limit=1, concurrency_id="geometry")
|