[Bf-blender-cvs] [84a4f2ae68d] master: Geometry Nodes: Improve performance of point distribute node

Hans Goudey noreply at git.blender.org
Mon Mar 8 18:45:13 CET 2021


Commit: 84a4f2ae68d40830111ae41b25d76b165e37d611
Author: Hans Goudey
Date:   Mon Mar 8 12:45:06 2021 -0500
Branches: master
https://developer.blender.org/rB84a4f2ae68d40830111ae41b25d76b165e37d611

Geometry Nodes: Improve performance of point distribute node

This commit refactors the point distribute node to skip realizing
the instances created by the point instance node or the collection
and object info nodes. Realizing instances is not necessary here
because it copies all the mesh data and and interpolates all
attributes from the instances when this operation does not
need to modify the input geometry at all.

In the tree leaves test file this patch improves the performance of
the node by about 14%. That's not very much, the gain is likely larger
for more complicated input instances with more attributes (especially
attributes on different domains, where interpolation would be necessary
to join all of the instances). Another possible performance improvement
would be to parallelize the code in this node where possible.

The point distribution code unfortunately gets quite a bit more
complicated because it has to handle the complexity of having many
inputs instead of just one.

Note that this commit changes the randomness of the distribution
in some cases, as if the seed input had changed.

Differential Revision: https://developer.blender.org/D10596

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

M	source/blender/blenlib/BLI_math_matrix.h
M	source/blender/blenlib/intern/math_matrix.c
M	source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc

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

diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index eac7f25f11a..6324963f06a 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -331,6 +331,7 @@ void rescale_m4(float mat[4][4], const float scale[3]);
 void transform_pivot_set_m3(float mat[3][3], const float pivot[2]);
 void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
 
+void mat4_to_rot(float rot[3][3], const float wmat[4][4]);
 void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);
 void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]);
 void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]);
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index b460d75d77f..2ada05d2965 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -2140,6 +2140,16 @@ void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3])
   }
 }
 
+void mat4_to_rot(float rot[3][3], const float wmat[4][4])
+{
+  normalize_v3_v3(rot[0], wmat[0]);
+  normalize_v3_v3(rot[1], wmat[1]);
+  normalize_v3_v3(rot[2], wmat[2]);
+  if (UNLIKELY(is_negative_m3(rot))) {
+    negate_m3(rot);
+  }
+}
+
 void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
 {
   float mat3[3][3]; /* wmat -> 3x3 */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
index c40cb2bb0ae..96409837491 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -29,6 +29,7 @@
 #include "BKE_attribute_math.hh"
 #include "BKE_bvhutils.h"
 #include "BKE_deform.h"
+#include "BKE_geometry_set_instances.hh"
 #include "BKE_mesh.h"
 #include "BKE_mesh_runtime.h"
 #include "BKE_pointcloud.h"
@@ -38,6 +39,9 @@
 
 #include "node_geometry_util.hh"
 
+using blender::bke::AttributeKind;
+using blender::bke::GeometryInstanceGroup;
+
 static bNodeSocketTemplate geo_node_point_distribute_in[] = {
     {SOCK_GEOMETRY, N_("Geometry")},
     {SOCK_FLOAT, N_("Distance Min"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
@@ -89,6 +93,7 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
 }
 
 static void sample_mesh_surface(const Mesh &mesh,
+                                const float4x4 &transform,
                                 const float base_density,
                                 const FloatReadAttribute *density_factors,
                                 const int seed,
@@ -106,9 +111,9 @@ static void sample_mesh_surface(const Mesh &mesh,
     const int v0_index = mesh.mloop[v0_loop].v;
     const int v1_index = mesh.mloop[v1_loop].v;
     const int v2_index = mesh.mloop[v2_loop].v;
-    const float3 v0_pos = mesh.mvert[v0_index].co;
-    const float3 v1_pos = mesh.mvert[v1_index].co;
-    const float3 v2_pos = mesh.mvert[v2_index].co;
+    const float3 v0_pos = transform * float3(mesh.mvert[v0_index].co);
+    const float3 v1_pos = transform * float3(mesh.mvert[v1_index].co);
+    const float3 v2_pos = transform * float3(mesh.mvert[v2_index].co);
 
     float looptri_density_factor = 1.0f;
     if (density_factors != nullptr) {
@@ -138,47 +143,64 @@ static void sample_mesh_surface(const Mesh &mesh,
   }
 }
 
-BLI_NOINLINE static KDTree_3d *build_kdtree(Span<float3> positions)
+BLI_NOINLINE static KDTree_3d *build_kdtree(Span<Vector<float3>> positions_all,
+                                            const int initial_points_len)
 {
-  KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size());
-  for (const int i : positions.index_range()) {
-    BLI_kdtree_3d_insert(kdtree, i, positions[i]);
+  KDTree_3d *kdtree = BLI_kdtree_3d_new(initial_points_len);
+
+  int i_point = 0;
+  for (const Vector<float3> positions : positions_all) {
+    for (const float3 position : positions) {
+      BLI_kdtree_3d_insert(kdtree, i_point, position);
+      i_point++;
+    }
   }
   BLI_kdtree_3d_balance(kdtree);
   return kdtree;
 }
 
 BLI_NOINLINE static void update_elimination_mask_for_close_points(
-    Span<float3> positions, const float minimum_distance, MutableSpan<bool> elimination_mask)
+    Span<Vector<float3>> positions_all,
+    Span<int> instance_start_offsets,
+    const float minimum_distance,
+    MutableSpan<bool> elimination_mask,
+    const int initial_points_len)
 {
   if (minimum_distance <= 0.0f) {
     return;
   }
 
-  KDTree_3d *kdtree = build_kdtree(positions);
+  KDTree_3d *kdtree = build_kdtree(positions_all, initial_points_len);
 
-  for (const int i : positions.index_range()) {
-    if (elimination_mask[i]) {
-      continue;
-    }
+  /* The elimination mask is a flattened array for every point,
+   * so keep track of the index to it separately. */
+  for (const int i_instance : positions_all.index_range()) {
+    Span<float3> positions = positions_all[i_instance];
+    const int offset = instance_start_offsets[i_instance];
+
+    for (const int i : positions.index_range()) {
+      if (elimination_mask[offset + i]) {
+        continue;
+      }
 
-    struct CallbackData {
-      int index;
-      MutableSpan<bool> elimination_mask;
-    } callback_data = {i, elimination_mask};
-
-    BLI_kdtree_3d_range_search_cb(
-        kdtree,
-        positions[i],
-        minimum_distance,
-        [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
-          CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
-          if (index != callback_data.index) {
-            callback_data.elimination_mask[index] = true;
-          }
-          return true;
-        },
-        &callback_data);
+      struct CallbackData {
+        int index;
+        MutableSpan<bool> elimination_mask;
+      } callback_data = {offset + i, elimination_mask};
+
+      BLI_kdtree_3d_range_search_cb(
+          kdtree,
+          positions[i],
+          minimum_distance,
+          [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
+            CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
+            if (index != callback_data.index) {
+              callback_data.elimination_mask[index] = true;
+            }
+            return true;
+          },
+          &callback_data);
+    }
   }
   BLI_kdtree_3d_free(kdtree);
 }
@@ -287,73 +309,106 @@ BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh,
   }
 }
 
+template<typename T>
 BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
                                                Span<float3> bary_coords,
                                                Span<int> looptri_indices,
-                                               const StringRef attribute_name,
-                                               const ReadAttribute &attribute_in,
-                                               GeometryComponent &component)
+                                               const AttributeDomain source_domain,
+                                               Span<T> source_span,
+                                               MutableSpan<T> output_span)
 {
-  const CustomDataType data_type = attribute_in.custom_data_type();
-  const AttributeDomain domain = attribute_in.domain();
-  if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
-    /* Not supported currently. */
-    return;
-  }
-
-  OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
-      attribute_name, ATTR_DOMAIN_POINT, data_type);
-  if (!attribute_out) {
-    return;
-  }
-
-  attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
-    using T = decltype(dummy);
-
-    Span data_in = attribute_in.get_span<T>();
-    MutableSpan data_out = attribute_out->get_span_for_write_only<T>();
-
-    switch (domain) {
-      case ATTR_DOMAIN_POINT: {
-        interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, data_in, data_out);
-        break;
-      }
-      case ATTR_DOMAIN_CORNER: {
-        interpolate_attribute_corner<T>(mesh, bary_coords, looptri_indices, data_in, data_out);
-        break;
-      }
-      default: {
-        BLI_assert(false);
-        break;
-      }
+  switch (source_domain) {
+    case ATTR_DOMAIN_POINT: {
+      interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, source_span, output_span);
+      break;
+    }
+    case ATTR_DOMAIN_CORNER: {
+      interpolate_attribute_corner<T>(
+          mesh, bary_coords, looptri_indices, source_span, output_span);
+      break;
     }
-  });
-  attribute_out.apply_span_and_save();
+    default: {
+      /* Not supported currently. */
+      return;
+    }
+  }
 }
 
-BLI_NOINLINE static void interpolate_existing_attributes(const MeshComponent &mesh_component,
-                                                         GeometryComponent &component,
-                                                         Span<float3> bary_coords,
-                                                         Span<int> looptri_indices)
+BLI_NOINLINE static void interpolate_existing_attributes(
+    Span<GeometryInstanceGroup> set_groups,
+    Span<int> instance_start_offsets,
+    const Map<std::string, AttributeKind> &attributes,
+    GeometryComponent &component,
+    Span<Vector<float3>> bary_coords_array,
+    Span<Vector<int>> looptri_indices_array)
 {
-  const Mesh &mesh = *mesh_component.get_for_read();
-
-  Set<std::string> attribute_names = mesh_component.attribute_names();
-  for (StringRefNull attribute_name : attribute_names) {
-    if (ELEM(attribute_name, "position", "normal", "id")) {
+  for (Map<std::string, AttributeKind>::Item entry : attributes.items()) {
+    StringRef attribute_name = entry.key;
+    const CustomDataType output_data_type = entry.value.data_type;
+    /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
+    OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
+        attribute_name, ATTR_DOMAI

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list