Mesh Merge By Distance: Avoiding unnecessary copying of 'vert_dest_map'
The `vert_dest_map` array, which contains a map indicating the index of destination vertices, was being copied to another array (`WeldVert`) unnecessarily. By directly using the `vert_dest_map` array, we achieved a performance improvement. The average execution time of different operations was reduced from 267.4ms to 261.3ms, resulting in a 2.3% improvement in overall performance.
This commit is contained in:
@@ -39,12 +39,6 @@ namespace blender::geometry {
|
||||
/* indicates whether an edge or vertex in groups_map will be merged. */
|
||||
#define ELEM_MERGED int(-2)
|
||||
|
||||
struct WeldVert {
|
||||
/* Indices relative to the original Mesh. */
|
||||
int vert_dest;
|
||||
int vert_orig;
|
||||
};
|
||||
|
||||
struct WeldEdge {
|
||||
union {
|
||||
int flag;
|
||||
@@ -329,27 +323,23 @@ static void weld_assert_poly_len(const WeldPoly *wp, const Span<WeldLoop> wloop)
|
||||
*
|
||||
* \return array with the context weld vertices.
|
||||
*/
|
||||
static Vector<WeldVert> weld_vert_ctx_alloc_and_setup(MutableSpan<int> vert_dest_map,
|
||||
const int vert_kill_len)
|
||||
static Vector<int> weld_vert_ctx_alloc_and_setup(MutableSpan<int> vert_dest_map,
|
||||
const int vert_kill_len)
|
||||
{
|
||||
Vector<WeldVert> wvert;
|
||||
Vector<int> wvert;
|
||||
wvert.reserve(std::min<int>(2 * vert_kill_len, vert_dest_map.size()));
|
||||
|
||||
for (const int i : vert_dest_map.index_range()) {
|
||||
if (vert_dest_map[i] != OUT_OF_CONTEXT) {
|
||||
const int vert_dest = vert_dest_map[i];
|
||||
WeldVert wv{};
|
||||
wv.vert_dest = vert_dest;
|
||||
wv.vert_orig = i;
|
||||
wvert.append(wv);
|
||||
wvert.append(i);
|
||||
|
||||
if (vert_dest_map[vert_dest] != vert_dest) {
|
||||
/* The target vertex is also part of the context and needs to be referenced.
|
||||
* #vert_dest_map could already indicate this from the beginning, but for better
|
||||
* compatibility, it is done here as well. */
|
||||
vert_dest_map[vert_dest] = vert_dest;
|
||||
wv.vert_orig = vert_dest;
|
||||
wvert.append(wv);
|
||||
wvert.append(vert_dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,26 +353,14 @@ static Vector<WeldVert> weld_vert_ctx_alloc_and_setup(MutableSpan<int> vert_dest
|
||||
* \return r_vert_groups_buffer: Buffer containing the indices of all vertices that merge.
|
||||
* \return r_vert_groups_offs: Array that indicates where each vertex group starts in the buffer.
|
||||
*/
|
||||
static void weld_vert_groups_setup(Span<WeldVert> wvert,
|
||||
static void weld_vert_groups_setup(Span<int> wvert,
|
||||
Span<int> vert_dest_map,
|
||||
const int vert_kill_len,
|
||||
MutableSpan<int> r_vert_groups_map,
|
||||
Array<int> &r_vert_groups_buffer,
|
||||
Array<int> &r_vert_groups_offs)
|
||||
{
|
||||
/**
|
||||
* Since `r_vert_groups_map` comes from `vert_dest_map`, we don't need to reset vertices out of
|
||||
* context again.
|
||||
*
|
||||
* \code{.c}
|
||||
* for (const int i : vert_dest_map.index_range()) {
|
||||
* r_vert_groups_map[i] = OUT_OF_CONTEXT;
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
BLI_assert(r_vert_groups_map.data() == vert_dest_map.data());
|
||||
UNUSED_VARS_NDEBUG(vert_dest_map);
|
||||
|
||||
r_vert_groups_map.fill(OUT_OF_CONTEXT);
|
||||
const int vert_groups_len = wvert.size() - vert_kill_len;
|
||||
|
||||
/* Add +1 to allow calculation of the length of the last group. */
|
||||
@@ -390,19 +368,20 @@ static void weld_vert_groups_setup(Span<WeldVert> wvert,
|
||||
r_vert_groups_offs.fill(0);
|
||||
|
||||
int wgroups_len = 0;
|
||||
for (const WeldVert &wv : wvert) {
|
||||
if (wv.vert_dest == wv.vert_orig) {
|
||||
for (int vert_orig : wvert) {
|
||||
if (vert_dest_map[vert_orig] == vert_orig) {
|
||||
/* Indicate the index of the vertex group */
|
||||
r_vert_groups_map[wv.vert_orig] = wgroups_len;
|
||||
r_vert_groups_map[vert_orig] = wgroups_len;
|
||||
wgroups_len++;
|
||||
}
|
||||
else {
|
||||
r_vert_groups_map[wv.vert_orig] = ELEM_MERGED;
|
||||
r_vert_groups_map[vert_orig] = ELEM_MERGED;
|
||||
}
|
||||
}
|
||||
|
||||
for (const WeldVert &wv : wvert) {
|
||||
int group_index = r_vert_groups_map[wv.vert_dest];
|
||||
for (int vert_orig : wvert) {
|
||||
int vert_dest = vert_dest_map[vert_orig];
|
||||
int group_index = r_vert_groups_map[vert_dest];
|
||||
r_vert_groups_offs[group_index]++;
|
||||
}
|
||||
|
||||
@@ -419,9 +398,10 @@ static void weld_vert_groups_setup(Span<WeldVert> wvert,
|
||||
|
||||
/* Use a reverse for loop to ensure that indexes are assigned in ascending order. */
|
||||
for (int i = wvert.size(); i--;) {
|
||||
const WeldVert &wv = wvert[i];
|
||||
int group_index = r_vert_groups_map[wv.vert_dest];
|
||||
r_vert_groups_buffer[--r_vert_groups_offs[group_index]] = wv.vert_orig;
|
||||
int vert_orig = wvert[i];
|
||||
int vert_dest = vert_dest_map[vert_orig];
|
||||
int group_index = r_vert_groups_map[vert_dest];
|
||||
r_vert_groups_buffer[--r_vert_groups_offs[group_index]] = vert_orig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1402,7 +1382,7 @@ static void weld_mesh_context_create(const Mesh &mesh,
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
const Span<int> corner_edges = mesh.corner_edges();
|
||||
|
||||
Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len);
|
||||
Vector<int> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len);
|
||||
r_weld_mesh->vert_kill_len = vert_kill_len;
|
||||
|
||||
Array<int> edge_dest_map(edges.size());
|
||||
@@ -1577,9 +1557,7 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
|
||||
const int totvert = mesh.totvert;
|
||||
const int totedge = mesh.totedge;
|
||||
|
||||
/* Reuse the same buffer as #vert_dest_map.
|
||||
* NOTE: the caller must be made aware of it changes. */
|
||||
MutableSpan<int> vert_group_map = vert_dest_map;
|
||||
Array<int> vert_group_map(totvert);
|
||||
|
||||
WeldMesh weld_mesh;
|
||||
weld_mesh_context_create(mesh, vert_dest_map, removed_vertex_count, vert_group_map, &weld_mesh);
|
||||
@@ -1619,12 +1597,14 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
|
||||
break;
|
||||
}
|
||||
if (vert_group_map[i] != ELEM_MERGED) {
|
||||
const int *wgroup = &weld_mesh.vert_groups_offs[vert_group_map[i]];
|
||||
customdata_weld(&mesh.vdata,
|
||||
&result->vdata,
|
||||
&weld_mesh.vert_groups_buffer[*wgroup],
|
||||
*(wgroup + 1) - *wgroup,
|
||||
dest_index);
|
||||
int *src_indices;
|
||||
int count;
|
||||
{
|
||||
int *wgroup = &weld_mesh.vert_groups_offs[vert_group_map[i]];
|
||||
src_indices = &weld_mesh.vert_groups_buffer[*wgroup];
|
||||
count = *(wgroup + 1) - *wgroup;
|
||||
}
|
||||
customdata_weld(&mesh.vdata, &result->vdata, src_indices, count, dest_index);
|
||||
vert_final_map[i] = dest_index;
|
||||
dest_index++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user