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. @@
_______________________________________________
Bf-blender-cvs mailing list
[email protected]
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs