[Bf-blender-cvs] [8a6dc0fac71] master: Geometry Nodes: Control Point Neighbors Node

Johnny Matthews noreply at git.blender.org
Mon Sep 26 20:07:12 CEST 2022


Commit: 8a6dc0fac71cc5eb6fc945295b9c1f51f72cc407
Author: Johnny Matthews
Date:   Mon Sep 26 13:03:28 2022 -0500
Branches: master
https://developer.blender.org/rB8a6dc0fac71cc5eb6fc945295b9c1f51f72cc407

Geometry Nodes: Control Point Neighbors Node

This node allows access to the indices of neighboring control points
within a curve via an offset. This includes taking into consideration
curves that are cyclic.

Differential Revision: D13373

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

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

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

diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 95bb9fd7e40..38629c18ca0 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -82,6 +82,7 @@ def curve_node_items(context):
     yield NodeItem("GeometryNodeSubdivideCurve")
     yield NodeItem("GeometryNodeTrimCurve")
     yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+    yield NodeItem("GeometryNodeInputControlPointNeighbors")
     yield NodeItem("GeometryNodeInputCurveHandlePositions")
     yield NodeItem("GeometryNodeInputTangent")
     yield NodeItem("GeometryNodeInputCurveTilt")
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 14cf8164b79..625c4d87bcd 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1531,6 +1531,7 @@ struct TexResult;
 #define GEO_NODE_SAMPLE_INDEX 1174
 #define GEO_NODE_SAMPLE_NEAREST 1175
 #define GEO_NODE_SAMPLE_NEAREST_SURFACE 1176
+#define GEO_NODE_INPUT_CONTROL_POINT_NEIGHBORS 1177
 
 /** \} */
 
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 4ed0bf12cb6..0dcb2aa3139 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4743,6 +4743,7 @@ static void registerGeometryNodes()
   register_node_type_geo_flip_faces();
   register_node_type_geo_geometry_to_instance();
   register_node_type_geo_image_texture();
+  register_node_type_geo_input_control_point_neighbors();
   register_node_type_geo_input_curve_handles();
   register_node_type_geo_input_curve_tilt();
   register_node_type_geo_input_id();
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index d02bbeb67f7..4ead6326295 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -61,6 +61,7 @@ void register_node_type_geo_field_at_index(void);
 void register_node_type_geo_flip_faces(void);
 void register_node_type_geo_geometry_to_instance(void);
 void register_node_type_geo_image_texture(void);
+void register_node_type_geo_input_control_point_neighbors(void);
 void register_node_type_geo_input_curve_handles(void);
 void register_node_type_geo_input_curve_tilt(void);
 void register_node_type_geo_input_id(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 2db8be661c3..574a8dcab96 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -319,6 +319,7 @@ DefNode(GeometryNode, GEO_NODE_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Fac
 DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "Convert each input geometry into an instance, which can be much faster than the Join Geometry node when the inputs are large")
 DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "Sample values from an image texture")
 DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES",InputCurveHandlePositions,"Curve Handle Positions", "Retrieve the position of each Bézier control point's handles")
