[Bf-blender-cvs] [5758d114c1a] master: Dual Mesh: Avoid transferring position attribute twice

Hans Goudey noreply at git.blender.org
Mon Nov 28 15:57:14 CET 2022


Commit: 5758d114c1a6126bea6e64ccb74b5ea7c33999c1
Author: Hans Goudey
Date:   Sun Nov 27 23:23:19 2022 -0600
Branches: master
https://developer.blender.org/rB5758d114c1a6126bea6e64ccb74b5ea7c33999c1

Dual Mesh: Avoid transferring position attribute twice

The node transferred position once as a generic attribute, and then set
the values again manually. This wastes processing during the attribute
transfer step. On a 1 million face grid, I observed roughly an 8%
improvement, from 231.5 to 217.1 ms average and 225.4 to 209.6 ms min.

===================================================================

M	source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc

===================================================================

diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
index ed6b1bad7cf..eb8f0b8e0ba 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -127,7 +127,6 @@ static void copy_data_based_on_pairs(Span<T> data,
  * closest face.
  */
 static void transfer_attributes(
-    const Map<AttributeIDRef, AttributeKind> &attributes,
     const Span<VertexType> vertex_types,
     const bool keep_boundaries,
     const Span<int> new_to_old_edges_map,
@@ -136,12 +135,14 @@ static void transfer_attributes(
     const AttributeAccessor src_attributes,
     MutableAttributeAccessor dst_attributes)
 {
-  for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
-    const AttributeIDRef attribute_id = entry.key;
-    GAttributeReader src_attribute = src_attributes.lookup(attribute_id);
-    if (!src_attribute) {
-      continue;
-    }
+  /* Retrieve all attributes except for position which is handled manually.
+   * Remove anonymous attributes that don't need to be propagated.*/
+  Set<AttributeIDRef> attribute_ids = src_attributes.all_ids();
+  attribute_ids.remove("position");
+  attribute_ids.remove_if([](const AttributeIDRef &id) { return !id.should_be_kept(); });
+
+  for (const AttributeIDRef &id : attribute_ids) {
+    GAttributeReader src_attribute = src_attributes.lookup(id);
 
     eAttrDomain out_domain;
     if (src_attribute.domain == ATTR_DOMAIN_FACE) {
@@ -157,7 +158,7 @@ static void transfer_attributes(
     const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
         src_attribute.varray.type());
     GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
-        attribute_id, out_domain, data_type);
+        id, out_domain, data_type);
     if (!dst_attribute) {
       continue;
     }
@@ -605,30 +606,23 @@ static void dissolve_redundant_verts(const Span<MEdge> edges,
  *
  * Some special cases are needed for boundaries and non-manifold geometry.
  */
-static void calc_dual_mesh(GeometrySet &geometry_set,
-                           const MeshComponent &in_component,
-                           const bool keep_boundaries)
+static Mesh *calc_dual_mesh(const Mesh &src_mesh, const bool keep_boundaries)
 {
-  const Mesh &mesh_in = *in_component.get_for_read();
-  const Span<MVert> src_verts = mesh_in.verts();
-  const Span<MEdge> src_edges = mesh_in.edges();
-  const Span<MPoly> src_polys = mesh_in.polys();
-  const Span<MLoop> src_loops = mesh_in.loops();
-
-  Map<AttributeIDRef, AttributeKind> attributes;
-  geometry_set.gather_attributes_for_propagation(
-      {GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_MESH, false, attributes);
-
-  Array<VertexType> vertex_types(mesh_in.totvert);
-  Array<EdgeType> edge_types(mesh_in.totedge);
-  calc_boundaries(mesh_in, vertex_types, edge_types);
+  const Span<MVert> src_verts = src_mesh.verts();
+  const Span<MEdge> src_edges = src_mesh.edges();
+  const Span<MPoly> src_polys = src_mesh.polys();
+  const Span<MLoop> src_loops = src_mesh.loops();
+
+  Array<VertexType> vertex_types(src_mesh.totvert);
+  Array<EdgeType> edge_types(src_mesh.totedge);
+  calc_boundaries(src_mesh, vertex_types, edge_types);
   /* Stores the indices of the polygons connected to the vertex. Because the polygons are looped
    * over in order of their indices, the polygon's indices will be sorted in ascending order.
    * (This can change once they are sorted using `sort_vertex_polys`). */
   Array<Vector<int>> vert_to_poly_map = bke::mesh_topology::build_vert_to_poly_map(
       src_polys, src_loops, src_verts.size());
-  Array<Array<int>> vertex_shared_edges(mesh_in.totvert);
-  Array<Array<int>> vertex_corners(mesh_in.totvert);
+  Array<Array<int>> vertex_shared_edges(src_mesh.totvert);
+  Array<Array<int>> vertex_corners(src_mesh.totvert);
   threading::parallel_for(vert_to_poly_map.index_range(), 512, [&](IndexRange range) {
     for (const int i : range) {
       if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
@@ -675,8 +669,8 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
     }
   });
 
-  Vector<float3> vertex_positions(mesh_in.totpoly);
-  for (const int i : IndexRange(mesh_in.totpoly)) {
+  Vector<float3> vertex_positions(src_mesh.totpoly);
+  for (const int i : IndexRange(src_mesh.totpoly)) {
     const MPoly &poly = src_polys[i];
     BKE_mesh_calc_poly_center(
         &poly, &src_loops[poly.loopstart], src_verts.data(), vertex_positions[i]);
@@ -685,9 +679,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
   Array<int> boundary_edge_midpoint_index;
   if (keep_boundaries) {
     /* Only initialize when we actually need it. */
-    boundary_edge_midpoint_index.reinitialize(mesh_in.totedge);
+    boundary_edge_midpoint_index.reinitialize(src_mesh.totedge);
     /* We need to add vertices at the centers of boundary edges. */
-    for (const int i : IndexRange(mesh_in.totedge)) {
+    for (const int i : IndexRange(src_mesh.totedge)) {
       if (edge_types[i] == EdgeType::Boundary) {
         float3 mid;
         const MEdge &edge = src_edges[i];
@@ -712,7 +706,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
    * needs to be created or not. If it's not -1 it gives the index in `new_edges` of the dual
    * edge. The edges coming from preserving the boundaries only get added once anyway, so we
    * don't need a hash-map for that. */
-  Array<int> old_to_new_edges_map(mesh_in.totedge);
+  Array<int> old_to_new_edges_map(src_mesh.totedge);
   old_to_new_edges_map.fill(-1);
 
   /* This is necessary to prevent duplicate edges from being created, but will likely not do
@@ -726,7 +720,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
                            new_edges,
                            new_to_old_edges_map);
 
-  for (const int i : IndexRange(mesh_in.totvert)) {
+  for (const int i : IndexRange(src_mesh.totvert)) {
     if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
         (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
       /* Bad vertex that we can't work with. */
@@ -887,13 +881,13 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
   }
   Mesh *mesh_out = BKE_mesh_new_nomain(
       vertex_positions.size(), new_edges.size(), 0, loops.size(), loop_lengths.size());
-  transfer_attributes(attributes,
-                      vertex_types,
+
+  transfer_attributes(vertex_types,
                       keep_boundaries,
                       new_to_old_edges_map,
                       new_to_old_face_corners_map,
                       boundary_vertex_to_relevant_face_map,
-                      mesh_in.attributes(),
+                      src_mesh.attributes(),
                       mesh_out->attributes_for_write());
 
   MutableSpan<MVert> dst_verts = mesh_out->verts_for_write();
@@ -915,7 +909,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
     copy_v3_v3(dst_verts[i].co, vertex_positions[i]);
   }
   dst_edges.copy_from(new_edges);
-  geometry_set.replace_mesh(mesh_out);
+  return mesh_out;
 }
 
 static void node_geo_exec(GeoNodeExecParams params)
@@ -923,9 +917,9 @@ static void node_geo_exec(GeoNodeExecParams params)
   GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
   const bool keep_boundaries = params.extract_input<bool>("Keep Boundaries");
   geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
-    if (geometry_set.has_mesh()) {
-      const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
-      calc_dual_mesh(geometry_set, component, keep_boundaries);
+    if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
+      Mesh *new_mesh = calc_dual_mesh(*mesh, keep_boundaries);
+      geometry_set.replace_mesh(new_mesh);
     }
   });
   params.set_output("Dual Mesh", std::move(geometry_set));



More information about the Bf-blender-cvs mailing list