Fix #109236: Split Edges node skips loose edges

With the previous fix to the node, 8a11f0f3a2, the new edge
indices are built with the changed corner vertices from a previous step
in the algorithm. That doesn't work for loose edges though, since they
aren't used by any face corners. The best solution I could come up with
was adding a second loop over the split vertices that adjusts the vertex
indices of loose edges. This can be skipped when there are none.

Pull Request: https://projects.blender.org/blender/blender/pulls/109262
This commit is contained in:
Hans Goudey
2023-06-23 17:07:05 +02:00
committed by Hans Goudey
parent 6437c0c948
commit b226c115e2

View File

@@ -180,6 +180,33 @@ static void split_vertex_per_fan(const int vertex,
}
}
/** Assign the newly created vertex duplicates to the loose edges around this vertex. */
static void reassign_loose_edge_verts(const int vertex,
const int start_offset,
const Span<int> fans,
const Span<int> fan_sizes,
const BoundedBitSpan loose_edges,
MutableSpan<int2> edges)
{
int fan_start = 0;
/* We don't need to create a new vertex for the last fan. That fan can just be connected to the
* original vertex. */
for (const int i : fan_sizes.index_range().drop_back(1)) {
const int new_vert = start_offset + i;
for (const int edge_i : fans.slice(fan_start, fan_sizes[i])) {
if (loose_edges[edge_i]) {
if (edges[edge_i][0] == vertex) {
edges[edge_i][0] = new_vert;
}
else if (edges[edge_i][1] == vertex) {
edges[edge_i][1] = new_vert;
}
}
}
fan_start += fan_sizes[i];
}
}
/**
* Get the index of the adjacent edge to a loop connected to a vertex. In other words, for the
* given polygon return the unique edge connected to the given vertex and not on the given loop.
@@ -340,12 +367,14 @@ void split_edges(Mesh &mesh,
MutableSpan<int> corner_edges = mesh.corner_edges_for_write();
/* Step 1: Split the edges. */
/* Split corner edge indices and update the edge to corner map. This step does not take into
* account future deduplication of the new edges, but is necessary in order to calculate the
* new fans around each vertex. */
mask.foreach_index([&](const int edge_i) {
split_edge_per_poly(edge_i, edge_offsets[edge_i], edge_to_loop_map, corner_edges);
});
/* Step 1.5: Update topology information (can't parallelize). */
/* Update vertex to edge map with new vertices from duplicated edges. */
for (const int edge_i : mask) {
const int2 &edge = edges[edge_i];
for (const int duplicate_i : IndexRange(edge_offsets[edge_i], num_edge_duplicates[edge_i])) {
@@ -356,7 +385,8 @@ void split_edges(Mesh &mesh,
MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
/* Step 2: Calculate vertex fans. */
/* Calculate vertex fans by reordering the vertex to edge maps. Fans are the the ordered
* groups of consecutive edges between consecutive faces looping around a vertex. */
Array<Vector<int>> vertex_fan_sizes(mesh.totvert);
threading::parallel_for(IndexRange(mesh.totvert), 512, [&](IndexRange range) {
for (const int vert : range) {
@@ -374,7 +404,7 @@ void split_edges(Mesh &mesh,
}
});
/* Step 2.5: Calculate offsets for next step. */
/* Calculate result indices per source vertex as offsets for parallelizing the next step. */
Array<int> vert_offsets(mesh.totvert);
int total_verts_num = mesh.totvert;
for (const int vert : IndexRange(mesh.totvert)) {
@@ -386,7 +416,7 @@ void split_edges(Mesh &mesh,
total_verts_num += vertex_fan_sizes[vert].size() - 1;
}
/* Step 3: Split the vertices.
/* Split the vertices into their duplicates so that each fan has its own result vertex.
* Build a map from each new vertex to an old vertex to use for transferring attributes later. */
const int new_verts_num = total_verts_num - mesh.totvert;
Array<int> new_to_old_verts_map(new_verts_num);
@@ -406,6 +436,7 @@ void split_edges(Mesh &mesh,
}
});
/* Create deduplicated new edges based on the corner vertices at each polygon. */
VectorSet<OrderedEdge> new_edges;
new_edges.reserve(new_edges_size + loose_edges.size());
for (const int i : polys.index_range()) {
@@ -418,6 +449,7 @@ void split_edges(Mesh &mesh,
}
loose_edges.foreach_index([&](const int64_t i) { new_edges.add(OrderedEdge(edges[i])); });
/* Build a map of old to new edges for transferring attributes. */
Array<int> new_to_old_edges_map(new_edges.size());
auto index_mask_to_indices = [&](const IndexMask &mask, MutableSpan<int> indices) {
for (const int i : mask.index_range()) {
@@ -435,10 +467,28 @@ void split_edges(Mesh &mesh,
}
}
/* Step 5: Resize the mesh to add the new vertices and rebuild the edges. */
/* Resize the mesh to add the new vertices and rebuild the edges. */
add_new_vertices(mesh, new_to_old_verts_map);
add_new_edges(mesh, new_edges.as_span().cast<int2>(), new_to_old_edges_map, propagation_info);
/* Connect loose edges to duplicated vertices. */
if (loose_edges_cache.count > 0) {
MutableSpan<int2> new_edges_span = mesh.edges_for_write();
threading::parallel_for(should_split_vert.index_range(), 512, [&](IndexRange range) {
for (const int vert : range) {
if (!should_split_vert[vert]) {
continue;
}
reassign_loose_edge_verts(vert,
vert_offsets[vert],
vert_to_edge_map[vert],
vertex_fan_sizes[vert],
loose_edges_cache.is_loose_bits,
new_edges_span);
}
});
}
BKE_mesh_tag_edges_split(&mesh);
}