Geometry Nodes: Fill new quad poly offsets in parallel
Add an offset indices utility to do fill constant size new offsets in parallel, which was already done in the duplicate elements node. For example, filling poly offsets for a new part of a mesh that is only quads. In the extrude node this was single-threaded before, so the new poly offsets is about 10x faster, saving about 10 out of 157 ms when extruding 2 million faces.
This commit is contained in:
parent
4c6653274c
commit
2b4666b17b
|
@ -125,8 +125,7 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
|
|||
MutableSpan<int> poly_offsets = mesh->poly_offsets_for_write();
|
||||
MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
|
||||
|
||||
poly_offsets.fill(4);
|
||||
blender::offset_indices::accumulate_counts_to_offsets(poly_offsets);
|
||||
blender::offset_indices::fill_constant_group_size(4, 0, poly_offsets);
|
||||
|
||||
mesh->vert_positions_for_write().copy_from(
|
||||
Span(reinterpret_cast<float3 *>(qrd.out_verts), qrd.out_totverts));
|
||||
|
@ -230,10 +229,11 @@ static Mesh *remesh_voxel_volume_to_mesh(const openvdb::FloatGrid::Ptr level_set
|
|||
MutableSpan<int> poly_offsets = mesh->poly_offsets_for_write();
|
||||
MutableSpan<int> mesh_corner_verts = mesh->corner_verts_for_write();
|
||||
|
||||
const int triangle_loop_start = quads.size() * 4;
|
||||
if (!poly_offsets.is_empty()) {
|
||||
poly_offsets.take_front(quads.size()).fill(4);
|
||||
poly_offsets.drop_front(quads.size()).fill(3);
|
||||
blender::offset_indices::accumulate_counts_to_offsets(poly_offsets);
|
||||
blender::offset_indices::fill_constant_group_size(4, 0, poly_offsets.take_front(quads.size()));
|
||||
blender::offset_indices::fill_constant_group_size(
|
||||
3, triangle_loop_start, poly_offsets.drop_front(quads.size()));
|
||||
}
|
||||
|
||||
for (const int i : vert_positions.index_range()) {
|
||||
|
@ -248,7 +248,6 @@ static Mesh *remesh_voxel_volume_to_mesh(const openvdb::FloatGrid::Ptr level_set
|
|||
mesh_corner_verts[loopstart + 3] = quads[i][1];
|
||||
}
|
||||
|
||||
const int triangle_loop_start = quads.size() * 4;
|
||||
for (const int i : IndexRange(tris.size())) {
|
||||
const int loopstart = triangle_loop_start + i * 3;
|
||||
mesh_corner_verts[loopstart] = tris[i][2];
|
||||
|
|
|
@ -140,6 +140,9 @@ template<typename T> struct GroupedSpan {
|
|||
OffsetIndices<int> accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets,
|
||||
int start_offset = 0);
|
||||
|
||||
/** Create offsets where every group has the same size. */
|
||||
void fill_constant_group_size(int size, int start_offset, MutableSpan<int> offsets);
|
||||
|
||||
/** Copy the number of indices in every group in the mask to the corresponding index. */
|
||||
void copy_group_sizes(OffsetIndices<int> offsets, const IndexMask &mask, MutableSpan<int> sizes);
|
||||
|
||||
|
|
|
@ -22,6 +22,15 @@ OffsetIndices<int> accumulate_counts_to_offsets(MutableSpan<int> counts_to_offse
|
|||
return OffsetIndices<int>(counts_to_offsets);
|
||||
}
|
||||
|
||||
void fill_constant_group_size(const int size, const int start_offset, MutableSpan<int> offsets)
|
||||
{
|
||||
threading::parallel_for(offsets.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int64_t i : range) {
|
||||
offsets[i] = size * i + start_offset;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void copy_group_sizes(const OffsetIndices<int> offsets,
|
||||
const IndexMask &mask,
|
||||
MutableSpan<int> sizes)
|
||||
|
|
|
@ -68,14 +68,8 @@ static OffsetIndices<int> accumulate_counts_to_offsets(const IndexMask &selectio
|
|||
Array<int> &r_offset_data)
|
||||
{
|
||||
r_offset_data.reinitialize(selection.size() + 1);
|
||||
if (counts.is_single()) {
|
||||
const int count = counts.get_internal_single();
|
||||
threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int64_t i : range) {
|
||||
r_offset_data[i] = count * i;
|
||||
}
|
||||
});
|
||||
r_offset_data.last() = count * selection.size();
|
||||
if (const std::optional<int> count = counts.get_if_single()) {
|
||||
offset_indices::fill_constant_group_size(*count, 0, r_offset_data);
|
||||
}
|
||||
else {
|
||||
array_utils::gather(counts, selection, r_offset_data.as_mutable_span().drop_back(1), 1024);
|
||||
|
|
|
@ -487,8 +487,7 @@ static void extrude_mesh_edges(Mesh &mesh,
|
|||
MutableSpan<int> corner_edges = mesh.corner_edges_for_write();
|
||||
MutableSpan<int> new_corner_edges = corner_edges.slice(new_loop_range);
|
||||
|
||||
new_poly_offsets.fill(4);
|
||||
offset_indices::accumulate_counts_to_offsets(new_poly_offsets, orig_loop_size);
|
||||
offset_indices::fill_constant_group_size(4, orig_loop_size, new_poly_offsets);
|
||||
const OffsetIndices polys = mesh.polys();
|
||||
|
||||
for (const int i : connect_edges.index_range()) {
|
||||
|
@ -848,8 +847,7 @@ static void extrude_mesh_face_regions(Mesh &mesh,
|
|||
|
||||
/* Initialize the new side polygons. */
|
||||
if (!new_poly_offsets.is_empty()) {
|
||||
new_poly_offsets.fill(4);
|
||||
offset_indices::accumulate_counts_to_offsets(new_poly_offsets, orig_loop_size);
|
||||
offset_indices::fill_constant_group_size(4, orig_loop_size, new_poly_offsets);
|
||||
}
|
||||
const OffsetIndices polys = mesh.polys();
|
||||
|
||||
|
@ -1169,8 +1167,7 @@ static void extrude_individual_mesh_faces(
|
|||
MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
|
||||
MutableSpan<int> corner_edges = mesh.corner_edges_for_write();
|
||||
|
||||
new_poly_offsets.fill(4);
|
||||
offset_indices::accumulate_counts_to_offsets(new_poly_offsets, orig_loop_size);
|
||||
offset_indices::fill_constant_group_size(4, orig_loop_size, new_poly_offsets);
|
||||
const OffsetIndices polys = mesh.polys();
|
||||
|
||||
/* For every selected polygon, change it to use the new extruded vertices and the duplicate
|
||||
|
|
Loading…
Reference in New Issue