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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user