+DefNode(GeometryNode, GEO_NODE_INPUT_CONTROL_POINT_NEIGHBORS, 0, "INPUT_CONTROL_POINT_NEIGHBORS", InputControlPointNeighbors, "Control Point Neighbors", "Offset a control point index within its curve")
 DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "Retrieve the angle at each control point used to twist the curve's normal around its tangent")
 DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "Retrieve a stable random identifier value from the \"id\" attribute on the point domain, or the index if the attribute does not exist")
 DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "Retrieve an integer value indicating the position of each element in the list, starting at zero")
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 19a325eca89..b80e87e80ac 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -71,6 +71,7 @@ set(SRC
   nodes/node_geo_flip_faces.cc
   nodes/node_geo_geometry_to_instance.cc
   nodes/node_geo_image_texture.cc
+  nodes/node_geo_input_control_point_neighbors.cc
   nodes/node_geo_input_curve_handles.cc
   nodes/node_geo_input_curve_tilt.cc
   nodes/node_geo_input_id.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc
new file mode 100644
index 00000000000..33b15e0056e
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+#include "BKE_curves.hh"
+
+namespace blender::nodes::node_geo_input_control_point_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+  b.add_input<decl::Int>(N_("Point Index"))
+      .implicit_field(implicit_field_inputs::index)
+      .hide_value()
+      .description(
+          N_("The index of the control point to evaluate. Defaults to the current index"));
+  b.add_input<decl::Int>(N_("Offset"))
+      .dependent_field()
+      .description(N_("The number of control points along the curve to traverse"));
+  b.add_output<decl::Bool>(N_("Is Valid Offset"))
+      .field_source()
+      .description(N_("Outputs true if the evaluated control point plus the offset "
+                      "is a valid index of the original curve"));
+  b.add_output<decl::Int>(N_("Point Index"))
+      .field_source()
+      .description(N_("The index of the control point plus the offset within the entire "
+                      "curves object"));
+}
+
+static int apply_offset_in_cyclic_range(const IndexRange range,
+                                        const int start_index,
+                                        const int offset)
+{
+  BLI_assert(range.contains(start_index));
+  const int start_in_range = start_index - range.first();
+  const int offset_in_range = start_in_range + offset;
+  const int mod_offset = offset_in_range % range.size();
+  if (mod_offset >= 0) {
+    return range[mod_offset];
+  }
+  return range.last(-(mod_offset + 1));
+}
+
+static Array<int> build_parent_curves(const bke::CurvesGeometry &curves)
+{
+  Array<int> parent_curves(curves.points_num());
+  for (const int i : curves.curves_range()) {
+    parent_curves.as_mutable_span().slice(curves.points_for_curve(i)).fill(i);
+  }
+  return parent_curves;
+}
+
+class ControlPointNeighborFieldInput final : public bke::CurvesFieldInput {
+ private:
+  Field<int> index_;
+  Field<int> offset_;
+
+ public:
+  ControlPointNeighborFieldInput(Field<int> index, Field<int> offset)
+      : CurvesFieldInput(CPPType::get<int>(), "Control Point Neighbors node"),
+        index_(index),
+        offset_(offset)
+  {
+    category_ = Category::Generated;
+  }
+
+  GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
+                                 const eAttrDomain domain,
+                                 IndexMask mask) const final
+  {
+    const VArray<bool> cyclic = curves.cyclic();
+    const Array<int> parent_curves = build_parent_curves(curves);
+    bke::CurvesFieldContext context{curves, domain};
+    fn::FieldEvaluator evaluator{context, &mask};
+    evaluator.add(index_);
+    evaluator.add(offset_);
+    evaluator.evaluate();
+    const VArray<int> indices = evaluator.get_evaluated<int>(0);
+    const VArray<int> offsets = evaluator.get_evaluated<int>(1);
+    Array<int> output(curves.points_num());
+
+    for (const int i_selection : mask) {
+      const int i_point = std::clamp(indices[i_selection], 0, curves.points_num() - 1);
+      const int i_curve = parent_curves[i_point];
+      const IndexRange curve_points = curves.points_for_curve(i_curve);
+      const int offset_point = i_point + offsets[i_point];
+
+      if (cyclic[i_curve]) {
+        output[i_selection] = apply_offset_in_cyclic_range(
+            curve_points, i_point, offsets[i_selection]);
+        continue;
+      }
+      output[i_selection] = std::clamp(offset_point, 0, int(curves.points_num() - 1));
+    }
+
+    return VArray<int>::ForContainer(std::move(output));
+  }
+};
+
+class OffsetValidFieldInput final : public bke::CurvesFieldInput {
+ private:
+  Field<int> index_;
+  Field<int> offset_;
+
+ public:
+  OffsetValidFieldInput(Field<int> index, Field<int> offset)
+      : CurvesFieldInput(CPPType::get<bool>(), "Offset Valid"), index_(index), offset_(offset)
+  {
+    category_ = Category::Generated;
+  }
+
+  GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
+                                 const eAttrDomain domain,
+                                 const IndexMask mask) const final
+  {
+    bke::CurvesFieldContext context{curves, ATTR_DOMAIN_POINT};
+    fn::FieldEvaluator evaluator{context, &mask};
+    evaluator.add(index_);
+    evaluator.add(offset_);
+    evaluator.evaluate();
+    const VArray<int> indices = evaluator.get_evaluated<int>(0);
+    const VArray<int> offsets = evaluator.get_evaluated<int>(1);
+    Array<int> parent_curves = build_parent_curves(curves);
+    VArray<bool> cyclic = curves.cyclic();
+    Array<bool> output(curves.points_num());
+
+    for (const int i_selection : mask) {
+      const int i_point = indices[i_selection];
+
+      if (!curves.points_range().contains(i_point)) {
+        output[i_selection] = false;
+        continue;
+      }
+      const int i_curve = parent_curves[i_point];
+      const IndexRange curve_points = curves.points_for_curve(i_curve);
+      if (cyclic[i_curve]) {
+        output[i_selection] = true;
+        continue;
+      }
+      output[i_selection] = curve_points.contains(i_point + offsets[i_selection]);
+    };
+    return VArray<bool>::ForContainer(std::move(output))

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list