[Bf-blender-cvs] [d985751324a] master: Geometry Nodes: improve Point Distribute node

Jacques Lucke noreply at git.blender.org
Wed Jan 13 12:44:49 CET 2021


Commit: d985751324a81d0227d163981cc561968a88ff68
Author: Jacques Lucke
Date:   Wed Jan 13 12:34:48 2021 +0100
Branches: master
https://developer.blender.org/rBd985751324a81d0227d163981cc561968a88ff68

Geometry Nodes: improve Point Distribute node

This greatly simplifies the Point Distribute node. For a poisson disk
distribution, it now uses a simpler dart throwing variant. This results
in a slightly lower quality poisson disk distribution, but it still
fulfills our requirements: have a max density, minimum distance input
and stability while painting the density attribute.

This new implementation has a number of benefits over the old one:
* Much less and more readable code.
* Easier to extend with other distribution algorithms.
* Easier to transfer more attributes to the generated points later on.
* More predictable output when changing the max density and min distance.
* Works in 3d, so no projection on the xy plane is necessary.

This is related to T84640.

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

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

M	source/blender/makesrna/intern/rna_nodetree.c
M	source/blender/nodes/CMakeLists.txt
M	source/blender/nodes/geometry/node_geometry_util.hh
M	source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
D	source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc

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

diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index cf44d8a84be..1f6359c2ed4 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -436,7 +436,8 @@ static const EnumPropertyItem rna_node_geometry_point_distribute_method_items[]
      "POISSON",
      0,
      "Poisson Disk",
-     "Project points on the surface evenly with a Poisson disk distribution"},
+     "Distribute the points randomly on the surface while taking a minimum distance between "
+     "points into account"},
     {0, NULL, 0, NULL, NULL},
 };
 
@@ -6291,7 +6292,8 @@ static void rna_def_cmp_output_file_slot_file(BlenderRNA *brna)
 
   prop = RNA_def_property(srna, "save_as_render", PROP_BOOLEAN, PROP_NONE);
   RNA_def_property_boolean_sdna(prop, NULL, "save_as_render", 1);
