Geometry Nodes: Extrude: Skip topology map with no edge attributes

In vertex extrusion mode, when there are no edge attributes we can avoid
creating a topology map meant for mixing old values. This makes
simulation caching for a curl noise demo file from user Higgsas 10%
faster (from 44s to 40s to calculate 230 frames).
This commit is contained in:
Hans Goudey
2023-05-10 14:49:08 -04:00
parent 3958f4cb02
commit 5b5e6a846a

View File

@@ -115,10 +115,8 @@ static void expand_mesh(Mesh &mesh,
const int vert_expand,
const int edge_expand,
const int poly_expand,
const int loop_expand,
const AnonymousAttributePropagationInfo &propagation_info)
const int loop_expand)
{
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
/* Remove types that aren't supported for interpolation in this node. */
if (vert_expand != 0) {
CustomData_free_layers(&mesh.vdata, CD_ORCO, mesh.totvert);
@@ -202,7 +200,9 @@ static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domai
* result point.
*/
template<typename T, typename GetMixIndicesFn>
void copy_with_mixing(MutableSpan<T> dst, Span<T> src, GetMixIndicesFn get_mix_indices_fn)
void copy_with_mixing(const Span<T> src,
const GetMixIndicesFn &get_mix_indices_fn,
MutableSpan<T> dst)
{
threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) {
bke::attribute_math::DefaultPropagationMixer<T> mixer{dst.slice(range)};
@@ -215,6 +215,15 @@ void copy_with_mixing(MutableSpan<T> dst, Span<T> src, GetMixIndicesFn get_mix_i
});
}
template<typename GetMixIndicesFn>
void copy_with_mixing(const GSpan src, const GetMixIndicesFn &get_mix_indices_fn, GMutableSpan dst)
{
bke::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
copy_with_mixing(src.typed<T>(), get_mix_indices_fn, dst.typed<T>());
});
}
static Array<Vector<int>> create_vert_to_edge_map(const int vert_size,
const Span<int2> edges,
const int vert_offset = 0)
@@ -246,61 +255,67 @@ static void extrude_mesh_vertices(Mesh &mesh,
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
/* This allows parallelizing attribute mixing for new edges. */
Array<Vector<int>> vert_to_edge_map = create_vert_to_edge_map(orig_vert_size, mesh.edges());
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
expand_mesh(mesh, selection.size(), selection.size(), 0, 0, propagation_info);
Set<AttributeIDRef> point_ids;
Set<AttributeIDRef> edge_ids;
mesh.attributes().for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (meta_data.data_type == CD_PROP_STRING) {
return true;
}
if (meta_data.domain == ATTR_DOMAIN_POINT) {
if (id.name() != "position") {
point_ids.add(id);
}
}
else if (meta_data.domain == ATTR_DOMAIN_EDGE) {
if (id.name() != ".edge_verts") {
edge_ids.add(id);
}
}
return true;
});
/* This allows parallelizing attribute mixing for new edges. */
Array<Vector<int>> vert_to_edge_map;
if (!edge_ids.is_empty()) {
vert_to_edge_map = create_vert_to_edge_map(orig_vert_size, mesh.edges());
}
expand_mesh(mesh, selection.size(), selection.size(), 0, 0);
const IndexRange new_vert_range{orig_vert_size, selection.size()};
const IndexRange new_edge_range{orig_edge_size, selection.size()};
MutableSpan<float3> new_positions = mesh.vert_positions_for_write().slice(new_vert_range);
MutableSpan<int2> new_edges = mesh.edges_for_write().slice(new_edge_range);
for (const int i_selection : selection.index_range()) {
new_edges[i_selection] = int2(selection[i_selection], new_vert_range[i_selection]);
}
MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) {
return true;
}
if (ELEM(id.name(), ".corner_vert", ".corner_edge", ".edge_verts")) {
return true;
}
if (meta_data.data_type == CD_PROP_STRING) {
return true;
}
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
switch (attribute.domain) {
case ATTR_DOMAIN_POINT:
/* New vertices copy the attribute values from their source vertex. */
array_utils::gather(attribute.span, selection, attribute.span.slice(new_vert_range));
break;
case ATTR_DOMAIN_EDGE:
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
MutableSpan<T> data = attribute.span.typed<T>();
/* New edge values are mixed from of all the edges connected to the source vertex. */
copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) {
return vert_to_edge_map[selection[i]].as_span();
});
});
break;
default:
BLI_assert_unreachable();
}
/* New vertices copy the attribute values from their source vertex. */
for (const AttributeIDRef &id : point_ids) {
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
array_utils::gather(attribute.span, selection, attribute.span.slice(new_vert_range));
attribute.finish();
return true;
});
}
/* New edge values are mixed from of all the edges connected to the source vertex. */
for (const AttributeIDRef &id : edge_ids) {
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
copy_with_mixing(
attribute.span,
[&](const int i) { return vert_to_edge_map[selection[i]].as_span(); },
attribute.span.slice(new_edge_range));
attribute.finish();
}
MutableSpan<float3> positions = mesh.vert_positions_for_write();
MutableSpan<float3> new_positions = positions.slice(new_vert_range);
threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
new_positions[i] += offsets[selection[i]];
new_positions[i] = positions[selection[i]] + offsets[selection[i]];
}
});
@@ -436,12 +451,12 @@ static void extrude_mesh_edges(Mesh &mesh,
/* Every new polygon is a quad with four corners. */
const IndexRange new_loop_range{orig_loop_size, new_poly_range.size() * 4};
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
expand_mesh(mesh,
new_vert_range.size(),
connect_edge_range.size() + duplicate_edge_range.size(),
new_poly_range.size(),
new_loop_range.size(),
propagation_info);
new_loop_range.size());
MutableSpan<int2> edges = mesh.edges_for_write();
MutableSpan<int2> connect_edges = edges.slice(connect_edge_range);
@@ -537,18 +552,19 @@ static void extrude_mesh_edges(Mesh &mesh,
array_utils::gather(data.as_span(), edge_selection, duplicate_data);
/* Edges connected to original vertices mix values of selected connected edges. */
MutableSpan<T> connect_data = data.slice(connect_edge_range);
copy_with_mixing(connect_data, duplicate_data.as_span(), [&](const int i_new_vert) {
return new_vert_to_duplicate_edge_map[i_new_vert].as_span();
});
copy_with_mixing(
duplicate_data.as_span(),
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
data.slice(connect_edge_range));
break;
}
case ATTR_DOMAIN_FACE: {
/* Attribute values for new faces are a mix of the values of faces connected to the its
* original edge. */
copy_with_mixing(data.slice(new_poly_range), data.as_span(), [&](const int i) {
return edge_to_poly_map[edge_selection[i]].as_span();
});
copy_with_mixing(
data.as_span(),
[&](const int i) { return edge_to_poly_map[edge_selection[i]].as_span(); },
data.slice(new_poly_range));
break;
}
@@ -800,12 +816,12 @@ static void extrude_mesh_face_regions(Mesh &mesh,
/* The loops that form the new side faces. */
const IndexRange side_loop_range{orig_corner_verts.size(), side_poly_range.size() * 4};
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
expand_mesh(mesh,
new_vert_range.size(),
connect_edge_range.size() + boundary_edge_range.size() + new_inner_edge_range.size(),
side_poly_range.size(),
side_loop_range.size(),
propagation_info);
side_loop_range.size());
MutableSpan<int2> edges = mesh.edges_for_write();
MutableSpan<int2> connect_edges = edges.slice(connect_edge_range);
@@ -941,10 +957,10 @@ static void extrude_mesh_face_regions(Mesh &mesh,
array_utils::gather(data.as_span(), new_inner_edge_indices.as_span(), new_inner_data);
/* Edges connected to original vertices mix values of selected connected edges. */
MutableSpan<T> connect_data = data.slice(connect_edge_range);
copy_with_mixing(connect_data, boundary_data.as_span(), [&](const int i) {
return new_vert_to_duplicate_edge_map[i].as_span();
});
copy_with_mixing(
boundary_data.as_span(),
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
data.slice(connect_edge_range));
break;
}
case ATTR_DOMAIN_FACE: {
@@ -1132,12 +1148,12 @@ static void extrude_individual_mesh_faces(
const IndexRange side_poly_range{orig_polys.size(), duplicate_edge_range.size()};
const IndexRange side_loop_range{orig_loop_size, side_poly_range.size() * 4};
remove_non_propagated_attributes(mesh.attributes_for_write(), propagation_info);
expand_mesh(mesh,
new_vert_range.size(),
connect_edge_range.size() + duplicate_edge_range.size(),
side_poly_range.size(),
side_loop_range.size(),
propagation_info);
side_loop_range.size());
MutableSpan<float3> new_positions = mesh.vert_positions_for_write().slice(new_vert_range);
MutableSpan<int2> edges = mesh.edges_for_write();