[Bf-blender-cvs] [4eef1d2edc1] geometry-nodes-point-separate-node: Geometry Nodes: Point separate node

Hans Goudey noreply at git.blender.org
Tue Dec 1 22:05:42 CET 2020


Commit: 4eef1d2edc16b113e2ef83e0279e555cbb2e0884
Author: Hans Goudey
Date:   Tue Dec 1 16:05:35 2020 -0500
Branches: geometry-nodes-point-separate-node
https://developer.blender.org/rB4eef1d2edc16b113e2ef83e0279e555cbb2e0884

Geometry Nodes: Point separate node

This node takes an input geometry and ouputs two geometries, moving
some points to the first and other points to the second depending on a
mask attribute input and a threshold.

The implementation tries to be "attribute component agnostic", meaning
it should be relatively easy to add "separate" functionality for more
component types in the future when they need to support it. (Then the
node could be renamed "Separate Geometry").

There is still an error carrying over the values for some attributes to
the output geometries.

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

M	release/scripts/startup/nodeitems_builtins.py
M	source/blender/blenkernel/BKE_node.h
M	source/blender/blenkernel/intern/node.c
M	source/blender/blenkernel/intern/pointcloud.cc
M	source/blender/nodes/CMakeLists.txt
M	source/blender/nodes/NOD_geometry.h
M	source/blender/nodes/NOD_static_types.h
A	source/blender/nodes/geometry/nodes/node_geo_point_separate.cc

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

diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index b1789776728..f955389d36b 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -512,6 +512,7 @@ geometry_node_categories = [
     GeometryNodeCategory("GEO_POINT", "Point", items=[
         NodeItem("GeometryNodePointDistribute"),
         NodeItem("GeometryNodePointInstance"),
+        NodeItem("GeometryNodePointSeparate"),
     ]),
     GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
         NodeItem("ShaderNodeMapRange"),
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index a8a94958772..68093affab8 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1350,6 +1350,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
 #define GEO_NODE_RANDOM_ATTRIBUTE 1008
 #define GEO_NODE_ATTRIBUTE_MATH 1009
 #define GEO_NODE_JOIN_GEOMETRY 1010
+#define GEO_NODE_POINT_SEPARATE 1011
 
 /** \} */
 
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index b564a4c468b..8edafce3518 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -4693,6 +4693,7 @@ static void registerGeometryNodes(void)
   register_node_type_geo_random_attribute();
   register_node_type_geo_attribute_math();
   register_node_type_geo_join_geometry();
+  register_node_type_geo_point_separate();
 }
 
 static void registerFunctionNodes(void)
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 5f6685817b9..1d38b69462a 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -243,13 +243,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
 
   pointcloud->totpoint = totpoint;
 
-  CustomData_add_layer_named(&pointcloud->pdata,
-                             CD_PROP_FLOAT,
-                             CD_CALLOC,
-                             nullptr,
-                             pointcloud->totpoint,
-                             POINTCLOUD_ATTR_RADIUS);
-
   pointcloud->totpoint = totpoint;
   CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
   BKE_pointcloud_update_customdata_pointers(pointcloud);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index a367f40dca7..3e1f287dd91 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -147,6 +147,7 @@ set(SRC
   geometry/nodes/node_geo_subdivision_surface.cc
   geometry/nodes/node_geo_point_distribute.cc
   geometry/nodes/node_geo_point_instance.cc
+  geometry/nodes/node_geo_point_separate.cc
   geometry/nodes/node_geo_random_attribute.cc
   geometry/nodes/node_geo_transform.cc
   geometry/nodes/node_geo_triangulate.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 0532547375f..2faa7f50f10 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -37,6 +37,7 @@ void register_node_type_geo_object_info(void);
 void register_node_type_geo_random_attribute(void);
 void register_node_type_geo_attribute_math(void);
 void register_node_type_geo_join_geometry(void);
+void register_node_type_geo_point_separate(void);
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 09e0908140c..9d06d49db46 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -277,6 +277,7 @@ DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Objec
 DefNode(GeometryNode, GEO_NODE_RANDOM_ATTRIBUTE, def_geo_random_attribute, "RANDOM_ATTRIBUTE", RandomAttribute, "Random Attribute", "")
 DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MATH, def_geo_attribute_math, "ATTRIBUTE_MATH", AttributeMath, "Attribute Math", "")
 DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
+DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "")
 
 /* undefine macros */
 #undef DefNode
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
new file mode 100644
index 00000000000..81a193723b2
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
@@ -0,0 +1,180 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_mesh.h"
+#include "BKE_persistent_data_handle.hh"
+#include "BKE_pointcloud.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_point_instance_in[] = {
+    {SOCK_GEOMETRY, N_("Geometry")},
+    {SOCK_STRING, N_("Mask")},
+    {SOCK_FLOAT, N_("Threshold"), 0.5f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
+    {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_point_instance_out[] = {
+    {SOCK_GEOMETRY, N_("Geometry A")},
+    {SOCK_GEOMETRY, N_("Geometry B")},
+    {-1, ""},
+};
+
+namespace blender::nodes {
+
+static void fill_attribute_from_input(ReadAttributePtr input_attribute,
+                                      WriteAttributePtr out_attribute_a,
+                                      WriteAttributePtr out_attribute_b,
+                                      Span<bool> a_or_b)
+{
+  fn::GSpan in_span = input_attribute->get_span();
+  int i_a = 0;
+  int i_b = 0;
+  for (int i_in : IndexRange(input_attribute->size())) {
+    if (a_or_b[i_in]) {
+      out_attribute_a->set(i_a, in_span[i_in]);
+      i_a++;
+    }
+    else {
+      out_attribute_b->set(i_b, in_span[i_in]);
+      i_b++;
+    }
+  }
+}
+
+static void separate_component_attributes(const PointCloudComponent &component,
+                                          GeometrySet *out_set_a,
+                                          GeometrySet *out_set_b,
+                                          const int a_total,
+                                          const int b_total,
+                                          Span<bool> a_or_b)
+{
+  /* Start fresh with new pointclouds. */
+  out_set_a->replace_pointcloud(BKE_pointcloud_new_nomain(a_total));
+  out_set_b->replace_pointcloud(BKE_pointcloud_new_nomain(b_total));
+  PointCloudComponent &out_component_a = out_set_a->get_component_for_write<PointCloudComponent>();
+  PointCloudComponent &out_component_b = out_set_b->get_component_for_write<PointCloudComponent>();
+
+  Set<std::string> attribute_names = component.attribute_names();
+  for (const std::string &name : attribute_names) {
+    ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
+    BLI_assert(attribute);
+
+    const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute->cpp_type());
+    const AttributeDomain domain = attribute->domain();
+    if (!component.attribute_is_builtin(name)) {
+      const bool create_success_a = out_component_a.attribute_try_create(name, domain, data_type);
+      const bool create_success_b = out_component_b.attribute_try_create(name, domain, data_type);
+      if (!(create_success_a && create_success_b)) {
+        /* Since the input attribute is from the same component type,
+         * it should always be possible to create the new attributes. */
+        BLI_assert(false);
+        continue;
+      }
+    }
+    WriteAttributePtr out_attribute_a = out_component_a.attribute_try_get_for_write(name);
+    WriteAttributePtr out_attribute_b = out_component_b.attribute_try_get_for_write(name);
+    if (!out_attribute_a || !out_attribute_b) {
+      BLI_assert(false);
+      continue;
+    }
+
+    fill_attribute_from_input(
+        std::move(attribute), std::move(out_attribute_a), std::move(out_attribute_b), a_or_b);
+  }
+}
+
+/**
+ * Find total in each new set and find which of the output sets each point will belong to.
+ */
+static Array<bool> calculate_split(const GeometryComponent &component,
+                                   const std::string mask_name,
+                                   const float threshold,
+                                   int *r_a_total,
+                                   int *r_b_total)
+{
+  /* For now this will always sample the attributes on the point level. */
+  const FloatReadAttribute mask_attribute = component.attribute_get_for_read<float>(
+      mask_name, ATTR_DOMAIN_POINT, 1.0f);
+  Span<float> masks = mask_attribute.get_span();
+  const int in_total = masks.size();
+
+  *r_a_total = 0;
+  Array<bool> a_or_b(in_total);
+  for (int i : masks.index_range()) {
+    const bool in_a = masks[i] > threshold;
+    a_or_b[i] = in_a;
+    if (in_a) {
+      *r_a_total += 1;
+    }
+  }
+  *r_b_total = in_total - *r_a_total;
+
+  return a_or_b;
+}
+
+/* Much of the attribute code can be handled generically for every geometry component type. */
+template<typename Component>
+static void separate_component_type(const Component &component,
+                                    GeometrySet *out_set_a,
+                                    GeometrySet *out_set_b,
+                                    const std::string mask_name,
+                                    const float threshold)
+{
+  int a_total;
+  int b_total;
+  Array<bool> a_or_b = calculate_split(component, mask_name, threshold, &a_total, &b_total);
+


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list