-  RNA_def_property_ui_text(prop, "Save as Render", "Apply render part of display transform when saving byte image");
+  RNA_def_property_ui_text(
+      prop, "Save as Render", "Apply render part of display transform when saving byte image");
   RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL);
 
   prop = RNA_def_property(srna, "format", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 64667faa735..d72189636e4 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -154,7 +154,6 @@ set(SRC
   geometry/nodes/node_geo_join_geometry.cc
   geometry/nodes/node_geo_object_info.cc
   geometry/nodes/node_geo_point_distribute.cc
-  geometry/nodes/node_geo_point_distribute_poisson_disk.cc
   geometry/nodes/node_geo_point_instance.cc
   geometry/nodes/node_geo_point_separate.cc
   geometry/nodes/node_geo_rotate_points.cc
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 0cabe5e1155..b7b2afeefcb 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -46,11 +46,6 @@ void update_attribute_input_socket_availabilities(bNode &node,
 
 CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType>);
 
-void poisson_disk_point_elimination(Vector<float3> const *input_points,
-                                    Vector<float3> *output_points,
-                                    float maximum_distance,
-                                    float3 boundbox);
-
 Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
                                                   const AttributeDomain domain);
 
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 f5f9c9f8830..1370f45877d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -16,9 +16,11 @@
 
 #include "BLI_float3.hh"
 #include "BLI_hash.h"
+#include "BLI_kdtree.h"
 #include "BLI_math_vector.h"
 #include "BLI_rand.hh"
 #include "BLI_span.hh"
+#include "BLI_timeit.hh"
 
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
@@ -34,7 +36,7 @@
 
 static bNodeSocketTemplate geo_node_point_distribute_in[] = {
     {SOCK_GEOMETRY, N_("Geometry")},
-    {SOCK_FLOAT, N_("Distance Min"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
+    {SOCK_FLOAT, N_("Distance Min"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
     {SOCK_FLOAT, N_("Density Max"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
     {SOCK_STRING, N_("Density Attribute")},
     {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000},
@@ -67,213 +69,196 @@ static float3 normal_to_euler_rotation(const float3 normal)
   return rotation;
 }
 
-static Vector<float3> random_scatter_points_from_mesh(const Mesh *mesh,
-                                                      const float density,
-                                                      const FloatReadAttribute &density_factors,
-                                                      Vector<float3> &r_normals,
-                                                      Vector<int> &r_ids,
-                                                      const int seed)
+static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
 {
   /* This only updates a cache and can be considered to be logically const. */
-  const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(mesh));
-  const int looptris_len = BKE_mesh_runtime_looptri_len(mesh);
+  const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh));
+  const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
+  return {looptris, looptris_len};
+}
 
-  Vector<float3> points;
+static void sample_mesh_surface(const Mesh &mesh,
+                                const float base_density,
+                                const FloatReadAttribute *density_factors,
+                                const int seed,
+                                Vector<float3> &r_positions,
+                                Vector<float3> &r_bary_coords,
+                                Vector<int> &r_looptri_indices)
+{
+  Span<MLoopTri> looptris = get_mesh_looptris(mesh);
 
-  for (const int looptri_index : IndexRange(looptris_len)) {
+  for (const int looptri_index : looptris.index_range()) {
     const MLoopTri &looptri = looptris[looptri_index];
-    const int v0_index = mesh->mloop[looptri.tri[0]].v;
-    const int v1_index = mesh->mloop[looptri.tri[1]].v;
-    const int v2_index = mesh->mloop[looptri.tri[2]].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 float v0_density_factor = std::max(0.0f, density_factors[v0_index]);
-    const float v1_density_factor = std::max(0.0f, density_factors[v1_index]);
-    const float v2_density_factor = std::max(0.0f, density_factors[v2_index]);
-    const float looptri_density_factor = (v0_density_factor + v1_density_factor +
-                                          v2_density_factor) /
-                                         3.0f;
+    const int v0_index = mesh.mloop[looptri.tri[0]].v;
+    const int v1_index = mesh.mloop[looptri.tri[1]].v;
+    const int v2_index = mesh.mloop[looptri.tri[2]].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;
+
+    float looptri_density_factor = 1.0f;
+    if (density_factors != nullptr) {
+      const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_index]);
+      const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_index]);
+      const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_index]);
+      looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
+    }
     const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
 
     const int looptri_seed = BLI_hash_int(looptri_index + seed);
     RandomNumberGenerator looptri_rng(looptri_seed);
 
-    const float points_amount_fl = area * density * looptri_density_factor;
+    const float points_amount_fl = area * base_density * looptri_density_factor;
     const float add_point_probability = fractf(points_amount_fl);
     const bool add_point = add_point_probability > looptri_rng.get_float();
     const int point_amount = (int)points_amount_fl + (int)add_point;
 
     for (int i = 0; i < point_amount; i++) {
-      const float3 bary_coords = looptri_rng.get_barycentric_coordinates();
+      const float3 bary_coord = looptri_rng.get_barycentric_coordinates();
       float3 point_pos;
-      interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coords);
-      points.append(point_pos);
-
-      /* Build a hash stable even when the mesh is deformed. */
-      r_ids.append(((int)(bary_coords.hash()) + looptri_index));
-
-      float3 tri_normal;
-      normal_tri_v3(tri_normal, v0_pos, v1_pos, v2_pos);
-      r_normals.append(tri_normal);
+      interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coord);
+      r_positions.append(point_pos);
+      r_bary_coords.append(bary_coord);
+      r_looptri_indices.append(looptri_index);
     }
   }
+}
 
-  return points;
+BLI_NOINLINE static KDTree_3d *build_kdtree(Span<float3> positions)
+{
+  KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size());
+  for (const int i : positions.index_range()) {
+    BLI_kdtree_3d_insert(kdtree, i, positions[i]);
+  }
+  BLI_kdtree_3d_balance(kdtree);
+  return kdtree;
 }
 
-struct RayCastAll_Data {
-  void *bvhdata;
+BLI_NOINLINE static void update_elimination_mask_for_close_points(
+    Span<float3> positions, const float minimum_distance, MutableSpan<bool> elimination_mask)
+{
+  if (minimum_distance <= 0.0f) {
+    return;
+  }
 
-  BVHTree_RayCastCallback raycast_callback;
+  KDTree_3d *kdtree = build_kdtree(positions);
 
-  /** The original coordinate the result point was projected from. */
-  float2 raystart;
+  for (const int i : positions.index_range()) {
+    if (elimination_mask[i]) {
+      continue;
+    }
 
-  const Mesh *mesh;
-  float base_weight;
-  FloatReadAttribute *density_factors;
-  Vector<float3> *projected_points;
-  Vector<float3> *normals;
-  Vector<int> *stable_ids;
-  float cur_point_weight;
-};
+    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);
+  }
+  BLI_kdtree_3d_free(kdtree);
+}
 
-static void project_2d_bvh_callback(void *userdata,
-                                    int index,
-         

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list