This commit is contained in:
Yousef Rafat 2026-05-19 01:42:35 +03:00
parent f29fb04fa2
commit 9bf7bbb496

View File

@ -189,17 +189,14 @@ def fill_holes_fn(vertices, faces, max_perimeter=0.03):
edges = torch.cat([f[:, [0, 1]], f[:, [1, 2]], f[:, [2, 0]]], dim=0) edges = torch.cat([f[:, [0, 1]], f[:, [1, 2]], f[:, [2, 0]]], dim=0)
edges_sorted, _ = torch.sort(edges, dim=1) edges_sorted, _ = torch.sort(edges, dim=1)
max_v = v.shape[0] max_v = v.shape[0]
packed_undirected = edges_sorted[:, 0].long() * max_v + edges_sorted[:, 1].long() packed_undirected = edges_sorted[:, 0].long() * max_v + edges_sorted[:, 1].long()
unique_packed, counts = torch.unique(packed_undirected, return_counts=True) unique_packed, counts = torch.unique(packed_undirected, return_counts=True)
boundary_packed = unique_packed[counts == 1] boundary_packed = unique_packed[counts == 1]
if boundary_packed.numel() == 0: if boundary_packed.numel() == 0:
return v, f return v, f
# Build undirected boundary edge adjacency
boundary_mask = torch.isin(packed_undirected, boundary_packed) boundary_mask = torch.isin(packed_undirected, boundary_packed)
b_edges = edges_sorted[boundary_mask] b_edges = edges_sorted[boundary_mask]
@ -213,15 +210,12 @@ def fill_holes_fn(vertices, faces, max_perimeter=0.03):
# Trace all boundary loops # Trace all boundary loops
loops = [] loops = []
visited = set() visited = set()
for start_node in adj.keys(): for start_node in adj.keys():
if start_node in visited: if start_node in visited:
continue continue
curr = start_node curr = start_node
prev = -1 prev = -1
loop = [] loop = []
while curr not in visited: while curr not in visited:
visited.add(curr) visited.add(curr)
loop.append(curr) loop.append(curr)
@ -239,7 +233,7 @@ def fill_holes_fn(vertices, faces, max_perimeter=0.03):
if not loops: if not loops:
return v, f return v, f
# Compute mesh normal for orientation # Mesh normal for winding orientation only
face_normals = torch.linalg.cross( face_normals = torch.linalg.cross(
v[f[:, 1]] - v[f[:, 0]], v[f[:, 1]] - v[f[:, 0]],
v[f[:, 2]] - v[f[:, 0]], v[f[:, 2]] - v[f[:, 0]],
@ -248,25 +242,12 @@ def fill_holes_fn(vertices, faces, max_perimeter=0.03):
mesh_normal = face_normals.mean(dim=0) mesh_normal = face_normals.mean(dim=0)
mesh_normal = mesh_normal / (torch.norm(mesh_normal) + 1e-8) mesh_normal = mesh_normal / (torch.norm(mesh_normal) + 1e-8)
# Classify loops: keep only holes (normal aligns with mesh_normal), discard outer boundary # === FIX: Fill ALL boundary loops below perimeter threshold ===
hole_loops = []
for loop in loops:
loop_t = torch.tensor(loop, device=device, dtype=torch.long)
loop_v = v[loop_t]
next_v = torch.roll(loop_v, -1, dims=0)
cross = torch.linalg.cross(loop_v, next_v, dim=-1)
loop_normal = cross.sum(dim=0)
loop_normal = loop_normal / (torch.norm(loop_normal) + 1e-8)
# Hole: loop normal points same way as mesh normal (both "up" for a hole)
# Outer boundary: loop normal points opposite
if torch.dot(loop_normal, mesh_normal) > 0:
hole_loops.append(loop)
new_verts = [] new_verts = []
new_faces = [] new_faces = []
v_idx = v.shape[0] v_idx = v.shape[0]
for loop in hole_loops: for loop in loops:
loop_t = torch.tensor(loop, device=device, dtype=torch.long) loop_t = torch.tensor(loop, device=device, dtype=torch.long)
loop_v = v[loop_t] loop_v = v[loop_t]
@ -284,6 +265,8 @@ def fill_holes_fn(vertices, faces, max_perimeter=0.03):
loop_normal = loop_normal / (torch.norm(loop_normal) + 1e-8) loop_normal = loop_normal / (torch.norm(loop_normal) + 1e-8)
if torch.dot(loop_normal, mesh_normal) < 0: if torch.dot(loop_normal, mesh_normal) < 0:
loop = loop[::-1] loop = loop[::-1]
loop_t = torch.tensor(loop, device=device, dtype=torch.long)
loop_v = v[loop_t]
if len(loop) == 3: if len(loop) == 3:
new_faces.append([loop[0], loop[1], loop[2]]) new_faces.append([loop[0], loop[1], loop[2]])