opsiclear-admin commited on
Commit
b2c1bcb
·
verified ·
1 Parent(s): f3d01ab

Fix black texture bug: add _clean_invalid_vertices after cumesh.fill_holes()

Browse files
Files changed (1) hide show
  1. o-voxel/o_voxel/postprocess.py +32 -2
o-voxel/o_voxel/postprocess.py CHANGED
@@ -11,6 +11,31 @@ import nvdiffrast.torch as dr
11
  import cumesh
12
 
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def to_glb(
15
  vertices: torch.Tensor,
16
  faces: torch.Tensor,
@@ -111,6 +136,7 @@ def to_glb(
111
  if verbose:
112
  print(f"After filling holes: {mesh.num_vertices} vertices, {mesh.num_faces} faces")
113
  vertices, faces = mesh.read()
 
114
  if use_tqdm:
115
  pbar.update(1)
116
 
@@ -142,19 +168,23 @@ def to_glb(
142
  mesh.repair_non_manifold_edges()
143
  mesh.remove_small_connected_components(1e-5)
144
  mesh.fill_holes(max_hole_perimeter=3e-2)
 
 
145
  if verbose:
146
  print(f"After initial cleanup: {mesh.num_vertices} vertices, {mesh.num_faces} faces")
147
-
148
  # Step 3: Final simplification to target count
149
  mesh.simplify(decimation_target, verbose=verbose)
150
  if verbose:
151
  print(f"After final simplification: {mesh.num_vertices} vertices, {mesh.num_faces} faces")
152
-
153
  # Step 4: Final Cleanup loop
154
  mesh.remove_duplicate_faces()
155
  mesh.repair_non_manifold_edges()
156
  mesh.remove_small_connected_components(1e-5)
157
  mesh.fill_holes(max_hole_perimeter=3e-2)
 
 
158
  if verbose:
159
  print(f"After final cleanup: {mesh.num_vertices} vertices, {mesh.num_faces} faces")
160
 
 
11
  import cumesh
12
 
13
 
14
+ def _clean_invalid_vertices(mesh, vertices, faces, aabb, verbose=False):
15
+ """
16
+ Workaround for cumesh.fill_holes() bug that creates vertices with garbage positions.
17
+ Removes vertices and faces that are outside the valid AABB bounds.
18
+ """
19
+ valid_mask = (vertices.min(dim=1)[0] >= aabb[0].min() - 1.0) & (vertices.max(dim=1)[0] <= aabb[1].max() + 1.0)
20
+ if not valid_mask.all():
21
+ invalid_count = (~valid_mask).sum().item()
22
+ if verbose:
23
+ print(f" [CLEANUP] Removing {invalid_count} vertices with invalid positions")
24
+ # Remove faces that reference invalid vertices
25
+ invalid_verts = torch.where(~valid_mask)[0]
26
+ valid_faces_mask = ~torch.isin(faces, invalid_verts).any(dim=1)
27
+ faces = faces[valid_faces_mask]
28
+ # Compact vertices - renumber faces to match new vertex indices
29
+ valid_indices = torch.where(valid_mask)[0]
30
+ remap = torch.zeros(vertices.shape[0], dtype=torch.int32, device=vertices.device)
31
+ remap[valid_indices] = torch.arange(valid_indices.shape[0], dtype=torch.int32, device=vertices.device)
32
+ vertices = vertices[valid_mask]
33
+ faces = remap[faces.long()].int()
34
+ # Reinitialize mesh with cleaned data
35
+ mesh.init(vertices, faces)
36
+ return vertices, faces
37
+
38
+
39
  def to_glb(
40
  vertices: torch.Tensor,
41
  faces: torch.Tensor,
 
136
  if verbose:
137
  print(f"After filling holes: {mesh.num_vertices} vertices, {mesh.num_faces} faces")
138
  vertices, faces = mesh.read()
139
+ vertices, faces = _clean_invalid_vertices(mesh, vertices, faces, aabb, verbose)
140
  if use_tqdm:
141
  pbar.update(1)
142
 
 
168
  mesh.repair_non_manifold_edges()
169
  mesh.remove_small_connected_components(1e-5)
170
  mesh.fill_holes(max_hole_perimeter=3e-2)
171
+ vertices_tmp, faces_tmp = mesh.read()
172
+ vertices_tmp, faces_tmp = _clean_invalid_vertices(mesh, vertices_tmp, faces_tmp, aabb, verbose)
173
  if verbose:
174
  print(f"After initial cleanup: {mesh.num_vertices} vertices, {mesh.num_faces} faces")
175
+
176
  # Step 3: Final simplification to target count
177
  mesh.simplify(decimation_target, verbose=verbose)
178
  if verbose:
179
  print(f"After final simplification: {mesh.num_vertices} vertices, {mesh.num_faces} faces")
180
+
181
  # Step 4: Final Cleanup loop
182
  mesh.remove_duplicate_faces()
183
  mesh.repair_non_manifold_edges()
184
  mesh.remove_small_connected_components(1e-5)
185
  mesh.fill_holes(max_hole_perimeter=3e-2)
186
+ vertices_tmp, faces_tmp = mesh.read()
187
+ vertices_tmp, faces_tmp = _clean_invalid_vertices(mesh, vertices_tmp, faces_tmp, aabb, verbose)
188
  if verbose:
189
  print(f"After final cleanup: {mesh.num_vertices} vertices, {mesh.num_faces} faces")
190